| 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 #include "base/test/multiprocess_test.h" | 5 #include "base/test/multiprocess_test.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <string.h> | 8 #include <string.h> |
| 9 #include <sys/types.h> | 9 #include <sys/types.h> |
| 10 #include <sys/socket.h> | 10 #include <sys/socket.h> |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 // Starts a child test helper process. | 96 // Starts a child test helper process. |
| 97 Process StartChildTestHelper(const std::string& procname, | 97 Process StartChildTestHelper(const std::string& procname, |
| 98 const CommandLine& base_command_line, | 98 const CommandLine& base_command_line, |
| 99 const LaunchOptions& options); | 99 const LaunchOptions& options); |
| 100 | 100 |
| 101 // Waits for a child test helper process. | 101 // Waits for a child test helper process. |
| 102 bool WaitForChildExitWithTimeout(const Process& process, TimeDelta timeout, | 102 bool WaitForChildExitWithTimeout(const Process& process, TimeDelta timeout, |
| 103 int* exit_code); | 103 int* exit_code); |
| 104 | 104 |
| 105 bool IsReady() const { return child_fd_ != -1; } | 105 bool IsReady() const { return child_fd_ != -1; } |
| 106 bool IsChild() const { return parent_fd_ != -1; } | 106 bool IsChild() const { return is_child_; } |
| 107 | 107 |
| 108 private: | 108 private: |
| 109 // Wrappers around sendmsg/recvmsg that supports message fragmentation. | 109 // Wrappers around sendmsg/recvmsg that supports message fragmentation. |
| 110 void Send(int fd, const MessageHeader* msg, const std::vector<int>& fds); | 110 void Send(int fd, const MessageHeader* msg, const std::vector<int>& fds); |
| 111 ssize_t Recv(int fd, void* buf, std::vector<ScopedFD>* fds); | 111 ssize_t Recv(int fd, void* buf, std::vector<ScopedFD>* fds); |
| 112 | 112 |
| 113 // Parent process implementation. | 113 // Parent process implementation. |
| 114 void DoParent(int fd); | 114 void DoParent(int fd); |
| 115 // Helper process implementation. | 115 // Helper process implementation. |
| 116 void DoHelper(int fd); | 116 void DoHelper(int fd); |
| 117 | 117 |
| 118 void StartProcessInHelper(const StartProcessRequest* request, | 118 void StartProcessInHelper(const StartProcessRequest* request, |
| 119 std::vector<ScopedFD> fds); | 119 std::vector<ScopedFD> fds); |
| 120 void WaitForChildInHelper(const WaitProcessRequest* request); | 120 void WaitForChildInHelper(const WaitProcessRequest* request); |
| 121 | 121 |
| 122 bool is_child_ = false; |
| 123 |
| 122 // Parent vars. | 124 // Parent vars. |
| 123 int child_fd_ = -1; | 125 int child_fd_ = -1; |
| 124 | 126 |
| 125 // Helper vars. | 127 // Helper vars. |
| 126 int parent_fd_ = -1; | 128 int parent_fd_ = -1; |
| 127 MainFunction main_ = nullptr; | 129 MainFunction main_ = nullptr; |
| 128 | 130 |
| 129 DISALLOW_COPY_AND_ASSIGN(LaunchHelper); | 131 DISALLOW_COPY_AND_ASSIGN(LaunchHelper); |
| 130 }; | 132 }; |
| 131 | 133 |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 } | 199 } |
| 198 return header->size; | 200 return header->size; |
| 199 } | 201 } |
| 200 | 202 |
| 201 void LaunchHelper::DoParent(int fd) { | 203 void LaunchHelper::DoParent(int fd) { |
| 202 child_fd_ = fd; | 204 child_fd_ = fd; |
| 203 } | 205 } |
| 204 | 206 |
| 205 void LaunchHelper::DoHelper(int fd) { | 207 void LaunchHelper::DoHelper(int fd) { |
| 206 parent_fd_ = fd; | 208 parent_fd_ = fd; |
| 209 is_child_ = true; |
| 207 std::unique_ptr<char[]> buf(new char[kMaxMessageSize]); | 210 std::unique_ptr<char[]> buf(new char[kMaxMessageSize]); |
| 208 while (true) { | 211 while (true) { |
| 209 // Wait for a message from the parent. | 212 // Wait for a message from the parent. |
| 210 std::vector<ScopedFD> fds; | 213 std::vector<ScopedFD> fds; |
| 211 ssize_t size = Recv(parent_fd_, buf.get(), &fds); | 214 ssize_t size = Recv(parent_fd_, buf.get(), &fds); |
| 212 if (size == 0 || (size < 0 && errno == ECONNRESET)) { | 215 if (size == 0 || (size < 0 && errno == ECONNRESET)) { |
| 213 _exit(0); | 216 _exit(0); |
| 214 } | 217 } |
| 215 PCHECK(size > 0); | 218 PCHECK(size > 0); |
| 216 | 219 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 240 PCHECK(pid >= 0) << "Fork failed"; | 243 PCHECK(pid >= 0) << "Fork failed"; |
| 241 if (pid) { | 244 if (pid) { |
| 242 // Helper. | 245 // Helper. |
| 243 StartProcessResponse resp; | 246 StartProcessResponse resp; |
| 244 resp.child_pid = pid; | 247 resp.child_pid = pid; |
| 245 Send(parent_fd_, reinterpret_cast<const MessageHeader*>(&resp), | 248 Send(parent_fd_, reinterpret_cast<const MessageHeader*>(&resp), |
| 246 std::vector<int>()); | 249 std::vector<int>()); |
| 247 } else { | 250 } else { |
| 248 // Child. | 251 // Child. |
| 249 PCHECK(close(parent_fd_) == 0); | 252 PCHECK(close(parent_fd_) == 0); |
| 253 parent_fd_ = -1; |
| 250 CommandLine::Reset(); | 254 CommandLine::Reset(); |
| 251 | 255 |
| 252 Pickle serialised_extra(reinterpret_cast<const char*>(request + 1), | 256 Pickle serialised_extra(reinterpret_cast<const char*>(request + 1), |
| 253 request->header.size - sizeof(StartProcessRequest)); | 257 request->header.size - sizeof(StartProcessRequest)); |
| 254 PickleIterator iter(serialised_extra); | 258 PickleIterator iter(serialised_extra); |
| 255 std::vector<std::string> args; | 259 std::vector<std::string> args; |
| 256 for (size_t i = 0; i < request->num_args; i++) { | 260 for (size_t i = 0; i < request->num_args; i++) { |
| 257 std::string arg; | 261 std::string arg; |
| 258 CHECK(iter.ReadString(&arg)); | 262 CHECK(iter.ReadString(&arg)); |
| 259 args.push_back(std::move(arg)); | 263 args.push_back(std::move(arg)); |
| 260 } | 264 } |
| 261 | 265 |
| 262 CHECK_EQ(request->num_fds, fds.size()); | 266 CHECK_EQ(request->num_fds, fds.size()); |
| 263 for (size_t i = 0; i < request->num_fds; i++) { | 267 for (size_t i = 0; i < request->num_fds; i++) { |
| 264 int new_fd; | 268 int new_fd; |
| 265 CHECK(iter.ReadInt(&new_fd)); | 269 CHECK(iter.ReadInt(&new_fd)); |
| 266 int old_fd = fds[i].release(); | 270 int old_fd = fds[i].release(); |
| 267 if (dup2(old_fd, new_fd) < 0) { | 271 if (new_fd != old_fd) { |
| 268 PLOG(FATAL) << "dup2"; | 272 if (dup2(old_fd, new_fd) < 0) { |
| 273 PLOG(FATAL) << "dup2"; |
| 274 } |
| 275 PCHECK(close(old_fd) == 0); |
| 269 } | 276 } |
| 270 PCHECK(close(old_fd) == 0); | |
| 271 } | 277 } |
| 272 | 278 |
| 273 std::unique_ptr<char*[]> argv(new char*[args.size()]); | 279 std::unique_ptr<char*[]> argv(new char*[args.size()]); |
| 274 for (size_t i = 0; i < args.size(); i++) { | 280 for (size_t i = 0; i < args.size(); i++) { |
| 275 argv[i] = const_cast<char*>(args[i].c_str()); | 281 argv[i] = const_cast<char*>(args[i].c_str()); |
| 276 } | 282 } |
| 277 _exit(main_(args.size(), argv.get())); | 283 _exit(main_(args.size(), argv.get())); |
| 278 NOTREACHED(); | 284 NOTREACHED(); |
| 279 } | 285 } |
| 280 } | 286 } |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 } // namespace | 369 } // namespace |
| 364 | 370 |
| 365 void InitAndroidMultiProcessTestHelper(int (*main)(int, char**)) { | 371 void InitAndroidMultiProcessTestHelper(int (*main)(int, char**)) { |
| 366 DCHECK(main); | 372 DCHECK(main); |
| 367 // Don't allow child processes to themselves create new child processes. | 373 // Don't allow child processes to themselves create new child processes. |
| 368 if (g_launch_helper.Get().IsChild()) | 374 if (g_launch_helper.Get().IsChild()) |
| 369 return; | 375 return; |
| 370 g_launch_helper.Get().Init(main); | 376 g_launch_helper.Get().Init(main); |
| 371 } | 377 } |
| 372 | 378 |
| 379 bool AndroidIsChildProcess() { |
| 380 return g_launch_helper.Get().IsChild(); |
| 381 } |
| 382 |
| 373 bool AndroidWaitForChildExitWithTimeout( | 383 bool AndroidWaitForChildExitWithTimeout( |
| 374 const Process& process, TimeDelta timeout, int* exit_code) { | 384 const Process& process, TimeDelta timeout, int* exit_code) { |
| 375 CHECK(g_launch_helper.Get().IsReady()); | 385 CHECK(g_launch_helper.Get().IsReady()); |
| 376 return g_launch_helper.Get().WaitForChildExitWithTimeout( | 386 return g_launch_helper.Get().WaitForChildExitWithTimeout( |
| 377 process, timeout, exit_code); | 387 process, timeout, exit_code); |
| 378 } | 388 } |
| 379 | 389 |
| 380 // A very basic implementation for Android. On Android tests can run in an APK | 390 // A very basic implementation for Android. On Android tests can run in an APK |
| 381 // and we don't have an executable to exec*. This implementation does the bare | 391 // and we don't have an executable to exec*. This implementation does the bare |
| 382 // minimum to execute the method specified by procname (in the child process). | 392 // minimum to execute the method specified by procname (in the child process). |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 443 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 434 command_line->InitFromArgv(base_command_line.argv()); | 444 command_line->InitFromArgv(base_command_line.argv()); |
| 435 if (!command_line->HasSwitch(switches::kTestChildProcess)) | 445 if (!command_line->HasSwitch(switches::kTestChildProcess)) |
| 436 command_line->AppendSwitchASCII(switches::kTestChildProcess, procname); | 446 command_line->AppendSwitchASCII(switches::kTestChildProcess, procname); |
| 437 | 447 |
| 438 _exit(multi_process_function_list::InvokeChildProcessTest(procname)); | 448 _exit(multi_process_function_list::InvokeChildProcessTest(procname)); |
| 439 return Process(); | 449 return Process(); |
| 440 } | 450 } |
| 441 | 451 |
| 442 } // namespace base | 452 } // namespace base |
| OLD | NEW |