| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 #define _CRT_SECURE_NO_WARNINGS | 5 #define _CRT_SECURE_NO_WARNINGS |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 | 8 |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/debug/alias.h" | 10 #include "base/debug/alias.h" |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 #include <errno.h> | 43 #include <errno.h> |
| 44 #include <fcntl.h> | 44 #include <fcntl.h> |
| 45 #include <sched.h> | 45 #include <sched.h> |
| 46 #include <signal.h> | 46 #include <signal.h> |
| 47 #include <sys/resource.h> | 47 #include <sys/resource.h> |
| 48 #include <sys/socket.h> | 48 #include <sys/socket.h> |
| 49 #include <sys/types.h> | 49 #include <sys/types.h> |
| 50 #include <sys/wait.h> | 50 #include <sys/wait.h> |
| 51 #include <unistd.h> | 51 #include <unistd.h> |
| 52 #endif | 52 #endif |
| 53 #if defined(OS_WIN) | |
| 54 #include <windows.h> | |
| 55 #include "base/win/windows_version.h" | |
| 56 #endif | |
| 57 #if defined(OS_MACOSX) | 53 #if defined(OS_MACOSX) |
| 58 #include <mach/vm_param.h> | 54 #include <mach/vm_param.h> |
| 59 #include <malloc/malloc.h> | 55 #include <malloc/malloc.h> |
| 60 #include "base/mac/mac_util.h" | 56 #include "base/mac/mac_util.h" |
| 61 #endif | 57 #endif |
| 62 | 58 |
| 63 using base::FilePath; | 59 using base::FilePath; |
| 64 | 60 |
| 65 namespace { | 61 namespace { |
| 66 | 62 |
| 67 #if defined(OS_ANDROID) | 63 #if defined(OS_ANDROID) |
| 68 const char kShellPath[] = "/system/bin/sh"; | 64 const char kShellPath[] = "/system/bin/sh"; |
| 69 const char kPosixShell[] = "sh"; | 65 const char kPosixShell[] = "sh"; |
| 70 #else | 66 #else |
| 71 const char kShellPath[] = "/bin/sh"; | 67 const char kShellPath[] = "/bin/sh"; |
| 72 const char kPosixShell[] = "bash"; | 68 const char kPosixShell[] = "bash"; |
| 73 #endif | 69 #endif |
| 74 | 70 |
| 75 const char kSignalFileSlow[] = "SlowChildProcess.die"; | 71 const char kSignalFileSlow[] = "SlowChildProcess.die"; |
| 76 const char kSignalFileKill[] = "KilledChildProcess.die"; | 72 const char kSignalFileKill[] = "KilledChildProcess.die"; |
| 77 | 73 |
| 78 #if defined(OS_POSIX) | 74 #if defined(OS_POSIX) |
| 79 const char kSignalFileTerm[] = "TerminatedChildProcess.die"; | 75 const char kSignalFileTerm[] = "TerminatedChildProcess.die"; |
| 80 #endif | 76 #endif |
| 81 | 77 |
| 82 #if defined(OS_WIN) | |
| 83 const int kExpectedStillRunningExitCode = 0x102; | |
| 84 const int kExpectedKilledExitCode = 1; | |
| 85 #else | |
| 86 const int kExpectedStillRunningExitCode = 0; | 78 const int kExpectedStillRunningExitCode = 0; |
| 87 #endif | |
| 88 | 79 |
| 89 // Sleeps until file filename is created. | 80 // Sleeps until file filename is created. |
| 90 void WaitToDie(const char* filename) { | 81 void WaitToDie(const char* filename) { |
| 91 FILE* fp; | 82 FILE* fp; |
| 92 do { | 83 do { |
| 93 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); | 84 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); |
| 94 fp = fopen(filename, "r"); | 85 fp = fopen(filename, "r"); |
| 95 } while (!fp); | 86 } while (!fp); |
| 96 fclose(fp); | 87 fclose(fp); |
| 97 } | 88 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 | 184 |
| 194 SignalChildren(signal_file.c_str()); | 185 SignalChildren(signal_file.c_str()); |
| 195 exit_code = 42; | 186 exit_code = 42; |
| 196 base::TerminationStatus status = | 187 base::TerminationStatus status = |
| 197 WaitForChildTermination(process.Handle(), &exit_code); | 188 WaitForChildTermination(process.Handle(), &exit_code); |
| 198 EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status); | 189 EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status); |
| 199 EXPECT_EQ(0, exit_code); | 190 EXPECT_EQ(0, exit_code); |
| 200 remove(signal_file.c_str()); | 191 remove(signal_file.c_str()); |
| 201 } | 192 } |
| 202 | 193 |
| 203 #if defined(OS_WIN) | |
| 204 // TODO(cpu): figure out how to test this in other platforms. | |
| 205 TEST_F(ProcessUtilTest, GetProcId) { | |
| 206 base::ProcessId id1 = base::GetProcId(GetCurrentProcess()); | |
| 207 EXPECT_NE(0ul, id1); | |
| 208 base::Process process = SpawnChild("SimpleChildProcess"); | |
| 209 ASSERT_TRUE(process.IsValid()); | |
| 210 base::ProcessId id2 = process.Pid(); | |
| 211 EXPECT_NE(0ul, id2); | |
| 212 EXPECT_NE(id1, id2); | |
| 213 } | |
| 214 #endif | |
| 215 | |
| 216 #if !defined(OS_MACOSX) | 194 #if !defined(OS_MACOSX) |
| 217 // This test is disabled on Mac, since it's flaky due to ReportCrash | 195 // This test is disabled on Mac, since it's flaky due to ReportCrash |
| 218 // taking a variable amount of time to parse and load the debug and | 196 // taking a variable amount of time to parse and load the debug and |
| 219 // symbol data for this unit test's executable before firing the | 197 // symbol data for this unit test's executable before firing the |
| 220 // signal handler. | 198 // signal handler. |
| 221 // | 199 // |
| 222 // TODO(gspencer): turn this test process into a very small program | 200 // TODO(gspencer): turn this test process into a very small program |
| 223 // with no symbols (instead of using the multiprocess testing | 201 // with no symbols (instead of using the multiprocess testing |
| 224 // framework) to reduce the ReportCrash overhead. | 202 // framework) to reduce the ReportCrash overhead. |
| 225 const char kSignalFileCrash[] = "CrashingChildProcess.die"; | 203 const char kSignalFileCrash[] = "CrashingChildProcess.die"; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 255 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, | 233 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING, |
| 256 base::GetTerminationStatus(process.Handle(), &exit_code)); | 234 base::GetTerminationStatus(process.Handle(), &exit_code)); |
| 257 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); | 235 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code); |
| 258 | 236 |
| 259 SignalChildren(signal_file.c_str()); | 237 SignalChildren(signal_file.c_str()); |
| 260 exit_code = 42; | 238 exit_code = 42; |
| 261 base::TerminationStatus status = | 239 base::TerminationStatus status = |
| 262 WaitForChildTermination(process.Handle(), &exit_code); | 240 WaitForChildTermination(process.Handle(), &exit_code); |
| 263 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status); | 241 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status); |
| 264 | 242 |
| 265 #if defined(OS_WIN) | 243 #if defined(OS_POSIX) |
| 266 EXPECT_EQ(0xc0000005, exit_code); | |
| 267 #elif defined(OS_POSIX) | |
| 268 int signaled = WIFSIGNALED(exit_code); | 244 int signaled = WIFSIGNALED(exit_code); |
| 269 EXPECT_NE(0, signaled); | 245 EXPECT_NE(0, signaled); |
| 270 int signal = WTERMSIG(exit_code); | 246 int signal = WTERMSIG(exit_code); |
| 271 EXPECT_EQ(SIGSEGV, signal); | 247 EXPECT_EQ(SIGSEGV, signal); |
| 272 #endif | 248 #endif |
| 273 | 249 |
| 274 // Reset signal handlers back to "normal". | 250 // Reset signal handlers back to "normal". |
| 275 base::debug::EnableInProcessStackDumping(); | 251 base::debug::EnableInProcessStackDumping(); |
| 276 remove(signal_file.c_str()); | 252 remove(signal_file.c_str()); |
| 277 } | 253 } |
| 278 #endif // !defined(OS_MACOSX) | 254 #endif // !defined(OS_MACOSX) |
| 279 | 255 |
| 280 MULTIPROCESS_TEST_MAIN(KilledChildProcess) { | 256 MULTIPROCESS_TEST_MAIN(KilledChildProcess) { |
| 281 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str()); | 257 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileKill).c_str()); |
| 282 #if defined(OS_WIN) | 258 #if defined(OS_POSIX) |
| 283 // Kill ourselves. | |
| 284 HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId()); | |
| 285 ::TerminateProcess(handle, kExpectedKilledExitCode); | |
| 286 #elif defined(OS_POSIX) | |
| 287 // Send a SIGKILL to this process, just like the OOM killer would. | 259 // Send a SIGKILL to this process, just like the OOM killer would. |
| 288 ::kill(getpid(), SIGKILL); | 260 ::kill(getpid(), SIGKILL); |
| 289 #endif | 261 #endif |
| 290 return 1; | 262 return 1; |
| 291 } | 263 } |
| 292 | 264 |
| 293 #if defined(OS_POSIX) | 265 #if defined(OS_POSIX) |
| 294 MULTIPROCESS_TEST_MAIN(TerminatedChildProcess) { | 266 MULTIPROCESS_TEST_MAIN(TerminatedChildProcess) { |
| 295 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileTerm).c_str()); | 267 WaitToDie(ProcessUtilTest::GetSignalFilePath(kSignalFileTerm).c_str()); |
| 296 // Send a SIGTERM to this process. | 268 // Send a SIGTERM to this process. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 314 SignalChildren(signal_file.c_str()); | 286 SignalChildren(signal_file.c_str()); |
| 315 exit_code = 42; | 287 exit_code = 42; |
| 316 base::TerminationStatus status = | 288 base::TerminationStatus status = |
| 317 WaitForChildTermination(process.Handle(), &exit_code); | 289 WaitForChildTermination(process.Handle(), &exit_code); |
| 318 #if defined(OS_CHROMEOS) | 290 #if defined(OS_CHROMEOS) |
| 319 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status); | 291 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM, status); |
| 320 #else | 292 #else |
| 321 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); | 293 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); |
| 322 #endif | 294 #endif |
| 323 | 295 |
| 324 #if defined(OS_WIN) | 296 #if defined(OS_POSIX) |
| 325 EXPECT_EQ(kExpectedKilledExitCode, exit_code); | |
| 326 #elif defined(OS_POSIX) | |
| 327 int signaled = WIFSIGNALED(exit_code); | 297 int signaled = WIFSIGNALED(exit_code); |
| 328 EXPECT_NE(0, signaled); | 298 EXPECT_NE(0, signaled); |
| 329 int signal = WTERMSIG(exit_code); | 299 int signal = WTERMSIG(exit_code); |
| 330 EXPECT_EQ(SIGKILL, signal); | 300 EXPECT_EQ(SIGKILL, signal); |
| 331 #endif | 301 #endif |
| 332 remove(signal_file.c_str()); | 302 remove(signal_file.c_str()); |
| 333 } | 303 } |
| 334 | 304 |
| 335 #if defined(OS_POSIX) | 305 #if defined(OS_POSIX) |
| 336 TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) { | 306 TEST_F(ProcessUtilTest, GetTerminationStatusSigTerm) { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 352 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); | 322 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status); |
| 353 | 323 |
| 354 int signaled = WIFSIGNALED(exit_code); | 324 int signaled = WIFSIGNALED(exit_code); |
| 355 EXPECT_NE(0, signaled); | 325 EXPECT_NE(0, signaled); |
| 356 int signal = WTERMSIG(exit_code); | 326 int signal = WTERMSIG(exit_code); |
| 357 EXPECT_EQ(SIGTERM, signal); | 327 EXPECT_EQ(SIGTERM, signal); |
| 358 remove(signal_file.c_str()); | 328 remove(signal_file.c_str()); |
| 359 } | 329 } |
| 360 #endif | 330 #endif |
| 361 | 331 |
| 362 #if defined(OS_WIN) | |
| 363 // TODO(estade): if possible, port this test. | |
| 364 TEST_F(ProcessUtilTest, GetAppOutput) { | |
| 365 // Let's create a decently long message. | |
| 366 std::string message; | |
| 367 for (int i = 0; i < 1025; i++) { // 1025 so it does not end on a kilo-byte | |
| 368 // boundary. | |
| 369 message += "Hello!"; | |
| 370 } | |
| 371 // cmd.exe's echo always adds a \r\n to its output. | |
| 372 std::string expected(message); | |
| 373 expected += "\r\n"; | |
| 374 | |
| 375 FilePath cmd(L"cmd.exe"); | |
| 376 base::CommandLine cmd_line(cmd); | |
| 377 cmd_line.AppendArg("/c"); | |
| 378 cmd_line.AppendArg("echo " + message + ""); | |
| 379 std::string output; | |
| 380 ASSERT_TRUE(base::GetAppOutput(cmd_line, &output)); | |
| 381 EXPECT_EQ(expected, output); | |
| 382 | |
| 383 // Let's make sure stderr is ignored. | |
| 384 base::CommandLine other_cmd_line(cmd); | |
| 385 other_cmd_line.AppendArg("/c"); | |
| 386 // http://msdn.microsoft.com/library/cc772622.aspx | |
| 387 cmd_line.AppendArg("echo " + message + " >&2"); | |
| 388 output.clear(); | |
| 389 ASSERT_TRUE(base::GetAppOutput(other_cmd_line, &output)); | |
| 390 EXPECT_EQ("", output); | |
| 391 } | |
| 392 | |
| 393 // TODO(estade): if possible, port this test. | |
| 394 TEST_F(ProcessUtilTest, LaunchAsUser) { | |
| 395 base::UserTokenHandle token; | |
| 396 ASSERT_TRUE(OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token)); | |
| 397 base::LaunchOptions options; | |
| 398 options.as_user = token; | |
| 399 EXPECT_TRUE(base::LaunchProcess(MakeCmdLine("SimpleChildProcess"), | |
| 400 options).IsValid()); | |
| 401 } | |
| 402 | |
| 403 static const char kEventToTriggerHandleSwitch[] = "event-to-trigger-handle"; | |
| 404 | |
| 405 MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess) { | |
| 406 std::string handle_value_string = | |
| 407 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 408 kEventToTriggerHandleSwitch); | |
| 409 CHECK(!handle_value_string.empty()); | |
| 410 | |
| 411 uint64 handle_value_uint64; | |
| 412 CHECK(base::StringToUint64(handle_value_string, &handle_value_uint64)); | |
| 413 // Give ownership of the handle to |event|. | |
| 414 base::WaitableEvent event(base::win::ScopedHandle( | |
| 415 reinterpret_cast<HANDLE>(handle_value_uint64))); | |
| 416 | |
| 417 event.Signal(); | |
| 418 | |
| 419 return 0; | |
| 420 } | |
| 421 | |
| 422 TEST_F(ProcessUtilTest, InheritSpecifiedHandles) { | |
| 423 // Manually create the event, so that it can be inheritable. | |
| 424 SECURITY_ATTRIBUTES security_attributes = {}; | |
| 425 security_attributes.nLength = static_cast<DWORD>(sizeof(security_attributes)); | |
| 426 security_attributes.lpSecurityDescriptor = NULL; | |
| 427 security_attributes.bInheritHandle = true; | |
| 428 | |
| 429 // Takes ownership of the event handle. | |
| 430 base::WaitableEvent event(base::win::ScopedHandle( | |
| 431 CreateEvent(&security_attributes, true, false, NULL))); | |
| 432 base::HandlesToInheritVector handles_to_inherit; | |
| 433 handles_to_inherit.push_back(event.handle()); | |
| 434 base::LaunchOptions options; | |
| 435 options.handles_to_inherit = &handles_to_inherit; | |
| 436 | |
| 437 base::CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess"); | |
| 438 cmd_line.AppendSwitchASCII(kEventToTriggerHandleSwitch, | |
| 439 base::Uint64ToString(reinterpret_cast<uint64>(event.handle()))); | |
| 440 | |
| 441 // This functionality actually requires Vista or later. Make sure that it | |
| 442 // fails properly on XP. | |
| 443 if (base::win::GetVersion() < base::win::VERSION_VISTA) { | |
| 444 EXPECT_FALSE(base::LaunchProcess(cmd_line, options).IsValid()); | |
| 445 return; | |
| 446 } | |
| 447 | |
| 448 // Launch the process and wait for it to trigger the event. | |
| 449 ASSERT_TRUE(base::LaunchProcess(cmd_line, options).IsValid()); | |
| 450 EXPECT_TRUE(event.TimedWait(TestTimeouts::action_max_timeout())); | |
| 451 } | |
| 452 #endif // defined(OS_WIN) | |
| 453 | |
| 454 #if defined(OS_POSIX) | 332 #if defined(OS_POSIX) |
| 455 | 333 |
| 456 namespace { | 334 namespace { |
| 457 | 335 |
| 458 // Returns the maximum number of files that a process can have open. | 336 // Returns the maximum number of files that a process can have open. |
| 459 // Returns 0 on error. | 337 // Returns 0 on error. |
| 460 int GetMaxFilesOpenInProcess() { | 338 int GetMaxFilesOpenInProcess() { |
| 461 struct rlimit rlim; | 339 struct rlimit rlim; |
| 462 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { | 340 if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) { |
| 463 return 0; | 341 return 0; |
| (...skipping 639 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1103 options.current_directory = base::FilePath("/dev/null"); | 981 options.current_directory = base::FilePath("/dev/null"); |
| 1104 | 982 |
| 1105 base::Process process(SpawnChildWithOptions("SimpleChildProcess", options)); | 983 base::Process process(SpawnChildWithOptions("SimpleChildProcess", options)); |
| 1106 ASSERT_TRUE(process.IsValid()); | 984 ASSERT_TRUE(process.IsValid()); |
| 1107 | 985 |
| 1108 int exit_code = kSuccess; | 986 int exit_code = kSuccess; |
| 1109 EXPECT_TRUE(process.WaitForExit(&exit_code)); | 987 EXPECT_TRUE(process.WaitForExit(&exit_code)); |
| 1110 EXPECT_NE(kSuccess, exit_code); | 988 EXPECT_NE(kSuccess, exit_code); |
| 1111 } | 989 } |
| 1112 #endif | 990 #endif |
| OLD | NEW |