Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(58)

Side by Side Diff: ipc/attachment_broker_mac_unittest.cc

Issue 2473993003: Delete IPC::ChannelPosix, IPC::ChannelWin and IPC::AttachmentBroker. (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ipc/attachment_broker.cc ('k') | ipc/attachment_broker_messages.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 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 "build/build_config.h"
6
7 #include <fcntl.h>
8 #include <mach/mach_vm.h>
9 #include <stddef.h>
10 #include <sys/mman.h>
11
12 #include <memory>
13 #include <tuple>
14
15 #include "base/command_line.h"
16 #include "base/files/file_util.h"
17 #include "base/files/scoped_file.h"
18 #include "base/files/scoped_temp_dir.h"
19 #include "base/mac/mac_util.h"
20 #include "base/mac/mach_logging.h"
21 #include "base/memory/free_deleter.h"
22 #include "base/memory/shared_memory.h"
23 #include "base/run_loop.h"
24 #include "base/strings/string_number_conversions.h"
25 #include "base/synchronization/spin_wait.h"
26 #include "base/threading/thread.h"
27 #include "base/time/time.h"
28 #include "ipc/attachment_broker_messages.h"
29 #include "ipc/attachment_broker_privileged_mac.h"
30 #include "ipc/attachment_broker_unprivileged_mac.h"
31 #include "ipc/ipc_listener.h"
32 #include "ipc/ipc_message.h"
33 #include "ipc/ipc_test_base.h"
34 #include "ipc/ipc_test_messages.h"
35 #include "ipc/test_util_mac.h"
36
37 namespace {
38
39 const char kDataBuffer1[] = "This is some test data to write to the file.";
40 const char kDataBuffer2[] = "The lazy dog and a fox.";
41 const char kDataBuffer3[] = "Two green bears but not a potato.";
42 const char kDataBuffer4[] = "Red potato is best potato.";
43 const std::string g_service_switch_name = "service_name";
44 const size_t g_large_message_size = 8 * 1024 * 1024;
45 const int g_large_message_count = 1000;
46 const size_t g_medium_message_size = 512 * 1024;
47
48 // Running the message loop is expected to increase the number of resident
49 // pages. The exact amount is non-deterministic, but for a simple test suite
50 // like this one, the increase is expected to be less than 1 MB.
51 const size_t g_expected_memory_increase = 1024 * 1024;
52
53 enum TestResult {
54 RESULT_UNKNOWN,
55 RESULT_SUCCESS,
56 RESULT_FAILURE,
57 };
58
59 mach_vm_size_t GetResidentSize() {
60 task_basic_info_64 info;
61 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
62 kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64,
63 reinterpret_cast<task_info_t>(&info), &count);
64 MACH_CHECK(kr == KERN_SUCCESS, kr) << "Couldn't get resident size.";
65
66 return info.resident_size;
67 }
68
69 base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment(
70 const scoped_refptr<IPC::BrokerableAttachment>& attachment) {
71 if (attachment->GetType() !=
72 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) {
73 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT.";
74 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
75 }
76
77 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) {
78 LOG(INFO) << "Brokerable type not MACH_PORT.";
79 return base::mac::ScopedMachSendRight(MACH_PORT_NULL);
80 }
81
82 IPC::internal::MachPortAttachmentMac* received_mach_port_attachment =
83 static_cast<IPC::internal::MachPortAttachmentMac*>(attachment.get());
84 base::mac::ScopedMachSendRight send_right(
85 received_mach_port_attachment->get_mach_port());
86 received_mach_port_attachment->reset_mach_port_ownership();
87 return send_right;
88 }
89
90 // Makes a Mach port backed SharedMemory region and fills it with |contents|.
91 std::unique_ptr<base::SharedMemory> MakeSharedMemory(
92 const std::string& contents) {
93 base::SharedMemoryHandle shm(contents.size());
94 if (!shm.IsValid()) {
95 LOG(ERROR) << "Failed to make SharedMemoryHandle.";
96 return nullptr;
97 }
98 std::unique_ptr<base::SharedMemory> shared_memory(
99 new base::SharedMemory(shm, false));
100 shared_memory->Map(contents.size());
101 memcpy(shared_memory->memory(), contents.c_str(), contents.size());
102 return shared_memory;
103 }
104
105 // |message| must be deserializable as a TestSharedMemoryHandleMsg1.
106 base::SharedMemoryHandle GetSharedMemoryHandleFromMsg1(
107 const IPC::Message& message) {
108 // Expect a message with a brokered attachment.
109 if (!message.HasBrokerableAttachments()) {
110 LOG(ERROR) << "Message missing brokerable attachment.";
111 return base::SharedMemoryHandle();
112 }
113
114 TestSharedMemoryHandleMsg1::Schema::Param p;
115 if (!TestSharedMemoryHandleMsg1::Read(&message, &p)) {
116 LOG(ERROR) << "Failed to deserialize message.";
117 return base::SharedMemoryHandle();
118 }
119
120 return std::get<1>(p);
121 }
122
123 // |message| must be deserializable as a TestSharedMemoryHandleMsg2. Returns
124 // whether deserialization was successful. |handle1| and |handle2| are output
125 // variables populated on success.
126 bool GetSharedMemoryHandlesFromMsg2(const IPC::Message& message,
127 base::SharedMemoryHandle* handle1,
128 base::SharedMemoryHandle* handle2) {
129 // Expect a message with a brokered attachment.
130 if (!message.HasBrokerableAttachments()) {
131 LOG(ERROR) << "Message missing brokerable attachment.";
132 return false;
133 }
134
135 TestSharedMemoryHandleMsg2::Schema::Param p;
136 if (!TestSharedMemoryHandleMsg2::Read(&message, &p)) {
137 LOG(ERROR) << "Failed to deserialize message.";
138 return false;
139 }
140
141 *handle1 = std::get<0>(p);
142 *handle2 = std::get<1>(p);
143 return true;
144 }
145
146 // Returns |nullptr| on error.
147 std::unique_ptr<base::SharedMemory> MapSharedMemoryHandle(
148 const base::SharedMemoryHandle& shm,
149 bool read_only) {
150 if (!shm.IsValid()) {
151 LOG(ERROR) << "Invalid SharedMemoryHandle";
152 return nullptr;
153 }
154
155 size_t size;
156 if (!shm.GetSize(&size)) {
157 LOG(ERROR) << "Couldn't get size of SharedMemoryHandle";
158 return nullptr;
159 }
160
161 std::unique_ptr<base::SharedMemory> shared_memory(
162 new base::SharedMemory(shm, read_only));
163 shared_memory->Map(size);
164 return shared_memory;
165 }
166
167 // This method maps the SharedMemoryHandle, checks the contents, and then
168 // consumes a reference to the underlying Mach port.
169 bool CheckContentsOfSharedMemoryHandle(const base::SharedMemoryHandle& shm,
170 const std::string& contents) {
171 std::unique_ptr<base::SharedMemory> shared_memory(
172 MapSharedMemoryHandle(shm, false));
173
174 if (memcmp(shared_memory->memory(), contents.c_str(), contents.size()) != 0) {
175 LOG(ERROR) << "Shared Memory contents not equivalent";
176 return false;
177 }
178 return true;
179 }
180
181 // This method mmaps the FileDescriptor, checks the contents, and then munmaps
182 // the FileDescriptor and closes the underlying fd.
183 bool CheckContentsOfFileDescriptor(const base::FileDescriptor& file_descriptor,
184 const std::string& contents) {
185 base::ScopedFD fd_closer(file_descriptor.fd);
186 lseek(file_descriptor.fd, 0, SEEK_SET);
187 std::unique_ptr<char, base::FreeDeleter> buffer(
188 static_cast<char*>(malloc(contents.size())));
189 if (!base::ReadFromFD(file_descriptor.fd, buffer.get(), contents.size()))
190 return false;
191
192 int result = memcmp(buffer.get(), contents.c_str(), contents.size());
193 return result == 0;
194 }
195
196 // Open |fp| and populate it with |contents|.
197 base::FileDescriptor MakeFileDescriptor(const base::FilePath& fp,
198 const std::string& contents) {
199 int fd = open(fp.value().c_str(), O_RDWR, S_IWUSR | S_IRUSR);
200 base::ScopedFD fd_closer(fd);
201 if (fd <= 0) {
202 LOG(ERROR) << "Error opening file at: " << fp.value();
203 return base::FileDescriptor();
204 }
205
206 if (lseek(fd, 0, SEEK_SET) != 0) {
207 LOG(ERROR) << "Error changing offset";
208 return base::FileDescriptor();
209 }
210
211 if (write(fd, contents.c_str(), contents.size()) !=
212 static_cast<ssize_t>(contents.size())) {
213 LOG(ERROR) << "Error writing to file";
214 return base::FileDescriptor();
215 }
216
217 return base::FileDescriptor(fd_closer.release(), true);
218 }
219
220 // Maps both handles, then checks that their contents matches |contents|. Then
221 // checks that changes to one are reflected in the other. Then consumes
222 // references to both underlying Mach ports.
223 bool CheckContentsOfTwoEquivalentSharedMemoryHandles(
224 const base::SharedMemoryHandle& handle1,
225 const base::SharedMemoryHandle& handle2,
226 const std::string& contents) {
227 std::unique_ptr<base::SharedMemory> shared_memory1(
228 MapSharedMemoryHandle(handle1, false));
229 std::unique_ptr<base::SharedMemory> shared_memory2(
230 MapSharedMemoryHandle(handle2, false));
231
232 if (memcmp(shared_memory1->memory(), contents.c_str(), contents.size()) !=
233 0) {
234 LOG(ERROR) << "Incorrect contents in shared_memory1";
235 return false;
236 }
237
238 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
239 contents.size()) != 0) {
240 LOG(ERROR) << "Incorrect contents in shared_memory2";
241 return false;
242 }
243
244 // Updating shared_memory1 should update shared_memory2.
245 const char known_string[] = "string bean";
246 if (shared_memory1->mapped_size() < strlen(known_string) ||
247 shared_memory2->mapped_size() < strlen(known_string)) {
248 LOG(ERROR) << "Shared memory size is too small";
249 return false;
250 }
251 memcpy(shared_memory1->memory(), known_string, strlen(known_string));
252
253 if (memcmp(shared_memory1->memory(), shared_memory2->memory(),
254 strlen(known_string)) != 0) {
255 LOG(ERROR) << "Incorrect contents in shared_memory2";
256 return false;
257 }
258
259 return true;
260 }
261
262 // |message| must be deserializable as a TestSharedMemoryHandleMsg1. Returns
263 // whether the contents of the attached shared memory region matches |contents|.
264 // Consumes a reference to the underlying Mach port.
265 bool CheckContentsOfMessage1(const IPC::Message& message,
266 const std::string& contents) {
267 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
268 return CheckContentsOfSharedMemoryHandle(shm, contents);
269 }
270
271 // Once the test is finished, send a control message to the parent process with
272 // the result. The message may require the runloop to be run before its
273 // dispatched.
274 void SendControlMessage(IPC::Sender* sender, bool success) {
275 IPC::Message* message = new IPC::Message(0, 2, IPC::Message::PRIORITY_NORMAL);
276 TestResult result = success ? RESULT_SUCCESS : RESULT_FAILURE;
277 message->WriteInt(result);
278 sender->Send(message);
279 }
280
281 // Records the most recently received brokerable attachment's id.
282 class AttachmentBrokerObserver : public IPC::AttachmentBroker::Observer {
283 public:
284 void ReceivedBrokerableAttachmentWithId(
285 const IPC::BrokerableAttachment::AttachmentId& id) override {
286 id_ = id;
287 }
288 IPC::BrokerableAttachment::AttachmentId* get_id() { return &id_; }
289
290 private:
291 IPC::BrokerableAttachment::AttachmentId id_;
292 };
293
294 // A broker which always sets the current process as the destination process
295 // for attachments.
296 class MockBroker : public IPC::AttachmentBrokerUnprivilegedMac {
297 public:
298 MockBroker() {}
299 ~MockBroker() override {}
300 bool SendAttachmentToProcess(
301 const scoped_refptr<IPC::BrokerableAttachment>& attachment,
302 base::ProcessId destination_process) override {
303 return IPC::AttachmentBrokerUnprivilegedMac::SendAttachmentToProcess(
304 attachment, base::Process::Current().Pid());
305 }
306 };
307
308 // Forwards all messages to |listener_|. Quits the message loop after a
309 // message is received, or the channel has an error.
310 class ProxyListener : public IPC::Listener {
311 public:
312 ProxyListener() : listener_(nullptr), reason_(MESSAGE_RECEIVED) {}
313 ~ProxyListener() override {}
314
315 // The reason for exiting the message loop.
316 enum Reason { MESSAGE_RECEIVED, CHANNEL_ERROR };
317
318 bool OnMessageReceived(const IPC::Message& message) override {
319 bool result = false;
320 if (listener_)
321 result = listener_->OnMessageReceived(message);
322 reason_ = MESSAGE_RECEIVED;
323 messages_.push_back(message);
324 base::MessageLoop::current()->QuitNow();
325 return result;
326 }
327
328 void OnChannelError() override {
329 reason_ = CHANNEL_ERROR;
330 base::MessageLoop::current()->QuitNow();
331 }
332
333 void set_listener(IPC::Listener* listener) { listener_ = listener; }
334 Reason get_reason() { return reason_; }
335 IPC::Message get_first_message() {
336 DCHECK(!messages_.empty());
337 return messages_[0];
338 }
339 void pop_first_message() {
340 DCHECK(!messages_.empty());
341 messages_.erase(messages_.begin());
342 }
343 bool has_message() { return !messages_.empty(); }
344
345 private:
346 IPC::Listener* listener_;
347 Reason reason_;
348 std::vector<IPC::Message> messages_;
349 };
350
351 // Waits for a result to be sent over the channel. Quits the message loop
352 // after a message is received, or the channel has an error.
353 class ResultListener : public IPC::Listener {
354 public:
355 ResultListener() : result_(RESULT_UNKNOWN) {}
356 ~ResultListener() override {}
357
358 bool OnMessageReceived(const IPC::Message& message) override {
359 base::PickleIterator iter(message);
360
361 int result;
362 EXPECT_TRUE(iter.ReadInt(&result));
363 result_ = static_cast<TestResult>(result);
364 return true;
365 }
366
367 TestResult get_result() { return result_; }
368
369 private:
370 TestResult result_;
371 };
372
373 class MockPortProvider : public base::PortProvider {
374 public:
375 mach_port_t TaskForPid(base::ProcessHandle process) const override {
376 auto it = port_map_.find(process);
377 if (it != port_map_.end())
378 return it->second;
379 return MACH_PORT_NULL;
380 }
381
382 void InsertEntry(base::ProcessHandle process, mach_port_t task_port) {
383 port_map_[process] = task_port;
384 NotifyObservers(process);
385 }
386
387 void ClearPortMap() { port_map_.clear(); }
388
389 private:
390 std::map<base::ProcessHandle, mach_port_t> port_map_;
391 };
392
393 // End-to-end tests for the attachment brokering process on Mac.
394 // The parent process acts as an unprivileged process. The child process acts
395 // as the privileged process.
396 class IPCAttachmentBrokerMacTest : public IPCTestBase {
397 public:
398 IPCAttachmentBrokerMacTest() {}
399 ~IPCAttachmentBrokerMacTest() override {}
400
401 base::CommandLine MakeCmdLine(const std::string& procname) override {
402 base::CommandLine command_line = IPCTestBase::MakeCmdLine(procname);
403 // Pass the service name to the child process.
404 command_line.AppendSwitchASCII(g_service_switch_name, service_name_);
405 return command_line;
406 }
407
408 // Takes ownership of |broker|. Has no effect if called after CommonSetUp().
409 void SetBroker(IPC::AttachmentBrokerUnprivilegedMac* broker) {
410 broker_.reset(broker);
411 }
412
413 // Mach Setup that needs to occur before child processes are forked.
414 void MachPreForkSetUp() {
415 service_name_ = IPC::CreateRandomServiceName();
416 server_port_.reset(IPC::BecomeMachServer(service_name_.c_str()).release());
417 }
418
419 // Mach Setup that needs to occur after child processes are forked.
420 void MachPostForkSetUp() {
421 client_port_.reset(IPC::ReceiveMachPort(server_port_.get()).release());
422 IPC::SendMachPort(
423 client_port_.get(), mach_task_self(), MACH_MSG_TYPE_COPY_SEND);
424 }
425
426 // Setup shared between tests.
427 void CommonSetUp(const char* name) {
428 PreConnectSetUp(name);
429 PostConnectSetUp();
430 }
431
432 // All of setup before the channel is connected.
433 void PreConnectSetUp(const char* name) {
434 Init(name);
435 MachPreForkSetUp();
436
437 if (!broker_.get())
438 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
439
440 broker_->AddObserver(&observer_, task_runner());
441 CreateChannel(&proxy_listener_);
442 broker_->RegisterBrokerCommunicationChannel(channel());
443 }
444
445 // All of setup including the connection and everything after.
446 void PostConnectSetUp() {
447 ASSERT_TRUE(ConnectChannel());
448 ASSERT_TRUE(StartClient());
449
450 MachPostForkSetUp();
451 active_names_at_start_ = IPC::GetActiveNameCount();
452 get_proxy_listener()->set_listener(&result_listener_);
453 }
454
455 void CheckChildResult() {
456 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED,
457 get_proxy_listener()->get_reason());
458 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS);
459 }
460
461 void FinalCleanUp() {
462 // There should be no leaked names.
463 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE(
464 base::TimeDelta::FromSeconds(10),
465 active_names_at_start_ == IPC::GetActiveNameCount());
466 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
467
468 // Close the channel so the client's OnChannelError() gets fired.
469 channel()->Close();
470
471 EXPECT_TRUE(WaitForClientShutdown());
472 DestroyChannel();
473 broker_.reset();
474 }
475
476 // Teardown shared between most tests.
477 void CommonTearDown() {
478 CheckChildResult();
479 FinalCleanUp();
480 }
481
482 // Makes a SharedMemory region, fills it with |contents|, sends the handle
483 // over Chrome IPC, and unmaps the region.
484 void SendMessage1(const std::string& contents) {
485 std::unique_ptr<base::SharedMemory> shared_memory(
486 MakeSharedMemory(contents));
487 IPC::Message* message =
488 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
489 sender()->Send(message);
490 }
491
492 ProxyListener* get_proxy_listener() { return &proxy_listener_; }
493 IPC::AttachmentBrokerUnprivilegedMac* get_broker() { return broker_.get(); }
494 AttachmentBrokerObserver* get_observer() { return &observer_; }
495 ResultListener* get_result_listener() { return &result_listener_; }
496
497 protected:
498 // The number of active names immediately after set up.
499 mach_msg_type_number_t active_names_at_start_;
500
501 private:
502 ProxyListener proxy_listener_;
503 std::unique_ptr<IPC::AttachmentBrokerUnprivilegedMac> broker_;
504 AttachmentBrokerObserver observer_;
505
506 // A port on which the main process listens for mach messages from the child
507 // process.
508 base::mac::ScopedMachReceiveRight server_port_;
509
510 // A port on which the child process listens for mach messages from the main
511 // process.
512 base::mac::ScopedMachSendRight client_port_;
513
514 std::string service_name_;
515
516 ResultListener result_listener_;
517 };
518
519 // These objects are globally accessible, and are expected to outlive all IPC
520 // Channels.
521 struct ChildProcessGlobals {
522 MockPortProvider port_provider;
523
524 // The broker must be destroyed before the port_provider, so that the broker
525 // gets a chance to unregister itself as an observer. This doesn't matter
526 // outside of tests, since neither port_provider nor broker will ever be
527 // destroyed.
528 std::unique_ptr<IPC::AttachmentBrokerPrivilegedMac> broker;
529 base::mac::ScopedMachSendRight server_task_port;
530
531 // Total resident memory before running the message loop.
532 mach_vm_size_t initial_resident_size;
533
534 // Whether to emit log statements while processing messages.
535 bool message_logging;
536 };
537
538 using OnMessageReceivedCallback = void (*)(IPC::Sender* sender,
539 const IPC::Message& message,
540 ChildProcessGlobals* globals);
541
542 // Sets up the Mach communication ports with the server. Returns a set of
543 // globals that must live at least as long as the test.
544 std::unique_ptr<ChildProcessGlobals> CommonChildProcessSetUp() {
545 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess();
546 std::string service_name =
547 cmd_line.GetSwitchValueASCII(g_service_switch_name);
548 base::mac::ScopedMachSendRight server_port(
549 IPC::LookupServer(service_name.c_str()));
550 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort());
551
552 // Send the port that this process is listening on to the server.
553 IPC::SendMachPort(
554 server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND);
555
556 // Receive the task port of the server process.
557 base::mac::ScopedMachSendRight server_task_port(
558 IPC::ReceiveMachPort(client_port.get()));
559
560 std::unique_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals);
561 globals->broker.reset(
562 new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider));
563 globals->port_provider.InsertEntry(getppid(), server_task_port.get());
564 globals->server_task_port.reset(server_task_port.release());
565 globals->message_logging = true;
566 return globals;
567 }
568
569 int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback,
570 const char* channel_name) {
571 LOG(INFO) << "Privileged process start.";
572 std::unique_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp());
573
574 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount();
575
576 base::MessageLoopForIO main_message_loop;
577 ProxyListener listener;
578
579 std::unique_ptr<IPC::Channel> channel(IPC::Channel::CreateClient(
580 IPCTestBase::GetChannelName(channel_name), &listener));
581 globals->broker->RegisterCommunicationChannel(channel.get(), nullptr);
582 CHECK(channel->Connect());
583
584 globals->initial_resident_size = GetResidentSize();
585
586 while (true) {
587 if (globals->message_logging)
588 LOG(INFO) << "Privileged process spinning run loop.";
589 base::RunLoop().Run();
590 ProxyListener::Reason reason = listener.get_reason();
591 if (reason == ProxyListener::CHANNEL_ERROR)
592 break;
593
594 while (listener.has_message()) {
595 if (globals->message_logging)
596 LOG(INFO) << "Privileged process running callback.";
597 callback(channel.get(), listener.get_first_message(), globals.get());
598 if (globals->message_logging)
599 LOG(INFO) << "Privileged process finishing callback.";
600 listener.pop_first_message();
601 }
602 }
603
604 if (active_names_at_start != IPC::GetActiveNameCount()) {
605 LOG(INFO) << "Memory leak!.";
606 }
607 LOG(INFO) << "Privileged process end.";
608 return 0;
609 }
610
611 // An unprivileged process makes a shared memory region, and writes a string to
612 // it. The SharedMemoryHandle is sent to the privileged process using Chrome
613 // IPC. The privileged process checks that it received the same memory region.
614 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandle) {
615 CommonSetUp("SendSharedMemoryHandle");
616
617 SendMessage1(kDataBuffer1);
618 base::RunLoop().Run();
619 CommonTearDown();
620 }
621
622 void SendSharedMemoryHandleCallback(IPC::Sender* sender,
623 const IPC::Message& message,
624 ChildProcessGlobals* globals) {
625 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
626 SendControlMessage(sender, success);
627 }
628
629 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandle) {
630 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleCallback,
631 "SendSharedMemoryHandle");
632 }
633
634 // Similar to SendSharedMemoryHandle, but sends a very long shared memory
635 // region.
636 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleLong) {
637 CommonSetUp("SendSharedMemoryHandleLong");
638
639 std::string buffer(1 << 23, 'a');
640 SendMessage1(buffer);
641 base::RunLoop().Run();
642 CommonTearDown();
643 }
644
645 void SendSharedMemoryHandleLongCallback(IPC::Sender* sender,
646 const IPC::Message& message,
647 ChildProcessGlobals* globals) {
648 std::string buffer(1 << 23, 'a');
649 bool success = CheckContentsOfMessage1(message, buffer);
650 SendControlMessage(sender, success);
651 }
652
653 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleLong) {
654 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleLongCallback,
655 "SendSharedMemoryHandleLong");
656 }
657
658 // Similar to SendSharedMemoryHandle, but sends two different shared memory
659 // regions in two messages.
660 TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesDifferentSharedMemoryHandle) {
661 CommonSetUp("SendTwoMessagesDifferentSharedMemoryHandle");
662
663 SendMessage1(kDataBuffer1);
664 SendMessage1(kDataBuffer2);
665 base::RunLoop().Run();
666 CommonTearDown();
667 }
668
669 void SendTwoMessagesDifferentSharedMemoryHandleCallback(
670 IPC::Sender* sender,
671 const IPC::Message& message,
672 ChildProcessGlobals* globals) {
673 static int count = 0;
674 static bool success = true;
675 ++count;
676 if (count == 1) {
677 success &= CheckContentsOfMessage1(message, kDataBuffer1);
678 } else if (count == 2) {
679 success &= CheckContentsOfMessage1(message, kDataBuffer2);
680 SendControlMessage(sender, success);
681 }
682 }
683
684 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesDifferentSharedMemoryHandle) {
685 return CommonPrivilegedProcessMain(
686 &SendTwoMessagesDifferentSharedMemoryHandleCallback,
687 "SendTwoMessagesDifferentSharedMemoryHandle");
688 }
689
690 // Similar to SendSharedMemoryHandle, but sends the same shared memory region in
691 // two messages.
692 TEST_F(IPCAttachmentBrokerMacTest, SendTwoMessagesSameSharedMemoryHandle) {
693 CommonSetUp("SendTwoMessagesSameSharedMemoryHandle");
694
695 {
696 std::unique_ptr<base::SharedMemory> shared_memory(
697 MakeSharedMemory(kDataBuffer1));
698
699 for (int i = 0; i < 2; ++i) {
700 IPC::Message* message =
701 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
702 sender()->Send(message);
703 }
704 }
705
706 base::RunLoop().Run();
707 CommonTearDown();
708 }
709
710 void SendTwoMessagesSameSharedMemoryHandleCallback(
711 IPC::Sender* sender,
712 const IPC::Message& message,
713 ChildProcessGlobals* globals) {
714 static int count = 0;
715 static base::SharedMemoryHandle handle1;
716 ++count;
717
718 if (count == 1) {
719 handle1 = GetSharedMemoryHandleFromMsg1(message);
720 } else if (count == 2) {
721 base::SharedMemoryHandle handle2(GetSharedMemoryHandleFromMsg1(message));
722
723 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
724 handle1, handle2, kDataBuffer1);
725 SendControlMessage(sender, success);
726 }
727 }
728
729 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendTwoMessagesSameSharedMemoryHandle) {
730 return CommonPrivilegedProcessMain(
731 &SendTwoMessagesSameSharedMemoryHandleCallback,
732 "SendTwoMessagesSameSharedMemoryHandle");
733 }
734
735 // Similar to SendSharedMemoryHandle, but sends one message with two different
736 // memory regions.
737 TEST_F(IPCAttachmentBrokerMacTest,
738 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
739 CommonSetUp("SendOneMessageWithTwoDifferentSharedMemoryHandles");
740
741 {
742 std::unique_ptr<base::SharedMemory> shared_memory1(
743 MakeSharedMemory(kDataBuffer1));
744 std::unique_ptr<base::SharedMemory> shared_memory2(
745 MakeSharedMemory(kDataBuffer2));
746 IPC::Message* message = new TestSharedMemoryHandleMsg2(
747 shared_memory1->handle(), shared_memory2->handle());
748 sender()->Send(message);
749 }
750 base::RunLoop().Run();
751 CommonTearDown();
752 }
753
754 void SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback(
755 IPC::Sender* sender,
756 const IPC::Message& message,
757 ChildProcessGlobals* globals) {
758 base::SharedMemoryHandle handle1;
759 base::SharedMemoryHandle handle2;
760 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
761 LOG(ERROR) << "Failed to deserialize message.";
762 SendControlMessage(sender, false);
763 return;
764 }
765
766 bool success = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
767 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
768 SendControlMessage(sender, success);
769 }
770
771 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
772 SendOneMessageWithTwoDifferentSharedMemoryHandles) {
773 return CommonPrivilegedProcessMain(
774 &SendOneMessageWithTwoDifferentSharedMemoryHandlesCallback,
775 "SendOneMessageWithTwoDifferentSharedMemoryHandles");
776 }
777
778 // Similar to SendSharedMemoryHandle, but sends one message that contains the
779 // same memory region twice.
780 TEST_F(IPCAttachmentBrokerMacTest,
781 SendOneMessageWithTwoSameSharedMemoryHandles) {
782 CommonSetUp("SendOneMessageWithTwoSameSharedMemoryHandles");
783
784 {
785 std::unique_ptr<base::SharedMemory> shared_memory(
786 MakeSharedMemory(kDataBuffer1));
787 IPC::Message* message = new TestSharedMemoryHandleMsg2(
788 shared_memory->handle(), shared_memory->handle());
789 sender()->Send(message);
790 }
791 base::RunLoop().Run();
792 CommonTearDown();
793 }
794
795 void SendOneMessageWithTwoSameSharedMemoryHandlesCallback(
796 IPC::Sender* sender,
797 const IPC::Message& message,
798 ChildProcessGlobals* globals) {
799 base::SharedMemoryHandle handle1;
800 base::SharedMemoryHandle handle2;
801 if (!GetSharedMemoryHandlesFromMsg2(message, &handle1, &handle2)) {
802 LOG(ERROR) << "Failed to deserialize message.";
803 SendControlMessage(sender, false);
804 return;
805 }
806
807 bool success = CheckContentsOfTwoEquivalentSharedMemoryHandles(
808 handle1, handle2, kDataBuffer1);
809 SendControlMessage(sender, success);
810 }
811
812 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(
813 SendOneMessageWithTwoSameSharedMemoryHandles) {
814 return CommonPrivilegedProcessMain(
815 &SendOneMessageWithTwoSameSharedMemoryHandlesCallback,
816 "SendOneMessageWithTwoSameSharedMemoryHandles");
817 }
818
819 // Sends one message with two Posix FDs and two Mach ports.
820 TEST_F(IPCAttachmentBrokerMacTest, SendPosixFDAndMachPort) {
821 base::ScopedTempDir temp_dir;
822 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
823 base::FilePath fp1, fp2;
824 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &fp1));
825 ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir.GetPath(), &fp2));
826
827 CommonSetUp("SendPosixFDAndMachPort");
828
829 {
830 std::unique_ptr<base::SharedMemory> shared_memory1(
831 MakeSharedMemory(kDataBuffer1));
832 std::unique_ptr<base::SharedMemory> shared_memory2(
833 MakeSharedMemory(kDataBuffer2));
834
835 base::FileDescriptor file_descriptor1(
836 MakeFileDescriptor(fp1, kDataBuffer3));
837 base::FileDescriptor file_descriptor2(
838 MakeFileDescriptor(fp2, kDataBuffer4));
839
840 IPC::Message* message = new TestSharedMemoryHandleMsg3(
841 file_descriptor1, shared_memory1->handle(), file_descriptor2,
842 shared_memory2->handle());
843 sender()->Send(message);
844 }
845
846 base::RunLoop().Run();
847 CommonTearDown();
848 }
849
850 void SendPosixFDAndMachPortCallback(IPC::Sender* sender,
851 const IPC::Message& message,
852 ChildProcessGlobals* globals) {
853 TestSharedMemoryHandleMsg3::Schema::Param p;
854 if (!TestSharedMemoryHandleMsg3::Read(&message, &p)) {
855 LOG(ERROR) << "Failed to deserialize message.";
856 SendControlMessage(sender, false);
857 return;
858 }
859
860 base::SharedMemoryHandle handle1 = std::get<1>(p);
861 base::SharedMemoryHandle handle2 = std::get<3>(p);
862 bool success1 = CheckContentsOfSharedMemoryHandle(handle1, kDataBuffer1) &&
863 CheckContentsOfSharedMemoryHandle(handle2, kDataBuffer2);
864 if (!success1)
865 LOG(ERROR) << "SharedMemoryHandles have wrong contents.";
866
867 bool success2 =
868 CheckContentsOfFileDescriptor(std::get<0>(p), kDataBuffer3) &&
869 CheckContentsOfFileDescriptor(std::get<2>(p), kDataBuffer4);
870 if (!success2)
871 LOG(ERROR) << "FileDescriptors have wrong contents.";
872
873 SendControlMessage(sender, success1 && success2);
874 }
875
876 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendPosixFDAndMachPort) {
877 return CommonPrivilegedProcessMain(&SendPosixFDAndMachPortCallback,
878 "SendPosixFDAndMachPort");
879 }
880
881 // Similar to SendHandle, except the attachment's destination process is this
882 // process. This is an unrealistic scenario, but simulates an unprivileged
883 // process sending an attachment to another unprivileged process.
884 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelf) {
885 SetBroker(new MockBroker);
886 PreConnectSetUp("SendSharedMemoryHandleToSelf");
887 // Technically, the channel is an endpoint, but we need the proxy listener to
888 // receive the messages so that it can quit the message loop.
889 channel()->SetAttachmentBrokerEndpoint(false);
890 PostConnectSetUp();
891 get_proxy_listener()->set_listener(get_broker());
892
893 {
894 std::unique_ptr<base::SharedMemory> shared_memory(
895 MakeSharedMemory(kDataBuffer1));
896 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
897 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
898
899 IPC::Message* message =
900 new TestSharedMemoryHandleMsg1(100, shared_memory->handle(), 200);
901 sender()->Send(message);
902
903 // Wait until the child process has sent this process a message.
904 base::RunLoop().Run();
905
906 // Wait for any asynchronous activity to complete.
907 base::RunLoop().RunUntilIdle();
908
909 // Get the received attachment.
910 IPC::BrokerableAttachment::AttachmentId* id = get_observer()->get_id();
911 ASSERT_TRUE(id);
912 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
913 get_broker()->GetAttachmentWithId(*id, &received_attachment);
914 ASSERT_NE(received_attachment.get(), nullptr);
915
916 // Check that it's has the same name, but that the ref count has increased.
917 base::mac::ScopedMachSendRight memory_object(
918 GetMachPortFromBrokeredAttachment(received_attachment));
919 ASSERT_EQ(memory_object, shared_memory->handle().GetMemoryObject());
920 EXPECT_EQ(ref_count + 1,
921 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
922 MACH_PORT_RIGHT_SEND));
923 }
924
925 FinalCleanUp();
926 }
927
928 void SendSharedMemoryHandleToSelfCallback(IPC::Sender* sender,
929 const IPC::Message&,
930 ChildProcessGlobals* globals) {
931 // Do nothing special. The default behavior already runs the
932 // AttachmentBrokerPrivilegedMac.
933 }
934
935 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelf) {
936 return CommonPrivilegedProcessMain(&SendSharedMemoryHandleToSelfCallback,
937 "SendSharedMemoryHandleToSelf");
938 }
939
940 // Similar to SendSharedMemoryHandle, but uses a ChannelProxy instead of a
941 // Channel.
942 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleChannelProxy) {
943 Init("SendSharedMemoryHandleChannelProxy");
944 MachPreForkSetUp();
945
946 SetBroker(new IPC::AttachmentBrokerUnprivilegedMac);
947 get_broker()->AddObserver(get_observer(), task_runner());
948
949 std::unique_ptr<base::Thread> thread(
950 new base::Thread("ChannelProxyTestServerThread"));
951 base::Thread::Options options;
952 options.message_loop_type = base::MessageLoop::TYPE_IO;
953 thread->StartWithOptions(options);
954
955 set_channel_proxy(std::unique_ptr<IPC::ChannelProxy>(new IPC::ChannelProxy(
956 get_proxy_listener(), thread->task_runner().get())));
957 get_broker()->RegisterBrokerCommunicationChannel(channel_proxy());
958 channel_proxy()->Init(
959 CreateChannelFactory(GetTestChannelHandle(), thread->task_runner().get()),
960 true);
961
962 ASSERT_TRUE(StartClient());
963
964 MachPostForkSetUp();
965 active_names_at_start_ = IPC::GetActiveNameCount();
966 get_proxy_listener()->set_listener(get_result_listener());
967
968 SendMessage1(kDataBuffer1);
969 base::RunLoop().Run();
970
971 CheckChildResult();
972
973 // There should be no leaked names.
974 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount());
975
976 // Close the channel so the client's OnChannelError() gets fired.
977 channel_proxy()->Close();
978
979 EXPECT_TRUE(WaitForClientShutdown());
980 DestroyChannelProxy();
981 }
982
983 void SendSharedMemoryHandleChannelProxyCallback(IPC::Sender* sender,
984 const IPC::Message& message,
985 ChildProcessGlobals* globals) {
986 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
987 SendControlMessage(sender, success);
988 }
989
990 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleChannelProxy) {
991 return CommonPrivilegedProcessMain(
992 &SendSharedMemoryHandleChannelProxyCallback,
993 "SendSharedMemoryHandleChannelProxy");
994 }
995
996 // Similar to SendSharedMemoryHandle, but first makes a copy of the handle using
997 // ShareToProcess().
998 TEST_F(IPCAttachmentBrokerMacTest, ShareToProcess) {
999 CommonSetUp("ShareToProcess");
1000
1001 {
1002 std::unique_ptr<base::SharedMemory> shared_memory(
1003 MakeSharedMemory(kDataBuffer1));
1004 base::SharedMemoryHandle new_handle;
1005 ASSERT_TRUE(shared_memory->ShareToProcess(0, &new_handle));
1006 IPC::Message* message =
1007 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
1008 sender()->Send(message);
1009 }
1010
1011 base::RunLoop().Run();
1012 CommonTearDown();
1013 }
1014
1015 void ShareToProcessCallback(IPC::Sender* sender,
1016 const IPC::Message& message,
1017 ChildProcessGlobals* globals) {
1018 bool success = CheckContentsOfMessage1(message, kDataBuffer1);
1019 SendControlMessage(sender, success);
1020 }
1021
1022 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareToProcess) {
1023 return CommonPrivilegedProcessMain(&ShareToProcessCallback, "ShareToProcess");
1024 }
1025
1026 // Similar to ShareToProcess, but instead shares the memory object only with
1027 // read permissions.
1028 TEST_F(IPCAttachmentBrokerMacTest, ShareReadOnlyToProcess) {
1029 CommonSetUp("ShareReadOnlyToProcess");
1030
1031 {
1032 std::unique_ptr<base::SharedMemory> shared_memory(
1033 MakeSharedMemory(kDataBuffer1));
1034 base::SharedMemoryHandle new_handle;
1035 ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(0, &new_handle));
1036 IPC::Message* message =
1037 new TestSharedMemoryHandleMsg1(100, new_handle, 200);
1038 sender()->Send(message);
1039 }
1040
1041 base::RunLoop().Run();
1042 CommonTearDown();
1043 }
1044
1045 void ShareReadOnlyToProcessCallback(IPC::Sender* sender,
1046 const IPC::Message& message,
1047 ChildProcessGlobals* globals) {
1048 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1049
1050 // Try to map the memory as writable.
1051 std::unique_ptr<base::SharedMemory> shared_memory(
1052 MapSharedMemoryHandle(shm, false));
1053 ASSERT_EQ(nullptr, shared_memory->memory());
1054
1055 // Now try as read-only.
1056 std::unique_ptr<base::SharedMemory> shared_memory2(
1057 MapSharedMemoryHandle(shm.Duplicate(), true));
1058 int current_prot, max_prot;
1059 ASSERT_TRUE(IPC::GetMachProtections(shared_memory2->memory(),
1060 shared_memory2->mapped_size(),
1061 &current_prot, &max_prot));
1062 ASSERT_EQ(VM_PROT_READ, current_prot);
1063 ASSERT_EQ(VM_PROT_READ, max_prot);
1064
1065 bool success =
1066 memcmp(shared_memory2->memory(), kDataBuffer1, strlen(kDataBuffer1)) == 0;
1067 SendControlMessage(sender, success);
1068 }
1069
1070 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(ShareReadOnlyToProcess) {
1071 return CommonPrivilegedProcessMain(&ShareReadOnlyToProcessCallback,
1072 "ShareReadOnlyToProcess");
1073 }
1074
1075 // Similar to SendSharedMemoryHandleToSelf, but the child process pretends to
1076 // not have the task port for the parent process.
1077 TEST_F(IPCAttachmentBrokerMacTest, SendSharedMemoryHandleToSelfDelayedPort) {
1078 SetBroker(new MockBroker);
1079 PreConnectSetUp("SendSharedMemoryHandleToSelfDelayedPort");
1080 // Technically, the channel is an endpoint, but we need the proxy listener to
1081 // receive the messages so that it can quit the message loop.
1082 channel()->SetAttachmentBrokerEndpoint(false);
1083 PostConnectSetUp();
1084 get_proxy_listener()->set_listener(get_broker());
1085
1086 {
1087 std::unique_ptr<base::SharedMemory> shared_memory(
1088 MakeSharedMemory(kDataBuffer1));
1089 mach_port_urefs_t ref_count = IPC::GetMachRefCount(
1090 shared_memory->handle().GetMemoryObject(), MACH_PORT_RIGHT_SEND);
1091
1092 std::vector<IPC::BrokerableAttachment::AttachmentId> ids;
1093 const int kMessagesToTest = 3;
1094 for (int i = 0; i < kMessagesToTest; ++i) {
1095 base::SharedMemoryHandle h = shared_memory->handle().Duplicate();
1096 ids.push_back(
1097 IPC::BrokerableAttachment::AttachmentId::CreateIdWithRandomNonce());
1098 IPC::internal::MachPortAttachmentMac::WireFormat wire_format(
1099 h.GetMemoryObject(), getpid(), ids[i]);
1100 sender()->Send(new AttachmentBrokerMsg_DuplicateMachPort(wire_format));
1101
1102 // Send a dummy message, which will trigger the callback handler in the
1103 // child process.
1104 sender()->Send(new TestSharedMemoryHandleMsg4(1));
1105 }
1106
1107 int received_message_count = 0;
1108 while (received_message_count < kMessagesToTest) {
1109 // Wait until the child process has sent this process a message.
1110 base::RunLoop().Run();
1111
1112 // Wait for any asynchronous activity to complete.
1113 base::RunLoop().RunUntilIdle();
1114
1115 while (get_proxy_listener()->has_message()) {
1116 get_proxy_listener()->pop_first_message();
1117 received_message_count++;
1118 }
1119 }
1120
1121 for (int i = 0; i < kMessagesToTest; ++i) {
1122 IPC::BrokerableAttachment::AttachmentId* id = &ids[i];
1123 ASSERT_TRUE(id);
1124 scoped_refptr<IPC::BrokerableAttachment> received_attachment;
1125 get_broker()->GetAttachmentWithId(*id, &received_attachment);
1126 ASSERT_NE(received_attachment.get(), nullptr);
1127
1128 base::mac::ScopedMachSendRight memory_object(
1129 GetMachPortFromBrokeredAttachment(received_attachment));
1130 ASSERT_EQ(shared_memory->handle().GetMemoryObject(), memory_object);
1131 }
1132
1133 // Check that the ref count hasn't changed.
1134 EXPECT_EQ(ref_count,
1135 IPC::GetMachRefCount(shared_memory->handle().GetMemoryObject(),
1136 MACH_PORT_RIGHT_SEND));
1137 }
1138
1139 FinalCleanUp();
1140 }
1141
1142 void SendSharedMemoryHandleToSelfDelayedPortCallback(
1143 IPC::Sender* sender,
1144 const IPC::Message& message,
1145 ChildProcessGlobals* globals) {
1146 static int i = 0;
1147 static base::ProcessId pid = message.get_sender_pid();
1148 static mach_port_t task_port = globals->port_provider.TaskForPid(pid);
1149 ++i;
1150
1151 if (i == 1) {
1152 // Pretend to not have the task port for the parent.
1153 globals->port_provider.ClearPortMap();
1154 } else if (i == 2) {
1155 // Intentionally do nothing.
1156 } else if (i == 3) {
1157 // Setting the task port should trigger callbacks, eventually resulting in
1158 // multiple attachment broker messages.
1159 globals->port_provider.InsertEntry(pid, task_port);
1160 }
1161 }
1162
1163 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) {
1164 return CommonPrivilegedProcessMain(
1165 &SendSharedMemoryHandleToSelfDelayedPortCallback,
1166 "SendSharedMemoryHandleToSelfDelayedPort");
1167 }
1168
1169 // Tests the memory usage characteristics of attachment brokering a single large
1170 // message. This test has the *potential* to be flaky, since it compares
1171 // resident memory at different points in time, and that measurement is
1172 // non-deterministic.
1173 TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) {
1174 CommonSetUp("MemoryUsageLargeMessage");
1175
1176 std::string test_string(g_large_message_size, 'a');
1177 SendMessage1(test_string);
1178 base::RunLoop().Run();
1179 CommonTearDown();
1180 }
1181
1182 void MemoryUsageLargeMessageCallback(IPC::Sender* sender,
1183 const IPC::Message& message,
1184 ChildProcessGlobals* globals) {
1185 EXPECT_LE(GetResidentSize(),
1186 globals->initial_resident_size + g_expected_memory_increase);
1187
1188 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1189 std::unique_ptr<base::SharedMemory> shared_memory(
1190 MapSharedMemoryHandle(shm, false));
1191 EXPECT_LE(GetResidentSize(),
1192 globals->initial_resident_size + g_expected_memory_increase);
1193
1194 char* addr = static_cast<char*>(shared_memory->memory());
1195 for (size_t i = 0; i < g_large_message_size; i += 1024) {
1196 addr[i] = 'a';
1197 }
1198 EXPECT_GE(GetResidentSize(),
1199 globals->initial_resident_size + g_large_message_size);
1200
1201 shared_memory.reset();
1202 #if !defined(ADDRESS_SANITIZER) && !defined(LEAK_SANITIZER) && \
1203 !defined(MEMORY_SANITIZER) && !defined(THREAD_SANITIZER) && \
1204 !defined(UNDEFINED_SANITIZER)
1205 // Under a sanitizer build, releasing memory does not necessarily reduce the
1206 // amount of resident memory.
1207 EXPECT_LE(GetResidentSize(),
1208 globals->initial_resident_size + g_expected_memory_increase);
1209 #endif
1210
1211 SendControlMessage(sender, true);
1212 }
1213
1214 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) {
1215 return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback,
1216 "MemoryUsageLargeMessage");
1217 }
1218
1219 // Tests the memory usage characteristics of attachment brokering many small
1220 // messages. This test has the *potential* to be flaky, since it compares
1221 // resident memory at different points in time, and that measurement is
1222 // non-deterministic.
1223 TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) {
1224 CommonSetUp("MemoryUsageManyMessages");
1225
1226 for (int i = 0; i < g_large_message_count; ++i) {
1227 std::string message = base::IntToString(i);
1228 message += '\0';
1229 size_t end = message.size();
1230 message.resize(g_medium_message_size);
1231 std::fill(message.begin() + end, message.end(), 'a');
1232 SendMessage1(message);
1233
1234 base::RunLoop().RunUntilIdle();
1235 }
1236
1237 if (get_result_listener()->get_result() == RESULT_UNKNOWN)
1238 base::RunLoop().Run();
1239
1240 CommonTearDown();
1241 }
1242
1243 void MemoryUsageManyMessagesCallback(IPC::Sender* sender,
1244 const IPC::Message& message,
1245 ChildProcessGlobals* globals) {
1246 static int message_index = 0;
1247
1248 {
1249 // Map the shared memory, and make sure that its pages are counting towards
1250 // resident size.
1251 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message));
1252 std::unique_ptr<base::SharedMemory> shared_memory(
1253 MapSharedMemoryHandle(shm, false));
1254
1255 char* addr = static_cast<char*>(shared_memory->memory());
1256 std::string message_string(addr);
1257 int message_int;
1258 ASSERT_TRUE(base::StringToInt(message_string, &message_int));
1259 ASSERT_EQ(message_index, message_int);
1260 for (size_t i = 0; i < g_medium_message_size; i += 1024) {
1261 addr[i] = 'a';
1262 }
1263 }
1264
1265 ++message_index;
1266
1267 if (message_index == 1) {
1268 // Disable message logging, since it significantly contributes towards total
1269 // memory usage.
1270 LOG(INFO) << "Disable privileged process message logging.";
1271 globals->message_logging = false;
1272 }
1273
1274 if (message_index == g_large_message_count) {
1275 size_t memory_increase_kb =
1276 (GetResidentSize() - globals->initial_resident_size) / 1024;
1277 LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb;
1278
1279 #if defined(ADDRESS_SANITIZER) || defined(LEAK_SANITIZER) || \
1280 defined(MEMORY_SANITIZER) || defined(THREAD_SANITIZER) || \
1281 defined(UNDEFINED_SANITIZER)
1282 // Under a sanitizer build, releasing memory does not necessarily reduce the
1283 // amount of resident memory.
1284 bool success = true;
1285 #else
1286 // The total increase in resident size should be less than 1MB. The exact
1287 // amount is not deterministic.
1288 bool success = memory_increase_kb < 1024;
1289 #endif
1290
1291 SendControlMessage(sender, success);
1292 }
1293 }
1294
1295 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) {
1296 return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback,
1297 "MemoryUsageManyMessages");
1298 }
1299
1300 } // namespace
OLDNEW
« no previous file with comments | « ipc/attachment_broker.cc ('k') | ipc/attachment_broker_messages.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698