OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <mach/mach_vm.h> | |
8 #include <sys/mman.h> | 9 #include <sys/mman.h> |
9 | 10 |
10 #include "base/command_line.h" | 11 #include "base/command_line.h" |
11 #include "base/files/file_util.h" | 12 #include "base/files/file_util.h" |
12 #include "base/files/scoped_file.h" | 13 #include "base/files/scoped_file.h" |
13 #include "base/files/scoped_temp_dir.h" | 14 #include "base/files/scoped_temp_dir.h" |
14 #include "base/mac/mac_util.h" | 15 #include "base/mac/mac_util.h" |
15 #include "base/memory/scoped_ptr.h" | 16 #include "base/memory/scoped_ptr.h" |
16 #include "base/memory/shared_memory.h" | 17 #include "base/memory/shared_memory.h" |
18 #include "base/strings/string_number_conversions.h" | |
19 #include "base/synchronization/spin_wait.h" | |
20 #include "base/time/time.h" | |
17 #include "ipc/attachment_broker_messages.h" | 21 #include "ipc/attachment_broker_messages.h" |
18 #include "ipc/attachment_broker_privileged_mac.h" | 22 #include "ipc/attachment_broker_privileged_mac.h" |
19 #include "ipc/attachment_broker_unprivileged_mac.h" | 23 #include "ipc/attachment_broker_unprivileged_mac.h" |
20 #include "ipc/ipc_listener.h" | 24 #include "ipc/ipc_listener.h" |
21 #include "ipc/ipc_message.h" | 25 #include "ipc/ipc_message.h" |
22 #include "ipc/ipc_test_base.h" | 26 #include "ipc/ipc_test_base.h" |
23 #include "ipc/ipc_test_messages.h" | 27 #include "ipc/ipc_test_messages.h" |
24 #include "ipc/test_util_mac.h" | 28 #include "ipc/test_util_mac.h" |
25 | 29 |
26 namespace { | 30 namespace { |
27 | 31 |
28 const char kDataBuffer1[] = "This is some test data to write to the file."; | 32 const char kDataBuffer1[] = "This is some test data to write to the file."; |
29 const char kDataBuffer2[] = "The lazy dog and a fox."; | 33 const char kDataBuffer2[] = "The lazy dog and a fox."; |
30 const char kDataBuffer3[] = "Two green bears but not a potato."; | 34 const char kDataBuffer3[] = "Two green bears but not a potato."; |
31 const char kDataBuffer4[] = "Red potato is best potato."; | 35 const char kDataBuffer4[] = "Red potato is best potato."; |
32 const std::string g_service_switch_name = "service_name"; | 36 const std::string g_service_switch_name = "service_name"; |
33 | 37 |
34 enum TestResult { | 38 enum TestResult { |
35 RESULT_UNKNOWN, | 39 RESULT_UNKNOWN, |
36 RESULT_SUCCESS, | 40 RESULT_SUCCESS, |
37 RESULT_FAILURE, | 41 RESULT_FAILURE, |
38 }; | 42 }; |
39 | 43 |
44 mach_vm_size_t GetResidentSize() { | |
45 task_basic_info_64 info; | |
46 mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT; | |
47 kern_return_t kr = task_info(mach_task_self(), TASK_BASIC_INFO_64, | |
48 reinterpret_cast<task_info_t>(&info), &count); | |
49 if (kr != KERN_SUCCESS) | |
50 LOG(FATAL) << "Couldn't get resident size."; | |
Mark Mentovai
2015/11/19 22:54:34
Basically just CHECK(kr == KERN_SUCCESS), or even
erikchen
2015/11/20 00:37:59
Done.
| |
51 | |
52 return info.resident_size; | |
53 } | |
54 | |
40 base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment( | 55 base::mac::ScopedMachSendRight GetMachPortFromBrokeredAttachment( |
41 const scoped_refptr<IPC::BrokerableAttachment>& attachment) { | 56 const scoped_refptr<IPC::BrokerableAttachment>& attachment) { |
42 if (attachment->GetType() != | 57 if (attachment->GetType() != |
43 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) { | 58 IPC::BrokerableAttachment::TYPE_BROKERABLE_ATTACHMENT) { |
44 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT."; | 59 LOG(INFO) << "Attachment type not TYPE_BROKERABLE_ATTACHMENT."; |
45 return base::mac::ScopedMachSendRight(MACH_PORT_NULL); | 60 return base::mac::ScopedMachSendRight(MACH_PORT_NULL); |
46 } | 61 } |
47 | 62 |
48 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) { | 63 if (attachment->GetBrokerableType() != IPC::BrokerableAttachment::MACH_PORT) { |
49 LOG(INFO) << "Brokerable type not MACH_PORT."; | 64 LOG(INFO) << "Brokerable type not MACH_PORT."; |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
411 } | 426 } |
412 | 427 |
413 void CheckChildResult() { | 428 void CheckChildResult() { |
414 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, | 429 ASSERT_EQ(ProxyListener::MESSAGE_RECEIVED, |
415 get_proxy_listener()->get_reason()); | 430 get_proxy_listener()->get_reason()); |
416 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS); | 431 ASSERT_EQ(get_result_listener()->get_result(), RESULT_SUCCESS); |
417 } | 432 } |
418 | 433 |
419 void FinalCleanUp() { | 434 void FinalCleanUp() { |
420 // There should be no leaked names. | 435 // There should be no leaked names. |
436 SPIN_FOR_TIMEDELTA_OR_UNTIL_TRUE( | |
437 base::TimeDelta::FromSeconds(10), | |
438 active_names_at_start_ == IPC::GetActiveNameCount()); | |
421 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount()); | 439 EXPECT_EQ(active_names_at_start_, IPC::GetActiveNameCount()); |
422 | 440 |
423 // Close the channel so the client's OnChannelError() gets fired. | 441 // Close the channel so the client's OnChannelError() gets fired. |
424 channel()->Close(); | 442 channel()->Close(); |
425 | 443 |
426 EXPECT_TRUE(WaitForClientShutdown()); | 444 EXPECT_TRUE(WaitForClientShutdown()); |
427 DestroyChannel(); | 445 DestroyChannel(); |
428 broker_.reset(); | 446 broker_.reset(); |
429 } | 447 } |
430 | 448 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
474 // Channels. | 492 // Channels. |
475 struct ChildProcessGlobals { | 493 struct ChildProcessGlobals { |
476 MockPortProvider port_provider; | 494 MockPortProvider port_provider; |
477 | 495 |
478 // The broker must be destroyed before the port_provider, so that the broker | 496 // The broker must be destroyed before the port_provider, so that the broker |
479 // gets a chance to unregister itself as an observer. This doesn't matter | 497 // gets a chance to unregister itself as an observer. This doesn't matter |
480 // outside of tests, since neither port_provider nor broker will ever be | 498 // outside of tests, since neither port_provider nor broker will ever be |
481 // destroyed. | 499 // destroyed. |
482 scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker; | 500 scoped_ptr<IPC::AttachmentBrokerPrivilegedMac> broker; |
483 base::mac::ScopedMachSendRight server_task_port; | 501 base::mac::ScopedMachSendRight server_task_port; |
502 | |
503 // Total resident memory before running the message loop. | |
504 mach_vm_size_t initial_resident_size; | |
505 | |
506 // Whether to emit log statements while processing messages. | |
507 bool message_logging; | |
484 }; | 508 }; |
485 | 509 |
486 using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, | 510 using OnMessageReceivedCallback = void (*)(IPC::Sender* sender, |
487 const IPC::Message& message, | 511 const IPC::Message& message, |
488 ChildProcessGlobals* globals); | 512 ChildProcessGlobals* globals); |
489 | 513 |
490 // Sets up the Mach communication ports with the server. Returns a set of | 514 // Sets up the Mach communication ports with the server. Returns a set of |
491 // globals that must live at least as long as the test. | 515 // globals that must live at least as long as the test. |
492 scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() { | 516 scoped_ptr<ChildProcessGlobals> CommonChildProcessSetUp() { |
493 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess(); | 517 base::CommandLine cmd_line = *base::CommandLine::ForCurrentProcess(); |
494 std::string service_name = | 518 std::string service_name = |
495 cmd_line.GetSwitchValueASCII(g_service_switch_name); | 519 cmd_line.GetSwitchValueASCII(g_service_switch_name); |
496 base::mac::ScopedMachSendRight server_port( | 520 base::mac::ScopedMachSendRight server_port( |
497 IPC::LookupServer(service_name.c_str())); | 521 IPC::LookupServer(service_name.c_str())); |
498 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort()); | 522 base::mac::ScopedMachReceiveRight client_port(IPC::MakeReceivingPort()); |
499 | 523 |
500 // Send the port that this process is listening on to the server. | 524 // Send the port that this process is listening on to the server. |
501 IPC::SendMachPort( | 525 IPC::SendMachPort( |
502 server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND); | 526 server_port.get(), client_port.get(), MACH_MSG_TYPE_MAKE_SEND); |
503 | 527 |
504 // Receive the task port of the server process. | 528 // Receive the task port of the server process. |
505 base::mac::ScopedMachSendRight server_task_port( | 529 base::mac::ScopedMachSendRight server_task_port( |
506 IPC::ReceiveMachPort(client_port.get())); | 530 IPC::ReceiveMachPort(client_port.get())); |
507 | 531 |
508 scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals); | 532 scoped_ptr<ChildProcessGlobals> globals(new ChildProcessGlobals); |
509 globals->broker.reset( | 533 globals->broker.reset( |
510 new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider)); | 534 new IPC::AttachmentBrokerPrivilegedMac(&globals->port_provider)); |
511 globals->port_provider.InsertEntry(getppid(), server_task_port.get()); | 535 globals->port_provider.InsertEntry(getppid(), server_task_port.get()); |
512 globals->server_task_port.reset(server_task_port.release()); | 536 globals->server_task_port.reset(server_task_port.release()); |
537 globals->message_logging = true; | |
513 return globals; | 538 return globals; |
514 } | 539 } |
515 | 540 |
516 int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, | 541 int CommonPrivilegedProcessMain(OnMessageReceivedCallback callback, |
517 const char* channel_name) { | 542 const char* channel_name) { |
518 LOG(INFO) << "Privileged process start."; | 543 LOG(INFO) << "Privileged process start."; |
519 scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp()); | 544 scoped_ptr<ChildProcessGlobals> globals(CommonChildProcessSetUp()); |
520 | 545 |
521 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount(); | 546 mach_msg_type_number_t active_names_at_start = IPC::GetActiveNameCount(); |
522 | 547 |
523 base::MessageLoopForIO main_message_loop; | 548 base::MessageLoopForIO main_message_loop; |
524 ProxyListener listener; | 549 ProxyListener listener; |
525 | 550 |
526 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( | 551 scoped_ptr<IPC::Channel> channel(IPC::Channel::CreateClient( |
527 IPCTestBase::GetChannelName(channel_name), &listener)); | 552 IPCTestBase::GetChannelName(channel_name), &listener)); |
528 globals->broker->RegisterCommunicationChannel(channel.get()); | 553 globals->broker->RegisterCommunicationChannel(channel.get()); |
529 CHECK(channel->Connect()); | 554 CHECK(channel->Connect()); |
530 | 555 |
556 globals->initial_resident_size = GetResidentSize(); | |
557 | |
531 while (true) { | 558 while (true) { |
532 LOG(INFO) << "Privileged process spinning run loop."; | 559 if (globals->message_logging) |
560 LOG(INFO) << "Privileged process spinning run loop."; | |
533 base::MessageLoop::current()->Run(); | 561 base::MessageLoop::current()->Run(); |
534 ProxyListener::Reason reason = listener.get_reason(); | 562 ProxyListener::Reason reason = listener.get_reason(); |
535 if (reason == ProxyListener::CHANNEL_ERROR) | 563 if (reason == ProxyListener::CHANNEL_ERROR) |
536 break; | 564 break; |
537 | 565 |
538 while (listener.has_message()) { | 566 while (listener.has_message()) { |
539 LOG(INFO) << "Privileged process running callback."; | 567 if (globals->message_logging) |
568 LOG(INFO) << "Privileged process running callback."; | |
540 callback(channel.get(), listener.get_first_message(), globals.get()); | 569 callback(channel.get(), listener.get_first_message(), globals.get()); |
541 LOG(INFO) << "Privileged process finishing callback."; | 570 if (globals->message_logging) |
571 LOG(INFO) << "Privileged process finishing callback."; | |
542 listener.pop_first_message(); | 572 listener.pop_first_message(); |
543 } | 573 } |
544 } | 574 } |
545 | 575 |
546 if (active_names_at_start != IPC::GetActiveNameCount()) { | 576 if (active_names_at_start != IPC::GetActiveNameCount()) { |
547 LOG(INFO) << "Memory leak!."; | 577 LOG(INFO) << "Memory leak!."; |
548 } | 578 } |
549 LOG(INFO) << "Privileged process end."; | 579 LOG(INFO) << "Privileged process end."; |
550 return 0; | 580 return 0; |
551 } | 581 } |
(...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1145 globals->port_provider.InsertEntry(pid, task_port); | 1175 globals->port_provider.InsertEntry(pid, task_port); |
1146 } | 1176 } |
1147 } | 1177 } |
1148 | 1178 |
1149 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) { | 1179 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(SendSharedMemoryHandleToSelfDelayedPort) { |
1150 return CommonPrivilegedProcessMain( | 1180 return CommonPrivilegedProcessMain( |
1151 &SendSharedMemoryHandleToSelfDelayedPortCallback, | 1181 &SendSharedMemoryHandleToSelfDelayedPortCallback, |
1152 "SendSharedMemoryHandleToSelfDelayedPort"); | 1182 "SendSharedMemoryHandleToSelfDelayedPort"); |
1153 } | 1183 } |
1154 | 1184 |
1185 // Tests the memory usage characteristics of attachment brokering a single | |
1186 // large message. | |
1187 TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageLargeMessage) { | |
1188 // Mach-based SharedMemory isn't support on OSX 10.6. | |
1189 if (base::mac::IsOSSnowLeopard()) | |
1190 return; | |
1191 | |
1192 CommonSetUp("MemoryUsageLargeMessage"); | |
1193 | |
1194 size_t message_size = 1024 * 1024 * 8; | |
1195 std::string test_string(message_size, 'a'); | |
1196 SendMessage1(test_string); | |
1197 base::MessageLoop::current()->Run(); | |
1198 CommonTearDown(); | |
1199 } | |
1200 | |
1201 void MemoryUsageLargeMessageCallback(IPC::Sender* sender, | |
1202 const IPC::Message& message, | |
1203 ChildProcessGlobals* globals) { | |
1204 size_t message_size = 1024 * 1024 * 8; | |
Mark Mentovai
2015/11/19 22:54:34
Share with message_size in the TEST_F above? Same
erikchen
2015/11/20 00:37:59
Done.
| |
1205 EXPECT_LE(GetResidentSize(), globals->initial_resident_size + message_size); | |
Tom Sepez
2015/11/19 22:17:58
I worry about these kinds of tests being flakey ba
Mark Mentovai
2015/11/19 22:54:34
I don’t know if we can really strictly say that th
erikchen
2015/11/20 00:37:59
you're right, I was using message_size for two dif
| |
1206 | |
1207 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); | |
1208 scoped_ptr<base::SharedMemory> shared_memory( | |
1209 MapSharedMemoryHandle(shm, false)); | |
1210 EXPECT_LE(GetResidentSize(), globals->initial_resident_size + message_size); | |
1211 | |
1212 // Volatile prevents the compiler from optimizing out |c|. | |
1213 volatile char c = '\0'; | |
1214 void* addr = shared_memory->memory(); | |
1215 for (size_t i = 0; i < message_size; i += 1024) { | |
1216 c += static_cast<char*>(addr)[i]; | |
1217 } | |
1218 EXPECT_GE(GetResidentSize(), globals->initial_resident_size + message_size); | |
1219 | |
1220 shared_memory.reset(); | |
1221 EXPECT_LE(GetResidentSize(), globals->initial_resident_size + message_size); | |
1222 | |
1223 SendControlMessage(sender, true); | |
1224 } | |
1225 | |
1226 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageLargeMessage) { | |
1227 return CommonPrivilegedProcessMain(&MemoryUsageLargeMessageCallback, | |
1228 "MemoryUsageLargeMessage"); | |
1229 } | |
1230 | |
1231 // Tests the memory usage characteristics of attachment brokering many small | |
1232 // messages. | |
1233 TEST_F(IPCAttachmentBrokerMacTest, MemoryUsageManyMessages) { | |
1234 // Mach-based SharedMemory isn't support on OSX 10.6. | |
1235 if (base::mac::IsOSSnowLeopard()) | |
1236 return; | |
1237 | |
1238 CommonSetUp("MemoryUsageManyMessages"); | |
1239 | |
1240 int message_count = 1000; | |
1241 size_t message_size = 512 * 1024; | |
1242 | |
1243 for (int i = 0; i < message_count; ++i) { | |
1244 std::string message = base::IntToString(i); | |
1245 message += '\0'; | |
1246 size_t end = message.size(); | |
1247 message.resize(message_size); | |
1248 std::fill(message.begin() + end, message.end(), 'a'); | |
1249 SendMessage1(message); | |
1250 | |
1251 base::MessageLoop::current()->RunUntilIdle(); | |
1252 } | |
1253 | |
1254 if (get_result_listener()->get_result() == RESULT_UNKNOWN) | |
1255 base::MessageLoop::current()->Run(); | |
1256 | |
1257 CommonTearDown(); | |
1258 } | |
1259 | |
1260 void MemoryUsageManyMessagesCallback(IPC::Sender* sender, | |
1261 const IPC::Message& message, | |
1262 ChildProcessGlobals* globals) { | |
1263 // Volatile prevents the compiler from optimizing out |c|. | |
1264 static volatile char c = '\0'; | |
1265 static int message_index = 0; | |
1266 size_t message_size = 512 * 1024; | |
1267 int message_count = 1000; | |
1268 | |
1269 { | |
1270 // Map the shared memory, and make sure that its pages are counting towards | |
1271 // resident size. | |
1272 base::SharedMemoryHandle shm(GetSharedMemoryHandleFromMsg1(message)); | |
1273 scoped_ptr<base::SharedMemory> shared_memory( | |
1274 MapSharedMemoryHandle(shm, false)); | |
1275 | |
1276 char* addr = static_cast<char*>(shared_memory->memory()); | |
1277 std::string message_string(addr); | |
1278 int message_int; | |
1279 ASSERT_TRUE(base::StringToInt(message_string, &message_int)); | |
1280 ASSERT_EQ(message_index, message_int); | |
1281 for (size_t i = 0; i < message_size; i += 1024) { | |
1282 c += static_cast<char*>(addr)[i]; | |
1283 } | |
1284 } | |
1285 | |
1286 ++message_index; | |
1287 | |
1288 if (message_index == 1) { | |
1289 // Disable message logging, since it significantly contributes towards total | |
1290 // memory usage. | |
1291 LOG(INFO) << "Disable privileged process message logging."; | |
1292 globals->message_logging = false; | |
1293 } | |
1294 | |
1295 if (message_index == message_count) { | |
1296 size_t memory_increase_kb = | |
1297 (GetResidentSize() - globals->initial_resident_size) / 1024; | |
1298 LOG(INFO) << "Increase in memory usage in KB: " << memory_increase_kb; | |
1299 | |
1300 // The total increase in resident size should be less than 1MB. The exact | |
1301 // amount is not deterministic. | |
1302 bool success = memory_increase_kb < 1024; | |
1303 SendControlMessage(sender, success); | |
1304 } | |
1305 } | |
1306 | |
1307 MULTIPROCESS_IPC_TEST_CLIENT_MAIN(MemoryUsageManyMessages) { | |
1308 return CommonPrivilegedProcessMain(&MemoryUsageManyMessagesCallback, | |
1309 "MemoryUsageManyMessages"); | |
1310 } | |
1311 | |
1155 } // namespace | 1312 } // namespace |
OLD | NEW |