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/test/multiprocess_test.h"
6
7#include <unistd.h>
8
9#include "base/containers/hash_tables.h"
10#include "base/logging.h"
11#include "testing/multiprocess_func_list.h"
12
13namespace base {
14
15// A very basic implementation for Android. On Android tests can run in an APK
16// and we don't have an executable to exec*. This implementation does the bare
17// minimum to execute the method specified by procname (in the child process).
18//  - All options except |fds_to_remap| are ignored.
19//  - |debug_on_start| is ignored.
20ProcessHandle MultiProcessTest::SpawnChildWithOptions(
21    const std::string& procname,
22    const LaunchOptions& options,
23    bool debug_on_start) {
24  // TODO(vtl): The FD-remapping done below is wrong in the presence of cycles
25  // (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 stdin, stdout and stderr open since this is not meant to spawn a
47  // daemon.
48  const int kFdForAndroidLogging = 3;  // FD used by __android_log_write().
49  for (int fd = kFdForAndroidLogging + 1; fd < getdtablesize(); ++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