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 |