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

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

Powered by Google App Engine
This is Rietveld 408576698