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
3// found in the LICENSE file.
4
5#include "base/posix/global_descriptors.h"
6#include "base/test/multiprocess_test.h"
7
8#include <unistd.h>
9
10#include "base/containers/hash_tables.h"
11#include "base/logging.h"
12#include "testing/multiprocess_func_list.h"
13
14namespace base {
15
16// A very basic implementation for Android. On Android tests can run in an APK
17// and we don't have an executable to exec*. This implementation does the bare
18// minimum to execute the method specified by procname (in the child process).
19//  - |base_command_line| is ignored.
20//  - All options except |fds_to_remap| are ignored.
21ProcessHandle SpawnMultiProcessTestChild(const std::string& procname,
22                                         const CommandLine& base_command_line,
23                                         const LaunchOptions& options) {
24  // TODO(viettrungluu): The FD-remapping done below is wrong in the presence of
25  // cycles (e.g., fd1 -> fd2, fd2 -> fd1). crbug.com/326576
26  FileHandleMappingVector empty;
27  const FileHandleMappingVector* fds_to_remap =
28      options.fds_to_remap ? options.fds_to_remap : &empty;
29
30  pid_t pid = fork();
31
32  if (pid < 0) {
33    PLOG(ERROR) << "fork";
34    return kNullProcessHandle;
35  }
36  if (pid > 0) {
37    // Parent process.
38    return pid;
39  }
40  // Child process.
41  std::hash_set<int> fds_to_keep_open;
42  for (FileHandleMappingVector::const_iterator it = fds_to_remap->begin();
43       it != fds_to_remap->end(); ++it) {
44    fds_to_keep_open.insert(it->first);
45  }
46  // Keep standard FDs (stdin, stdout, stderr, etc.) open since this
47  // is not meant to spawn a daemon.
48  int base = GlobalDescriptors::kBaseDescriptor;
49  for (int fd = base; fd < sysconf(_SC_OPEN_MAX); ++fd) {
50    if (fds_to_keep_open.find(fd) == fds_to_keep_open.end()) {
51      close(fd);
52    }
53  }
54  for (FileHandleMappingVector::const_iterator it = fds_to_remap->begin();
55       it != fds_to_remap->end(); ++it) {
56    int old_fd = it->first;
57    int new_fd = it->second;
58    if (dup2(old_fd, new_fd) < 0) {
59      PLOG(FATAL) << "dup2";
60    }
61    close(old_fd);
62  }
63  _exit(multi_process_function_list::InvokeChildProcessTest(procname));
64  return 0;
65}
66
67}  // namespace base
68