Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: content/shell/browser/layout_test/scoped_android_configuration.cc

Issue 2540603004: [Android] Redirect std{in,out,err} to sockets for layout tests. (Closed)
Patch Set: rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 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 "content/shell/browser/layout_test/scoped_android_configuration.h"
6
7 #include <fcntl.h>
8 #include <iostream>
9 #include <memory>
10
11 #include "base/android/context_utils.h"
12 #include "base/android/jni_android.h"
13 #include "base/android/jni_string.h"
14 #include "base/command_line.h"
15 #include "base/files/file_path.h"
16 #include "base/memory/ptr_util.h"
17 #include "base/message_loop/message_loop.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/synchronization/waitable_event.h"
20 #include "base/test/test_support_android.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/test/nested_message_pump_android.h"
23 #include "content/shell/browser/layout_test/blink_test_controller.h"
24 #include "content/shell/common/layout_test/layout_test_switches.h"
25 #include "content/shell/common/shell_switches.h"
26 #include "jni/ShellLayoutTestUtils_jni.h"
27 #include "net/base/ip_address.h"
28 #include "net/base/ip_endpoint.h"
29 #include "net/base/net_errors.h"
30 #include "net/base/sockaddr_storage.h"
31 #include "net/socket/socket_posix.h"
32 #include "url/gurl.h"
33
34 using base::android::ScopedJavaLocalRef;
35
36 namespace content {
37
38 namespace {
39
40 std::unique_ptr<base::MessagePump> CreateMessagePumpForUI() {
41 return std::unique_ptr<base::MessagePump>(new NestedMessagePumpAndroid());
42 }
43
44 void ConnectCompleted(const base::Closure& socket_connected, int rv) {
45 LOG_IF(FATAL, net::OK != rv) << " Failed to redirect to socket: "
46 << net::ErrorToString(rv);
47 socket_connected.Run();
48 }
49
50 void CreateAndConnectSocket(
51 uint16_t port,
52 const base::Callback<void(std::unique_ptr<net::SocketPosix>)>&
53 socket_connected) {
54 net::SockaddrStorage storage;
55 net::IPAddress address;
56 LOG_IF(FATAL, !address.AssignFromIPLiteral("127.0.0.1"))
57 << "Failed to create IPAddress from IP literal 127.0.0.1.";
58 net::IPEndPoint endpoint(address, port);
59 LOG_IF(FATAL, !endpoint.ToSockAddr(storage.addr, &storage.addr_len))
60 << "Failed to convert " << endpoint.ToString() << " to sockaddr.";
61
62 std::unique_ptr<net::SocketPosix> socket(
63 base::MakeUnique<net::SocketPosix>());
64
65 int result = socket->Open(AF_INET);
66 LOG_IF(FATAL, net::OK != result) << "Failed to open socket for "
67 << endpoint.ToString() << ": "
68 << net::ErrorToString(result);
69
70 // Set the socket as blocking.
71 const int flags = fcntl(socket->socket_fd(), F_GETFL);
72 LOG_IF(FATAL, flags == -1);
73 if (flags & O_NONBLOCK) {
74 fcntl(socket->socket_fd(), F_SETFL, flags & ~O_NONBLOCK);
75 }
76
77 net::SocketPosix* socket_ptr = socket.get();
78 net::CompletionCallback connect_completed =
79 base::Bind(&ConnectCompleted,
80 base::Bind(socket_connected, base::Passed(std::move(socket))));
81 result = socket_ptr->Connect(storage, connect_completed);
82 if (result != net::ERR_IO_PENDING) {
83 connect_completed.Run(result);
84 }
85 }
86
87 void RedirectStdout(int fd) {
88 LOG_IF(FATAL, dup2(fd, STDOUT_FILENO) == -1) << "Failed to dup2 stdout: "
89 << strerror(errno);
90 }
91
92 void RedirectStdin(int fd) {
93 LOG_IF(FATAL, dup2(fd, STDIN_FILENO) == -1) << "Failed to dup2 stdin: "
94 << strerror(errno);
95 }
96
97 void RedirectStderr(int fd) {
98 LOG_IF(FATAL, dup2(fd, STDERR_FILENO) == -1) << "Failed to dup2 stderr: "
99 << strerror(errno);
100 }
101
102 void FinishRedirection(
103 const base::Callback<void(int)>& redirect,
104 const base::Callback<void(std::unique_ptr<net::SocketPosix>)>&
105 transfer_socket,
106 base::WaitableEvent* event,
107 std::unique_ptr<net::SocketPosix> socket) {
108 redirect.Run(socket->socket_fd());
109 transfer_socket.Run(std::move(socket));
110 event->Signal();
111 }
112
113 void RedirectStream(
114 uint16_t port,
115 const base::Callback<void(base::WaitableEvent*,
116 std::unique_ptr<net::SocketPosix>)>&
117 finish_redirection) {
118 base::WaitableEvent redirected(
119 base::WaitableEvent::ResetPolicy::MANUAL,
120 base::WaitableEvent::InitialState::NOT_SIGNALED);
121 BrowserThread::PostTask(
122 BrowserThread::IO, FROM_HERE,
123 base::Bind(&CreateAndConnectSocket, port,
124 base::Bind(finish_redirection, &redirected)));
125 ScopedAllowWaitForAndroidLayoutTests allow_wait;
126 while (!redirected.IsSignaled())
127 redirected.Wait();
128 }
129
130 } // namespace
131
132 ScopedAndroidConfiguration::ScopedAndroidConfiguration() : sockets_() {
133 JNIEnv* env = base::android::AttachCurrentThread();
134 ScopedJavaLocalRef<jstring> jtest_data_dir =
135 Java_ShellLayoutTestUtils_getIsolatedTestRoot(env);
136 base::FilePath test_data_dir(
137 base::android::ConvertJavaStringToUTF8(env, jtest_data_dir));
138 base::InitAndroidTestPaths(test_data_dir);
139
140 bool success =
141 base::MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUI);
142 LOG_IF(FATAL, !success)
143 << "Unable to initialize the message pump for Android.";
144 }
145
146 ScopedAndroidConfiguration::~ScopedAndroidConfiguration() = default;
147
148 void ScopedAndroidConfiguration::RedirectStreams() {
149 // Unretained is safe here because all executions of add_socket finish
150 // before this function returns.
151 base::Callback<void(std::unique_ptr<net::SocketPosix>)> add_socket =
152 base::Bind(&ScopedAndroidConfiguration::AddSocket,
153 base::Unretained(this));
154
155 std::string stdout_port_str =
156 base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
157 switches::kAndroidStdoutPort);
158 unsigned stdout_port = 0;
159 if (base::StringToUint(stdout_port_str, &stdout_port)) {
160 RedirectStream(base::checked_cast<uint16_t>(stdout_port),
161 base::Bind(&FinishRedirection, base::Bind(&RedirectStdout),
162 add_socket));
163 }
164
165 std::string stdin_port_str =
166 base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
167 switches::kAndroidStdinPort);
168 unsigned stdin_port = 0;
169 if (base::StringToUint(stdin_port_str, &stdin_port)) {
170 RedirectStream(
171 base::checked_cast<uint16_t>(stdin_port),
172 base::Bind(&FinishRedirection, base::Bind(&RedirectStdin), add_socket));
173 }
174
175 std::string stderr_port_str =
176 base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
177 switches::kAndroidStderrPort);
178 unsigned stderr_port = 0;
179 if (base::StringToUint(stderr_port_str, &stderr_port)) {
180 RedirectStream(base::checked_cast<uint16_t>(stderr_port),
181 base::Bind(&FinishRedirection, base::Bind(&RedirectStderr),
182 add_socket));
183 }
184 }
185
186 void ScopedAndroidConfiguration::AddSocket(
187 std::unique_ptr<net::SocketPosix> socket) {
188 sockets_.push_back(std::move(socket));
189 }
190
191 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698