| Index: content/shell/browser/layout_test/scoped_android_configuration.cc
|
| diff --git a/content/shell/browser/layout_test/scoped_android_configuration.cc b/content/shell/browser/layout_test/scoped_android_configuration.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1cdb4d5c185bf9776a939c56752baa52813dcd9a
|
| --- /dev/null
|
| +++ b/content/shell/browser/layout_test/scoped_android_configuration.cc
|
| @@ -0,0 +1,191 @@
|
| +// Copyright 2016 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "content/shell/browser/layout_test/scoped_android_configuration.h"
|
| +
|
| +#include <fcntl.h>
|
| +#include <iostream>
|
| +#include <memory>
|
| +
|
| +#include "base/android/context_utils.h"
|
| +#include "base/android/jni_android.h"
|
| +#include "base/android/jni_string.h"
|
| +#include "base/command_line.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/test/test_support_android.h"
|
| +#include "content/public/browser/browser_thread.h"
|
| +#include "content/public/test/nested_message_pump_android.h"
|
| +#include "content/shell/browser/layout_test/blink_test_controller.h"
|
| +#include "content/shell/common/layout_test/layout_test_switches.h"
|
| +#include "content/shell/common/shell_switches.h"
|
| +#include "jni/ShellLayoutTestUtils_jni.h"
|
| +#include "net/base/ip_address.h"
|
| +#include "net/base/ip_endpoint.h"
|
| +#include "net/base/net_errors.h"
|
| +#include "net/base/sockaddr_storage.h"
|
| +#include "net/socket/socket_posix.h"
|
| +#include "url/gurl.h"
|
| +
|
| +using base::android::ScopedJavaLocalRef;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +std::unique_ptr<base::MessagePump> CreateMessagePumpForUI() {
|
| + return std::unique_ptr<base::MessagePump>(new NestedMessagePumpAndroid());
|
| +}
|
| +
|
| +void ConnectCompleted(const base::Closure& socket_connected, int rv) {
|
| + LOG_IF(FATAL, net::OK != rv) << " Failed to redirect to socket: "
|
| + << net::ErrorToString(rv);
|
| + socket_connected.Run();
|
| +}
|
| +
|
| +void CreateAndConnectSocket(
|
| + uint16_t port,
|
| + const base::Callback<void(std::unique_ptr<net::SocketPosix>)>&
|
| + socket_connected) {
|
| + net::SockaddrStorage storage;
|
| + net::IPAddress address;
|
| + LOG_IF(FATAL, !address.AssignFromIPLiteral("127.0.0.1"))
|
| + << "Failed to create IPAddress from IP literal 127.0.0.1.";
|
| + net::IPEndPoint endpoint(address, port);
|
| + LOG_IF(FATAL, !endpoint.ToSockAddr(storage.addr, &storage.addr_len))
|
| + << "Failed to convert " << endpoint.ToString() << " to sockaddr.";
|
| +
|
| + std::unique_ptr<net::SocketPosix> socket(
|
| + base::MakeUnique<net::SocketPosix>());
|
| +
|
| + int result = socket->Open(AF_INET);
|
| + LOG_IF(FATAL, net::OK != result) << "Failed to open socket for "
|
| + << endpoint.ToString() << ": "
|
| + << net::ErrorToString(result);
|
| +
|
| + // Set the socket as blocking.
|
| + const int flags = fcntl(socket->socket_fd(), F_GETFL);
|
| + LOG_IF(FATAL, flags == -1);
|
| + if (flags & O_NONBLOCK) {
|
| + fcntl(socket->socket_fd(), F_SETFL, flags & ~O_NONBLOCK);
|
| + }
|
| +
|
| + net::SocketPosix* socket_ptr = socket.get();
|
| + net::CompletionCallback connect_completed =
|
| + base::Bind(&ConnectCompleted,
|
| + base::Bind(socket_connected, base::Passed(std::move(socket))));
|
| + result = socket_ptr->Connect(storage, connect_completed);
|
| + if (result != net::ERR_IO_PENDING) {
|
| + connect_completed.Run(result);
|
| + }
|
| +}
|
| +
|
| +void RedirectStdout(int fd) {
|
| + LOG_IF(FATAL, dup2(fd, STDOUT_FILENO) == -1) << "Failed to dup2 stdout: "
|
| + << strerror(errno);
|
| +}
|
| +
|
| +void RedirectStdin(int fd) {
|
| + LOG_IF(FATAL, dup2(fd, STDIN_FILENO) == -1) << "Failed to dup2 stdin: "
|
| + << strerror(errno);
|
| +}
|
| +
|
| +void RedirectStderr(int fd) {
|
| + LOG_IF(FATAL, dup2(fd, STDERR_FILENO) == -1) << "Failed to dup2 stderr: "
|
| + << strerror(errno);
|
| +}
|
| +
|
| +void FinishRedirection(
|
| + const base::Callback<void(int)>& redirect,
|
| + const base::Callback<void(std::unique_ptr<net::SocketPosix>)>&
|
| + transfer_socket,
|
| + base::WaitableEvent* event,
|
| + std::unique_ptr<net::SocketPosix> socket) {
|
| + redirect.Run(socket->socket_fd());
|
| + transfer_socket.Run(std::move(socket));
|
| + event->Signal();
|
| +}
|
| +
|
| +void RedirectStream(
|
| + uint16_t port,
|
| + const base::Callback<void(base::WaitableEvent*,
|
| + std::unique_ptr<net::SocketPosix>)>&
|
| + finish_redirection) {
|
| + base::WaitableEvent redirected(
|
| + base::WaitableEvent::ResetPolicy::MANUAL,
|
| + base::WaitableEvent::InitialState::NOT_SIGNALED);
|
| + BrowserThread::PostTask(
|
| + BrowserThread::IO, FROM_HERE,
|
| + base::Bind(&CreateAndConnectSocket, port,
|
| + base::Bind(finish_redirection, &redirected)));
|
| + ScopedAllowWaitForAndroidLayoutTests allow_wait;
|
| + while (!redirected.IsSignaled())
|
| + redirected.Wait();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +ScopedAndroidConfiguration::ScopedAndroidConfiguration() : sockets_() {
|
| + JNIEnv* env = base::android::AttachCurrentThread();
|
| + ScopedJavaLocalRef<jstring> jtest_data_dir =
|
| + Java_ShellLayoutTestUtils_getIsolatedTestRoot(env);
|
| + base::FilePath test_data_dir(
|
| + base::android::ConvertJavaStringToUTF8(env, jtest_data_dir));
|
| + base::InitAndroidTestPaths(test_data_dir);
|
| +
|
| + bool success =
|
| + base::MessageLoop::InitMessagePumpForUIFactory(&CreateMessagePumpForUI);
|
| + LOG_IF(FATAL, !success)
|
| + << "Unable to initialize the message pump for Android.";
|
| +}
|
| +
|
| +ScopedAndroidConfiguration::~ScopedAndroidConfiguration() = default;
|
| +
|
| +void ScopedAndroidConfiguration::RedirectStreams() {
|
| + // Unretained is safe here because all executions of add_socket finish
|
| + // before this function returns.
|
| + base::Callback<void(std::unique_ptr<net::SocketPosix>)> add_socket =
|
| + base::Bind(&ScopedAndroidConfiguration::AddSocket,
|
| + base::Unretained(this));
|
| +
|
| + std::string stdout_port_str =
|
| + base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
|
| + switches::kAndroidStdoutPort);
|
| + unsigned stdout_port = 0;
|
| + if (base::StringToUint(stdout_port_str, &stdout_port)) {
|
| + RedirectStream(base::checked_cast<uint16_t>(stdout_port),
|
| + base::Bind(&FinishRedirection, base::Bind(&RedirectStdout),
|
| + add_socket));
|
| + }
|
| +
|
| + std::string stdin_port_str =
|
| + base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
|
| + switches::kAndroidStdinPort);
|
| + unsigned stdin_port = 0;
|
| + if (base::StringToUint(stdin_port_str, &stdin_port)) {
|
| + RedirectStream(
|
| + base::checked_cast<uint16_t>(stdin_port),
|
| + base::Bind(&FinishRedirection, base::Bind(&RedirectStdin), add_socket));
|
| + }
|
| +
|
| + std::string stderr_port_str =
|
| + base::CommandLine::ForCurrentProcess()->GetSwitchValueNative(
|
| + switches::kAndroidStderrPort);
|
| + unsigned stderr_port = 0;
|
| + if (base::StringToUint(stderr_port_str, &stderr_port)) {
|
| + RedirectStream(base::checked_cast<uint16_t>(stderr_port),
|
| + base::Bind(&FinishRedirection, base::Bind(&RedirectStderr),
|
| + add_socket));
|
| + }
|
| +}
|
| +
|
| +void ScopedAndroidConfiguration::AddSocket(
|
| + std::unique_ptr<net::SocketPosix> socket) {
|
| + sockets_.push_back(std::move(socket));
|
| +}
|
| +
|
| +} // namespace content
|
|
|