Merge changes from topic 'adb_cherrypick' into nyc-dev
* changes: adb: sysdeps_test: improve smoke test. adb: check for an error response from adbd between each write. adbd: restore the old error handling behavior. adb: change unsigned to uint32_t in sync struct definitions. adb: detect when the client disconnects in wait-for-device. adb: make fdevent_test, socket_test compile on Windows. adb: add fd exhaustion test, fix errno reporting in sysdeps_win32. adb: move win32 fd base to 2048, fix fd allocation. adb: don't emulate fdevent or socketpair on Windows. adb: fix clang-format for access modifier dedent. Add missing liblog dependency adb: sysdeps_win32: actually change ExitThread to _endthreadex. adb: make adb_thread_func_t return void, add adb_thread_exit. adb: redact reference to secret internal time machine. adb: mkdirs fixes adb: sysdeps: add support for joining threads. adb: allow wine's output for sysdeps_win32 strerror test. adb: setsid() for adb host server. adb: make ctrl-c when spawning a daemon not kill the daemon. adb: fix mkdirs test.
This commit is contained in:
commit
7b84c9bf93
28 changed files with 945 additions and 1788 deletions
|
|
@ -2,6 +2,7 @@ BasedOnStyle: Google
|
|||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
|
||||
AccessModifierOffset: -2
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: NOLINT:.*
|
||||
DerivePointerAlignment: false
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ LIBADB_SRC_FILES := \
|
|||
adb_listeners.cpp \
|
||||
adb_trace.cpp \
|
||||
adb_utils.cpp \
|
||||
fdevent.cpp \
|
||||
sockets.cpp \
|
||||
transport.cpp \
|
||||
transport_local.cpp \
|
||||
|
|
@ -58,6 +59,9 @@ LIBADB_SRC_FILES := \
|
|||
LIBADB_TEST_SRCS := \
|
||||
adb_io_test.cpp \
|
||||
adb_utils_test.cpp \
|
||||
fdevent_test.cpp \
|
||||
socket_test.cpp \
|
||||
sysdeps_test.cpp \
|
||||
transport_test.cpp \
|
||||
|
||||
LIBADB_CFLAGS := \
|
||||
|
|
@ -74,12 +78,10 @@ LIBADB_windows_CFLAGS := \
|
|||
$(ADB_COMMON_windows_CFLAGS) \
|
||||
|
||||
LIBADB_darwin_SRC_FILES := \
|
||||
fdevent.cpp \
|
||||
get_my_path_darwin.cpp \
|
||||
usb_osx.cpp \
|
||||
|
||||
LIBADB_linux_SRC_FILES := \
|
||||
fdevent.cpp \
|
||||
get_my_path_linux.cpp \
|
||||
usb_linux.cpp \
|
||||
|
||||
|
|
@ -87,14 +89,6 @@ LIBADB_windows_SRC_FILES := \
|
|||
sysdeps_win32.cpp \
|
||||
usb_windows.cpp \
|
||||
|
||||
LIBADB_TEST_linux_SRCS := \
|
||||
fdevent_test.cpp \
|
||||
socket_test.cpp \
|
||||
|
||||
LIBADB_TEST_darwin_SRCS := \
|
||||
fdevent_test.cpp \
|
||||
socket_test.cpp \
|
||||
|
||||
LIBADB_TEST_windows_SRCS := \
|
||||
sysdeps_win32_test.cpp \
|
||||
|
||||
|
|
@ -157,7 +151,7 @@ LOCAL_SRC_FILES := \
|
|||
|
||||
LOCAL_SANITIZE := $(adb_target_sanitize)
|
||||
LOCAL_STATIC_LIBRARIES := libadbd
|
||||
LOCAL_SHARED_LIBRARIES := libbase libcutils
|
||||
LOCAL_SHARED_LIBRARIES := liblog libbase libcutils
|
||||
include $(BUILD_NATIVE_TEST)
|
||||
|
||||
# libdiagnose_usb
|
||||
|
|
|
|||
|
|
@ -883,8 +883,6 @@ int launch_server(int server_port)
|
|||
fprintf(stderr, "ADB server didn't ACK\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
setsid();
|
||||
}
|
||||
#endif /* !defined(_WIN32) */
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ std::string adb_dirname(const std::string& path) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// Given a relative or absolute filepath, create the parent directory hierarchy
|
||||
// Given a relative or absolute filepath, create the directory hierarchy
|
||||
// as needed. Returns true if the hierarchy is/was setup.
|
||||
bool mkdirs(const std::string& path) {
|
||||
// TODO: all the callers do unlink && mkdirs && adb_creat ---
|
||||
|
|
@ -157,12 +157,12 @@ bool mkdirs(const std::string& path) {
|
|||
return true;
|
||||
}
|
||||
|
||||
const std::string parent(adb_dirname(path));
|
||||
|
||||
// If dirname returned the same path as what we passed in, don't go recursive.
|
||||
// This can happen on Windows when walking up the directory hierarchy and not
|
||||
// finding anything that already exists (unlike POSIX that will eventually
|
||||
// find . or /).
|
||||
const std::string parent(adb_dirname(path));
|
||||
|
||||
if (parent == path) {
|
||||
errno = ENOENT;
|
||||
return false;
|
||||
|
|
@ -174,14 +174,14 @@ bool mkdirs(const std::string& path) {
|
|||
}
|
||||
|
||||
// Now that the parent directory hierarchy of 'path' has been ensured,
|
||||
// create parent itself.
|
||||
// create path itself.
|
||||
if (adb_mkdir(path, 0775) == -1) {
|
||||
// Can't just check for errno == EEXIST because it might be a file that
|
||||
// exists.
|
||||
const int saved_errno = errno;
|
||||
if (directory_exists(parent)) {
|
||||
// If someone else created the directory, that is ok.
|
||||
if (directory_exists(path)) {
|
||||
return true;
|
||||
}
|
||||
// There might be a pre-existing file at 'path', or there might have been some other error.
|
||||
errno = saved_errno;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -213,6 +213,7 @@ std::string perror_str(const char* msg) {
|
|||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
// Windows version provided in sysdeps_win32.cpp
|
||||
bool set_file_block_mode(int fd, bool block) {
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
|
|
|
|||
|
|
@ -112,20 +112,26 @@ TEST(adb_utils, adb_dirname) {
|
|||
}
|
||||
|
||||
void test_mkdirs(const std::string basepath) {
|
||||
// Test creating a directory hierarchy.
|
||||
EXPECT_TRUE(mkdirs(basepath));
|
||||
EXPECT_NE(-1, adb_creat(basepath.c_str(), 0600));
|
||||
EXPECT_FALSE(mkdirs(basepath + "/subdir/"));
|
||||
// Test finding an existing directory hierarchy.
|
||||
EXPECT_TRUE(mkdirs(basepath));
|
||||
const std::string filepath = basepath + "/file";
|
||||
// Verify that the hierarchy was created by trying to create a file in it.
|
||||
EXPECT_NE(-1, adb_creat(filepath.c_str(), 0600));
|
||||
// If a file exists where we want a directory, the operation should fail.
|
||||
EXPECT_FALSE(mkdirs(filepath));
|
||||
}
|
||||
|
||||
TEST(adb_utils, mkdirs) {
|
||||
TemporaryDir td;
|
||||
|
||||
// Absolute paths.
|
||||
test_mkdirs(std::string(td.path) + "/dir/subdir/file");
|
||||
test_mkdirs(std::string(td.path) + "/dir/subdir");
|
||||
|
||||
// Relative paths.
|
||||
ASSERT_EQ(0, chdir(td.path)) << strerror(errno);
|
||||
test_mkdirs(std::string("relative/subrel/file"));
|
||||
test_mkdirs(std::string("relative/subrel"));
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// We only build the affinity WAR code for Linux.
|
||||
#if defined(__linux__)
|
||||
|
|
@ -125,6 +126,15 @@ int adb_server_main(int is_daemon, int server_port, int ack_reply_fd) {
|
|||
close_stdin();
|
||||
setup_daemon_logging();
|
||||
|
||||
#if !defined(_WIN32)
|
||||
// Start a new session for the daemon. Do this here instead of after the fork so
|
||||
// that a ctrl-c between the "starting server" and "done starting server" messages
|
||||
// gets a chance to terminate the server.
|
||||
if (setsid() == -1) {
|
||||
fatal("setsid() failed: %s", strerror(errno));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Any error output written to stderr now goes to adb.log. We could
|
||||
// keep around a copy of the stderr fd and use that to write any errors
|
||||
// encountered by the following code, but that is probably overkill.
|
||||
|
|
|
|||
|
|
@ -482,7 +482,7 @@ struct StdinReadArgs {
|
|||
// Loops to read from stdin and push the data to the given FD.
|
||||
// The argument should be a pointer to a StdinReadArgs object. This function
|
||||
// will take ownership of the object and delete it when finished.
|
||||
static void* stdin_read_thread_loop(void* x) {
|
||||
static void stdin_read_thread_loop(void* x) {
|
||||
std::unique_ptr<StdinReadArgs> args(reinterpret_cast<StdinReadArgs*>(x));
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
|
@ -586,8 +586,6 @@ static void* stdin_read_thread_loop(void* x) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Returns a shell service string with the indicated arguments and command.
|
||||
|
|
|
|||
|
|
@ -21,12 +21,11 @@
|
|||
#include "fdevent.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
|
@ -54,7 +53,7 @@ int SHELL_EXIT_NOTIFY_FD = -1;
|
|||
|
||||
struct PollNode {
|
||||
fdevent* fde;
|
||||
::pollfd pollfd;
|
||||
adb_pollfd pollfd;
|
||||
|
||||
PollNode(fdevent* fde) : fde(fde) {
|
||||
memset(&pollfd, 0, sizeof(pollfd));
|
||||
|
|
@ -72,18 +71,19 @@ struct PollNode {
|
|||
// That's why we don't need a lock for fdevent.
|
||||
static auto& g_poll_node_map = *new std::unordered_map<int, PollNode>();
|
||||
static auto& g_pending_list = *new std::list<fdevent*>();
|
||||
static std::atomic<bool> terminate_loop(false);
|
||||
static bool main_thread_valid;
|
||||
static pthread_t main_thread;
|
||||
static unsigned long main_thread_id;
|
||||
|
||||
static void check_main_thread() {
|
||||
if (main_thread_valid) {
|
||||
CHECK_NE(0, pthread_equal(main_thread, pthread_self()));
|
||||
CHECK_EQ(main_thread_id, adb_thread_id());
|
||||
}
|
||||
}
|
||||
|
||||
static void set_main_thread() {
|
||||
main_thread_valid = true;
|
||||
main_thread = pthread_self();
|
||||
main_thread_id = adb_thread_id();
|
||||
}
|
||||
|
||||
static std::string dump_fde(const fdevent* fde) {
|
||||
|
|
@ -217,7 +217,7 @@ void fdevent_del(fdevent* fde, unsigned events) {
|
|||
fdevent_set(fde, (fde->state & FDE_EVENTMASK) & ~events);
|
||||
}
|
||||
|
||||
static std::string dump_pollfds(const std::vector<pollfd>& pollfds) {
|
||||
static std::string dump_pollfds(const std::vector<adb_pollfd>& pollfds) {
|
||||
std::string result;
|
||||
for (const auto& pollfd : pollfds) {
|
||||
std::string op;
|
||||
|
|
@ -233,13 +233,13 @@ static std::string dump_pollfds(const std::vector<pollfd>& pollfds) {
|
|||
}
|
||||
|
||||
static void fdevent_process() {
|
||||
std::vector<pollfd> pollfds;
|
||||
std::vector<adb_pollfd> pollfds;
|
||||
for (const auto& pair : g_poll_node_map) {
|
||||
pollfds.push_back(pair.second.pollfd);
|
||||
}
|
||||
CHECK_GT(pollfds.size(), 0u);
|
||||
D("poll(), pollfds = %s", dump_pollfds(pollfds).c_str());
|
||||
int ret = TEMP_FAILURE_RETRY(poll(&pollfds[0], pollfds.size(), -1));
|
||||
int ret = adb_poll(&pollfds[0], pollfds.size(), -1);
|
||||
if (ret == -1) {
|
||||
PLOG(ERROR) << "poll(), ret = " << ret;
|
||||
return;
|
||||
|
|
@ -289,6 +289,9 @@ static void fdevent_call_fdfunc(fdevent* fde)
|
|||
}
|
||||
|
||||
#if !ADB_HOST
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
static void fdevent_subproc_event_func(int fd, unsigned ev,
|
||||
void* /* userdata */)
|
||||
{
|
||||
|
|
@ -363,6 +366,10 @@ void fdevent_loop()
|
|||
#endif // !ADB_HOST
|
||||
|
||||
while (true) {
|
||||
if (terminate_loop) {
|
||||
return;
|
||||
}
|
||||
|
||||
D("--- --- waiting for events");
|
||||
|
||||
fdevent_process();
|
||||
|
|
@ -375,6 +382,10 @@ void fdevent_loop()
|
|||
}
|
||||
}
|
||||
|
||||
void fdevent_terminate_loop() {
|
||||
terminate_loop = true;
|
||||
}
|
||||
|
||||
size_t fdevent_installed_count() {
|
||||
return g_poll_node_map.size();
|
||||
}
|
||||
|
|
@ -383,4 +394,5 @@ void fdevent_reset() {
|
|||
g_poll_node_map.clear();
|
||||
g_pending_list.clear();
|
||||
main_thread_valid = false;
|
||||
terminate_loop = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,9 +76,9 @@ void fdevent_set_timeout(fdevent *fde, int64_t timeout_ms);
|
|||
*/
|
||||
void fdevent_loop();
|
||||
|
||||
// For debugging only.
|
||||
// The following functions are used only for tests.
|
||||
void fdevent_terminate_loop();
|
||||
size_t fdevent_installed_count();
|
||||
// For debugging only.
|
||||
void fdevent_reset();
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -18,15 +18,13 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "adb_io.h"
|
||||
#include "fdevent_test.h"
|
||||
|
||||
class FdHandler {
|
||||
public:
|
||||
|
|
@ -48,7 +46,7 @@ class FdHandler {
|
|||
if (events & FDE_READ) {
|
||||
ASSERT_EQ(fd, handler->read_fd_);
|
||||
char c;
|
||||
ASSERT_EQ(1, read(fd, &c, 1));
|
||||
ASSERT_EQ(1, adb_read(fd, &c, 1));
|
||||
handler->queue_.push(c);
|
||||
fdevent_add(&handler->write_fde_, FDE_WRITE);
|
||||
}
|
||||
|
|
@ -57,7 +55,7 @@ class FdHandler {
|
|||
ASSERT_FALSE(handler->queue_.empty());
|
||||
char c = handler->queue_.front();
|
||||
handler->queue_.pop();
|
||||
ASSERT_EQ(1, write(fd, &c, 1));
|
||||
ASSERT_EQ(1, adb_write(fd, &c, 1));
|
||||
if (handler->queue_.empty()) {
|
||||
fdevent_del(&handler->write_fde_, FDE_WRITE);
|
||||
}
|
||||
|
|
@ -72,29 +70,19 @@ class FdHandler {
|
|||
std::queue<char> queue_;
|
||||
};
|
||||
|
||||
static void signal_handler(int) {
|
||||
pthread_exit(nullptr);
|
||||
}
|
||||
|
||||
class FdeventTest : public ::testing::Test {
|
||||
protected:
|
||||
static void SetUpTestCase() {
|
||||
ASSERT_NE(SIG_ERR, signal(SIGUSR1, signal_handler));
|
||||
ASSERT_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN));
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
fdevent_reset();
|
||||
ASSERT_EQ(0u, fdevent_installed_count());
|
||||
}
|
||||
};
|
||||
|
||||
struct ThreadArg {
|
||||
int first_read_fd;
|
||||
int last_write_fd;
|
||||
size_t middle_pipe_count;
|
||||
};
|
||||
|
||||
TEST_F(FdeventTest, fdevent_terminate) {
|
||||
adb_thread_t thread;
|
||||
PrepareThread();
|
||||
ASSERT_TRUE(adb_thread_create([](void*) { fdevent_loop(); }, nullptr, &thread));
|
||||
TerminateThread(thread);
|
||||
}
|
||||
|
||||
static void FdEventThreadFunc(ThreadArg* arg) {
|
||||
std::vector<int> read_fds;
|
||||
std::vector<int> write_fds;
|
||||
|
|
@ -102,7 +90,7 @@ static void FdEventThreadFunc(ThreadArg* arg) {
|
|||
read_fds.push_back(arg->first_read_fd);
|
||||
for (size_t i = 0; i < arg->middle_pipe_count; ++i) {
|
||||
int fds[2];
|
||||
ASSERT_EQ(0, pipe(fds));
|
||||
ASSERT_EQ(0, adb_socketpair(fds));
|
||||
read_fds.push_back(fds[0]);
|
||||
write_fds.push_back(fds[1]);
|
||||
}
|
||||
|
|
@ -122,9 +110,9 @@ TEST_F(FdeventTest, smoke) {
|
|||
const std::string MESSAGE = "fdevent_test";
|
||||
int fd_pair1[2];
|
||||
int fd_pair2[2];
|
||||
ASSERT_EQ(0, pipe(fd_pair1));
|
||||
ASSERT_EQ(0, pipe(fd_pair2));
|
||||
pthread_t thread;
|
||||
ASSERT_EQ(0, adb_socketpair(fd_pair1));
|
||||
ASSERT_EQ(0, adb_socketpair(fd_pair2));
|
||||
adb_thread_t thread;
|
||||
ThreadArg thread_arg;
|
||||
thread_arg.first_read_fd = fd_pair1[0];
|
||||
thread_arg.last_write_fd = fd_pair2[1];
|
||||
|
|
@ -132,9 +120,9 @@ TEST_F(FdeventTest, smoke) {
|
|||
int writer = fd_pair1[1];
|
||||
int reader = fd_pair2[0];
|
||||
|
||||
ASSERT_EQ(0, pthread_create(&thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(FdEventThreadFunc),
|
||||
&thread_arg));
|
||||
PrepareThread();
|
||||
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(FdEventThreadFunc), &thread_arg,
|
||||
&thread));
|
||||
|
||||
for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
|
||||
std::string read_buffer = MESSAGE;
|
||||
|
|
@ -144,10 +132,9 @@ TEST_F(FdeventTest, smoke) {
|
|||
ASSERT_EQ(read_buffer, write_buffer);
|
||||
}
|
||||
|
||||
ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
|
||||
ASSERT_EQ(0, pthread_join(thread, nullptr));
|
||||
ASSERT_EQ(0, close(writer));
|
||||
ASSERT_EQ(0, close(reader));
|
||||
TerminateThread(thread);
|
||||
ASSERT_EQ(0, adb_close(writer));
|
||||
ASSERT_EQ(0, adb_close(reader));
|
||||
}
|
||||
|
||||
struct InvalidFdArg {
|
||||
|
|
@ -161,7 +148,7 @@ static void InvalidFdEventCallback(int fd, unsigned events, void* userdata) {
|
|||
ASSERT_EQ(arg->expected_events, events);
|
||||
fdevent_remove(&arg->fde);
|
||||
if (++*(arg->happened_event_count) == 2) {
|
||||
pthread_exit(nullptr);
|
||||
fdevent_terminate_loop();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -184,9 +171,7 @@ static void InvalidFdThreadFunc(void*) {
|
|||
}
|
||||
|
||||
TEST_F(FdeventTest, invalid_fd) {
|
||||
pthread_t thread;
|
||||
ASSERT_EQ(0, pthread_create(&thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(InvalidFdThreadFunc),
|
||||
nullptr));
|
||||
ASSERT_EQ(0, pthread_join(thread, nullptr));
|
||||
adb_thread_t thread;
|
||||
ASSERT_TRUE(adb_thread_create(InvalidFdThreadFunc, nullptr, &thread));
|
||||
ASSERT_TRUE(adb_thread_join(thread));
|
||||
}
|
||||
|
|
|
|||
58
adb/fdevent_test.h
Normal file
58
adb/fdevent_test.h
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "socket.h"
|
||||
#include "sysdeps.h"
|
||||
|
||||
class FdeventTest : public ::testing::Test {
|
||||
protected:
|
||||
int dummy = -1;
|
||||
|
||||
static void SetUpTestCase() {
|
||||
#if !defined(_WIN32)
|
||||
ASSERT_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN));
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetUp() override {
|
||||
fdevent_reset();
|
||||
ASSERT_EQ(0u, fdevent_installed_count());
|
||||
}
|
||||
|
||||
// Register a dummy socket used to wake up the fdevent loop to tell it to die.
|
||||
void PrepareThread() {
|
||||
int dummy_fds[2];
|
||||
if (adb_socketpair(dummy_fds) != 0) {
|
||||
FAIL() << "failed to create socketpair: " << strerror(errno);
|
||||
}
|
||||
|
||||
asocket* dummy_socket = create_local_socket(dummy_fds[1]);
|
||||
if (!dummy_socket) {
|
||||
FAIL() << "failed to create local socket: " << strerror(errno);
|
||||
}
|
||||
dummy_socket->ready(dummy_socket);
|
||||
dummy = dummy_fds[0];
|
||||
}
|
||||
|
||||
void TerminateThread(adb_thread_t thread) {
|
||||
fdevent_terminate_loop();
|
||||
ASSERT_TRUE(WriteFdExactly(dummy, "", 1));
|
||||
ASSERT_TRUE(adb_thread_join(thread));
|
||||
ASSERT_EQ(0, adb_close(dummy));
|
||||
}
|
||||
};
|
||||
|
|
@ -88,7 +88,8 @@ class SyncConnection {
|
|||
: total_bytes_(0),
|
||||
start_time_ms_(CurrentTimeMs()),
|
||||
expected_total_bytes_(0),
|
||||
expect_multiple_files_(false) {
|
||||
expect_multiple_files_(false),
|
||||
expect_done_(false) {
|
||||
max = SYNC_DATA_MAX; // TODO: decide at runtime.
|
||||
|
||||
std::string error;
|
||||
|
|
@ -117,6 +118,16 @@ class SyncConnection {
|
|||
|
||||
bool IsValid() { return fd >= 0; }
|
||||
|
||||
bool ReceivedError(const char* from, const char* to) {
|
||||
adb_pollfd pfd = {.fd = fd, .events = POLLIN};
|
||||
int rc = adb_poll(&pfd, 1, 0);
|
||||
if (rc < 0) {
|
||||
Error("failed to poll: %s", strerror(errno));
|
||||
return true;
|
||||
}
|
||||
return rc != 0;
|
||||
}
|
||||
|
||||
bool SendRequest(int id, const char* path_and_mode) {
|
||||
size_t path_length = strlen(path_and_mode);
|
||||
if (path_length > 1024) {
|
||||
|
|
@ -175,6 +186,7 @@ class SyncConnection {
|
|||
p += sizeof(SyncRequest);
|
||||
|
||||
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
|
||||
expect_done_ = true;
|
||||
total_bytes_ += data_length;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -220,6 +232,11 @@ class SyncConnection {
|
|||
total_bytes_ += bytes_read;
|
||||
bytes_copied += bytes_read;
|
||||
|
||||
// Check to see if we've received an error from the other side.
|
||||
if (ReceivedError(lpath, rpath)) {
|
||||
break;
|
||||
}
|
||||
|
||||
ReportProgress(rpath, bytes_copied, total_size);
|
||||
}
|
||||
|
||||
|
|
@ -228,17 +245,24 @@ class SyncConnection {
|
|||
syncmsg msg;
|
||||
msg.data.id = ID_DONE;
|
||||
msg.data.size = mtime;
|
||||
expect_done_ = true;
|
||||
return WriteOrDie(lpath, rpath, &msg.data, sizeof(msg.data));
|
||||
}
|
||||
|
||||
bool CopyDone(const char* from, const char* to) {
|
||||
syncmsg msg;
|
||||
if (!ReadFdExactly(fd, &msg.status, sizeof(msg.status))) {
|
||||
Error("failed to copy '%s' to '%s': no ID_DONE: %s", from, to, strerror(errno));
|
||||
Error("failed to copy '%s' to '%s': couldn't read from device", from, to);
|
||||
return false;
|
||||
}
|
||||
if (msg.status.id == ID_OKAY) {
|
||||
return true;
|
||||
if (expect_done_) {
|
||||
expect_done_ = false;
|
||||
return true;
|
||||
} else {
|
||||
Error("failed to copy '%s' to '%s': received premature success", from, to);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (msg.status.id != ID_FAIL) {
|
||||
Error("failed to copy '%s' to '%s': unknown reason %d", from, to, msg.status.id);
|
||||
|
|
@ -357,6 +381,7 @@ class SyncConnection {
|
|||
|
||||
uint64_t expected_total_bytes_;
|
||||
bool expect_multiple_files_;
|
||||
bool expect_done_;
|
||||
|
||||
LinePrinter line_printer_;
|
||||
|
||||
|
|
|
|||
|
|
@ -183,8 +183,6 @@ static bool handle_send_file(int s, const char* path, uid_t uid,
|
|||
}
|
||||
|
||||
while (true) {
|
||||
unsigned int len;
|
||||
|
||||
if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
|
||||
|
||||
if (msg.data.id != ID_DATA) {
|
||||
|
|
@ -193,17 +191,17 @@ static bool handle_send_file(int s, const char* path, uid_t uid,
|
|||
break;
|
||||
}
|
||||
SendSyncFail(s, "invalid data message");
|
||||
goto fail;
|
||||
goto abort;
|
||||
}
|
||||
len = msg.data.size;
|
||||
if (len > buffer.size()) { // TODO: resize buffer?
|
||||
|
||||
if (msg.data.size > buffer.size()) { // TODO: resize buffer?
|
||||
SendSyncFail(s, "oversize data message");
|
||||
goto fail;
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!ReadFdExactly(s, &buffer[0], len)) goto fail;
|
||||
if (!ReadFdExactly(s, &buffer[0], msg.data.size)) goto abort;
|
||||
|
||||
if (!WriteFdExactly(fd, &buffer[0], len)) {
|
||||
if (!WriteFdExactly(fd, &buffer[0], msg.data.size)) {
|
||||
SendSyncFailErrno(s, "write failed");
|
||||
goto fail;
|
||||
}
|
||||
|
|
@ -221,6 +219,35 @@ static bool handle_send_file(int s, const char* path, uid_t uid,
|
|||
return WriteFdExactly(s, &msg.status, sizeof(msg.status));
|
||||
|
||||
fail:
|
||||
// If there's a problem on the device, we'll send an ID_FAIL message and
|
||||
// close the socket. Unfortunately the kernel will sometimes throw that
|
||||
// data away if the other end keeps writing without reading (which is
|
||||
// the case with old versions of adb). To maintain compatibility, keep
|
||||
// reading and throwing away ID_DATA packets until the other side notices
|
||||
// that we've reported an error.
|
||||
while (true) {
|
||||
if (!ReadFdExactly(s, &msg.data, sizeof(msg.data))) goto fail;
|
||||
|
||||
if (msg.data.id == ID_DONE) {
|
||||
goto abort;
|
||||
} else if (msg.data.id != ID_DATA) {
|
||||
char id[5];
|
||||
memcpy(id, &msg.data.id, sizeof(msg.data.id));
|
||||
id[4] = '\0';
|
||||
D("handle_send_fail received unexpected id '%s' during failure", id);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (msg.data.size > buffer.size()) {
|
||||
D("handle_send_fail received oversized packet of length '%u' during failure",
|
||||
msg.data.size);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (!ReadFdExactly(s, &buffer[0], msg.data.size)) goto abort;
|
||||
}
|
||||
|
||||
abort:
|
||||
if (fd >= 0) adb_close(fd);
|
||||
if (do_unlink) adb_unlink(path);
|
||||
return false;
|
||||
|
|
@ -403,18 +430,6 @@ static bool handle_sync_command(int fd, std::vector<char>& buffer) {
|
|||
void file_sync_service(int fd, void* cookie) {
|
||||
std::vector<char> buffer(SYNC_DATA_MAX);
|
||||
|
||||
// If there's a problem on the device, we'll send an ID_FAIL message and
|
||||
// close the socket. Unfortunately the kernel will sometimes throw that
|
||||
// data away if the other end keeps writing without reading (which is
|
||||
// the normal case with our protocol --- they won't read until the end).
|
||||
// So set SO_LINGER to give the client 20s to get around to reading our
|
||||
// failure response. Without this, the other side's ability to report
|
||||
// useful errors is reduced.
|
||||
struct linger l;
|
||||
l.l_onoff = 1;
|
||||
l.l_linger = 20;
|
||||
adb_setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
|
||||
|
||||
while (handle_sync_command(fd, buffer)) {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,25 +41,25 @@ struct SyncRequest {
|
|||
|
||||
union syncmsg {
|
||||
struct __attribute__((packed)) {
|
||||
unsigned id;
|
||||
unsigned mode;
|
||||
unsigned size;
|
||||
unsigned time;
|
||||
uint32_t id;
|
||||
uint32_t mode;
|
||||
uint32_t size;
|
||||
uint32_t time;
|
||||
} stat;
|
||||
struct __attribute__((packed)) {
|
||||
unsigned id;
|
||||
unsigned mode;
|
||||
unsigned size;
|
||||
unsigned time;
|
||||
unsigned namelen;
|
||||
uint32_t id;
|
||||
uint32_t mode;
|
||||
uint32_t size;
|
||||
uint32_t time;
|
||||
uint32_t namelen;
|
||||
} dent;
|
||||
struct __attribute__((packed)) {
|
||||
unsigned id;
|
||||
unsigned size;
|
||||
uint32_t id;
|
||||
uint32_t size;
|
||||
} data;
|
||||
struct __attribute__((packed)) {
|
||||
unsigned id;
|
||||
unsigned msglen;
|
||||
uint32_t id;
|
||||
uint32_t msglen;
|
||||
} status;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include "remount_service.h"
|
||||
#include "services.h"
|
||||
#include "shell_service.h"
|
||||
#include "sysdeps.h"
|
||||
#include "transport.h"
|
||||
|
||||
struct stinfo {
|
||||
|
|
@ -57,13 +58,11 @@ struct stinfo {
|
|||
void *cookie;
|
||||
};
|
||||
|
||||
void *service_bootstrap_func(void *x)
|
||||
{
|
||||
static void service_bootstrap_func(void* x) {
|
||||
stinfo* sti = reinterpret_cast<stinfo*>(x);
|
||||
adb_thread_setname(android::base::StringPrintf("service %d", sti->fd));
|
||||
sti->func(sti->fd, sti->cookie);
|
||||
free(sti);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if !ADB_HOST
|
||||
|
|
@ -371,12 +370,21 @@ static void wait_for_state(int fd, void* data) {
|
|||
std::string error = "unknown error";
|
||||
const char* serial = sinfo->serial.length() ? sinfo->serial.c_str() : NULL;
|
||||
atransport* t = acquire_one_transport(sinfo->transport_type, serial, &is_ambiguous, &error);
|
||||
|
||||
if (t != nullptr && t->connection_state == sinfo->state) {
|
||||
SendOkay(fd);
|
||||
break;
|
||||
} else if (!is_ambiguous) {
|
||||
adb_sleep_ms(1000);
|
||||
adb_pollfd pfd = {.fd = fd, .events = POLLIN };
|
||||
int rc = adb_poll(&pfd, 1, 1000);
|
||||
if (rc < 0) {
|
||||
SendFail(fd, error);
|
||||
break;
|
||||
} else if (rc > 0 && (pfd.revents & POLLHUP) != 0) {
|
||||
// The other end of the socket is closed, probably because the other side was
|
||||
// terminated, bail out.
|
||||
break;
|
||||
}
|
||||
|
||||
// Try again...
|
||||
} else {
|
||||
SendFail(fd, error);
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ class Subprocess {
|
|||
// Opens the file at |pts_name|.
|
||||
int OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd);
|
||||
|
||||
static void* ThreadHandler(void* userdata);
|
||||
static void ThreadHandler(void* userdata);
|
||||
void PassDataStreams();
|
||||
void WaitForExit();
|
||||
|
||||
|
|
@ -465,7 +465,7 @@ int Subprocess::OpenPtyChildFd(const char* pts_name, ScopedFd* error_sfd) {
|
|||
return child_fd;
|
||||
}
|
||||
|
||||
void* Subprocess::ThreadHandler(void* userdata) {
|
||||
void Subprocess::ThreadHandler(void* userdata) {
|
||||
Subprocess* subprocess = reinterpret_cast<Subprocess*>(userdata);
|
||||
|
||||
adb_thread_setname(android::base::StringPrintf(
|
||||
|
|
@ -475,8 +475,6 @@ void* Subprocess::ThreadHandler(void* userdata) {
|
|||
|
||||
D("deleting Subprocess for PID %d", subprocess->pid());
|
||||
delete subprocess;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Subprocess::PassDataStreams() {
|
||||
|
|
|
|||
|
|
@ -18,119 +18,89 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <array>
|
||||
#include <limits>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "adb.h"
|
||||
#include "adb_io.h"
|
||||
#include "fdevent_test.h"
|
||||
#include "socket.h"
|
||||
#include "sysdeps.h"
|
||||
|
||||
static void signal_handler(int) {
|
||||
ASSERT_EQ(1u, fdevent_installed_count());
|
||||
pthread_exit(nullptr);
|
||||
}
|
||||
|
||||
// On host, register a dummy socket, so fdevet_loop() will not abort when previously
|
||||
// registered local sockets are all closed. On device, fdevent_subproc_setup() installs
|
||||
// one fdevent which can be considered as dummy socket.
|
||||
static void InstallDummySocket() {
|
||||
#if ADB_HOST
|
||||
int dummy_fds[2];
|
||||
ASSERT_EQ(0, pipe(dummy_fds));
|
||||
asocket* dummy_socket = create_local_socket(dummy_fds[0]);
|
||||
ASSERT_TRUE(dummy_socket != nullptr);
|
||||
dummy_socket->ready(dummy_socket);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct ThreadArg {
|
||||
int first_read_fd;
|
||||
int last_write_fd;
|
||||
size_t middle_pipe_count;
|
||||
};
|
||||
|
||||
static void FdEventThreadFunc(ThreadArg* arg) {
|
||||
std::vector<int> read_fds;
|
||||
std::vector<int> write_fds;
|
||||
class LocalSocketTest : public FdeventTest {};
|
||||
|
||||
read_fds.push_back(arg->first_read_fd);
|
||||
for (size_t i = 0; i < arg->middle_pipe_count; ++i) {
|
||||
int fds[2];
|
||||
ASSERT_EQ(0, adb_socketpair(fds));
|
||||
read_fds.push_back(fds[0]);
|
||||
write_fds.push_back(fds[1]);
|
||||
}
|
||||
write_fds.push_back(arg->last_write_fd);
|
||||
|
||||
for (size_t i = 0; i < read_fds.size(); ++i) {
|
||||
asocket* reader = create_local_socket(read_fds[i]);
|
||||
ASSERT_TRUE(reader != nullptr);
|
||||
asocket* writer = create_local_socket(write_fds[i]);
|
||||
ASSERT_TRUE(writer != nullptr);
|
||||
reader->peer = writer;
|
||||
writer->peer = reader;
|
||||
reader->ready(reader);
|
||||
}
|
||||
|
||||
InstallDummySocket();
|
||||
static void FdEventThreadFunc(void*) {
|
||||
fdevent_loop();
|
||||
}
|
||||
|
||||
class LocalSocketTest : public ::testing::Test {
|
||||
protected:
|
||||
static void SetUpTestCase() {
|
||||
ASSERT_NE(SIG_ERR, signal(SIGUSR1, signal_handler));
|
||||
ASSERT_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN));
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
fdevent_reset();
|
||||
ASSERT_EQ(0u, fdevent_installed_count());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(LocalSocketTest, smoke) {
|
||||
const size_t PIPE_COUNT = 100;
|
||||
const size_t MESSAGE_LOOP_COUNT = 100;
|
||||
// Join two socketpairs with a chain of intermediate socketpairs.
|
||||
int first[2];
|
||||
std::vector<std::array<int, 2>> intermediates;
|
||||
int last[2];
|
||||
|
||||
constexpr size_t INTERMEDIATE_COUNT = 50;
|
||||
constexpr size_t MESSAGE_LOOP_COUNT = 100;
|
||||
const std::string MESSAGE = "socket_test";
|
||||
int fd_pair1[2];
|
||||
int fd_pair2[2];
|
||||
ASSERT_EQ(0, adb_socketpair(fd_pair1));
|
||||
ASSERT_EQ(0, adb_socketpair(fd_pair2));
|
||||
pthread_t thread;
|
||||
ThreadArg thread_arg;
|
||||
thread_arg.first_read_fd = fd_pair1[0];
|
||||
thread_arg.last_write_fd = fd_pair2[1];
|
||||
thread_arg.middle_pipe_count = PIPE_COUNT;
|
||||
int writer = fd_pair1[1];
|
||||
int reader = fd_pair2[0];
|
||||
|
||||
ASSERT_EQ(0, pthread_create(&thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(FdEventThreadFunc),
|
||||
&thread_arg));
|
||||
intermediates.resize(INTERMEDIATE_COUNT);
|
||||
ASSERT_EQ(0, adb_socketpair(first)) << strerror(errno);
|
||||
ASSERT_EQ(0, adb_socketpair(last)) << strerror(errno);
|
||||
asocket* prev_tail = create_local_socket(first[1]);
|
||||
ASSERT_NE(nullptr, prev_tail);
|
||||
|
||||
auto connect = [](asocket* tail, asocket* head) {
|
||||
tail->peer = head;
|
||||
head->peer = tail;
|
||||
tail->ready(tail);
|
||||
};
|
||||
|
||||
for (auto& intermediate : intermediates) {
|
||||
ASSERT_EQ(0, adb_socketpair(intermediate.data())) << strerror(errno);
|
||||
|
||||
asocket* head = create_local_socket(intermediate[0]);
|
||||
ASSERT_NE(nullptr, head);
|
||||
|
||||
asocket* tail = create_local_socket(intermediate[1]);
|
||||
ASSERT_NE(nullptr, tail);
|
||||
|
||||
connect(prev_tail, head);
|
||||
prev_tail = tail;
|
||||
}
|
||||
|
||||
asocket* end = create_local_socket(last[0]);
|
||||
ASSERT_NE(nullptr, end);
|
||||
connect(prev_tail, end);
|
||||
|
||||
PrepareThread();
|
||||
adb_thread_t thread;
|
||||
ASSERT_TRUE(adb_thread_create(FdEventThreadFunc, nullptr, &thread));
|
||||
|
||||
usleep(1000);
|
||||
for (size_t i = 0; i < MESSAGE_LOOP_COUNT; ++i) {
|
||||
std::string read_buffer = MESSAGE;
|
||||
std::string write_buffer(MESSAGE.size(), 'a');
|
||||
ASSERT_TRUE(WriteFdExactly(writer, read_buffer.c_str(), read_buffer.size()));
|
||||
ASSERT_TRUE(ReadFdExactly(reader, &write_buffer[0], write_buffer.size()));
|
||||
ASSERT_TRUE(WriteFdExactly(first[0], &read_buffer[0], read_buffer.size()));
|
||||
ASSERT_TRUE(ReadFdExactly(last[1], &write_buffer[0], write_buffer.size()));
|
||||
ASSERT_EQ(read_buffer, write_buffer);
|
||||
}
|
||||
ASSERT_EQ(0, adb_close(writer));
|
||||
ASSERT_EQ(0, adb_close(reader));
|
||||
// Wait until the local sockets are closed.
|
||||
sleep(1);
|
||||
|
||||
ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
|
||||
ASSERT_EQ(0, pthread_join(thread, nullptr));
|
||||
ASSERT_EQ(0, adb_close(first[0]));
|
||||
ASSERT_EQ(0, adb_close(last[1]));
|
||||
|
||||
// Wait until the local sockets are closed.
|
||||
adb_sleep_ms(100);
|
||||
TerminateThread(thread);
|
||||
}
|
||||
|
||||
struct CloseWithPacketArg {
|
||||
|
|
@ -160,7 +130,6 @@ static void CloseWithPacketThreadFunc(CloseWithPacketArg* arg) {
|
|||
s->peer = cause_close_s;
|
||||
cause_close_s->ready(cause_close_s);
|
||||
|
||||
InstallDummySocket();
|
||||
fdevent_loop();
|
||||
}
|
||||
|
||||
|
|
@ -176,21 +145,19 @@ TEST_F(LocalSocketTest, close_socket_with_packet) {
|
|||
CloseWithPacketArg arg;
|
||||
arg.socket_fd = socket_fd[1];
|
||||
arg.cause_close_fd = cause_close_fd[1];
|
||||
pthread_t thread;
|
||||
ASSERT_EQ(0, pthread_create(&thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(CloseWithPacketThreadFunc),
|
||||
&arg));
|
||||
// Wait until the fdevent_loop() starts.
|
||||
sleep(1);
|
||||
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
|
||||
sleep(1);
|
||||
ASSERT_EQ(2u, fdevent_installed_count());
|
||||
ASSERT_EQ(0, adb_close(socket_fd[0]));
|
||||
// Wait until the socket is closed.
|
||||
sleep(1);
|
||||
|
||||
ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
|
||||
ASSERT_EQ(0, pthread_join(thread, nullptr));
|
||||
PrepareThread();
|
||||
adb_thread_t thread;
|
||||
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
|
||||
&arg, &thread));
|
||||
// Wait until the fdevent_loop() starts.
|
||||
adb_sleep_ms(100);
|
||||
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
|
||||
adb_sleep_ms(100);
|
||||
EXPECT_EQ(2u, fdevent_installed_count());
|
||||
ASSERT_EQ(0, adb_close(socket_fd[0]));
|
||||
|
||||
TerminateThread(thread);
|
||||
}
|
||||
|
||||
// This test checks if we can read packets from a closing local socket.
|
||||
|
|
@ -203,26 +170,23 @@ TEST_F(LocalSocketTest, read_from_closing_socket) {
|
|||
arg.socket_fd = socket_fd[1];
|
||||
arg.cause_close_fd = cause_close_fd[1];
|
||||
|
||||
pthread_t thread;
|
||||
ASSERT_EQ(0, pthread_create(&thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(CloseWithPacketThreadFunc),
|
||||
&arg));
|
||||
PrepareThread();
|
||||
adb_thread_t thread;
|
||||
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
|
||||
&arg, &thread));
|
||||
// Wait until the fdevent_loop() starts.
|
||||
sleep(1);
|
||||
adb_sleep_ms(100);
|
||||
ASSERT_EQ(0, adb_close(cause_close_fd[0]));
|
||||
sleep(1);
|
||||
ASSERT_EQ(2u, fdevent_installed_count());
|
||||
adb_sleep_ms(100);
|
||||
EXPECT_EQ(2u, fdevent_installed_count());
|
||||
|
||||
// Verify if we can read successfully.
|
||||
std::vector<char> buf(arg.bytes_written);
|
||||
ASSERT_NE(0u, arg.bytes_written);
|
||||
ASSERT_EQ(true, ReadFdExactly(socket_fd[0], buf.data(), buf.size()));
|
||||
ASSERT_EQ(0, adb_close(socket_fd[0]));
|
||||
|
||||
// Wait until the socket is closed.
|
||||
sleep(1);
|
||||
|
||||
ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
|
||||
ASSERT_EQ(0, pthread_join(thread, nullptr));
|
||||
TerminateThread(thread);
|
||||
}
|
||||
|
||||
// This test checks if we can close local socket in the following situation:
|
||||
|
|
@ -238,20 +202,17 @@ TEST_F(LocalSocketTest, write_error_when_having_packets) {
|
|||
arg.socket_fd = socket_fd[1];
|
||||
arg.cause_close_fd = cause_close_fd[1];
|
||||
|
||||
pthread_t thread;
|
||||
ASSERT_EQ(0, pthread_create(&thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(CloseWithPacketThreadFunc),
|
||||
&arg));
|
||||
PrepareThread();
|
||||
adb_thread_t thread;
|
||||
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseWithPacketThreadFunc),
|
||||
&arg, &thread));
|
||||
|
||||
// Wait until the fdevent_loop() starts.
|
||||
sleep(1);
|
||||
ASSERT_EQ(3u, fdevent_installed_count());
|
||||
adb_sleep_ms(100);
|
||||
EXPECT_EQ(3u, fdevent_installed_count());
|
||||
ASSERT_EQ(0, adb_close(socket_fd[0]));
|
||||
|
||||
// Wait until the socket is closed.
|
||||
sleep(1);
|
||||
|
||||
ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
|
||||
ASSERT_EQ(0, pthread_join(thread, nullptr));
|
||||
TerminateThread(thread);
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
|
|
@ -260,50 +221,52 @@ static void ClientThreadFunc() {
|
|||
std::string error;
|
||||
int fd = network_loopback_client(5038, SOCK_STREAM, &error);
|
||||
ASSERT_GE(fd, 0) << error;
|
||||
sleep(2);
|
||||
adb_sleep_ms(200);
|
||||
ASSERT_EQ(0, adb_close(fd));
|
||||
}
|
||||
|
||||
struct CloseRdHupSocketArg {
|
||||
int socket_fd;
|
||||
int socket_fd;
|
||||
};
|
||||
|
||||
static void CloseRdHupSocketThreadFunc(CloseRdHupSocketArg* arg) {
|
||||
asocket* s = create_local_socket(arg->socket_fd);
|
||||
ASSERT_TRUE(s != nullptr);
|
||||
asocket* s = create_local_socket(arg->socket_fd);
|
||||
ASSERT_TRUE(s != nullptr);
|
||||
|
||||
InstallDummySocket();
|
||||
fdevent_loop();
|
||||
fdevent_loop();
|
||||
}
|
||||
|
||||
// This test checks if we can close sockets in CLOSE_WAIT state.
|
||||
TEST_F(LocalSocketTest, close_socket_in_CLOSE_WAIT_state) {
|
||||
std::string error;
|
||||
int listen_fd = network_inaddr_any_server(5038, SOCK_STREAM, &error);
|
||||
ASSERT_GE(listen_fd, 0);
|
||||
pthread_t client_thread;
|
||||
ASSERT_EQ(0, pthread_create(&client_thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(ClientThreadFunc), nullptr));
|
||||
std::string error;
|
||||
int listen_fd = network_inaddr_any_server(5038, SOCK_STREAM, &error);
|
||||
ASSERT_GE(listen_fd, 0);
|
||||
|
||||
struct sockaddr addr;
|
||||
socklen_t alen;
|
||||
alen = sizeof(addr);
|
||||
int accept_fd = adb_socket_accept(listen_fd, &addr, &alen);
|
||||
ASSERT_GE(accept_fd, 0);
|
||||
CloseRdHupSocketArg arg;
|
||||
arg.socket_fd = accept_fd;
|
||||
pthread_t thread;
|
||||
ASSERT_EQ(0, pthread_create(&thread, nullptr,
|
||||
reinterpret_cast<void* (*)(void*)>(CloseRdHupSocketThreadFunc),
|
||||
&arg));
|
||||
// Wait until the fdevent_loop() starts.
|
||||
sleep(1);
|
||||
ASSERT_EQ(2u, fdevent_installed_count());
|
||||
// Wait until the client closes its socket.
|
||||
ASSERT_EQ(0, pthread_join(client_thread, nullptr));
|
||||
sleep(2);
|
||||
ASSERT_EQ(0, pthread_kill(thread, SIGUSR1));
|
||||
ASSERT_EQ(0, pthread_join(thread, nullptr));
|
||||
adb_thread_t client_thread;
|
||||
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(ClientThreadFunc), nullptr,
|
||||
&client_thread));
|
||||
|
||||
struct sockaddr addr;
|
||||
socklen_t alen;
|
||||
alen = sizeof(addr);
|
||||
int accept_fd = adb_socket_accept(listen_fd, &addr, &alen);
|
||||
ASSERT_GE(accept_fd, 0);
|
||||
CloseRdHupSocketArg arg;
|
||||
arg.socket_fd = accept_fd;
|
||||
|
||||
PrepareThread();
|
||||
adb_thread_t thread;
|
||||
ASSERT_TRUE(adb_thread_create(reinterpret_cast<void (*)(void*)>(CloseRdHupSocketThreadFunc),
|
||||
&arg, &thread));
|
||||
|
||||
// Wait until the fdevent_loop() starts.
|
||||
adb_sleep_ms(100);
|
||||
EXPECT_EQ(2u, fdevent_installed_count());
|
||||
|
||||
// Wait until the client closes its socket.
|
||||
ASSERT_TRUE(adb_thread_join(client_thread));
|
||||
|
||||
TerminateThread(thread);
|
||||
}
|
||||
|
||||
#endif // defined(__linux__)
|
||||
|
|
|
|||
158
adb/sysdeps.h
158
adb/sysdeps.h
|
|
@ -30,6 +30,7 @@
|
|||
#include <vector>
|
||||
|
||||
// Include this before open/unlink are defined as macros below.
|
||||
#include <android-base/errors.h>
|
||||
#include <android-base/utf8.h>
|
||||
|
||||
/*
|
||||
|
|
@ -114,13 +115,62 @@ static __inline__ void adb_mutex_unlock( adb_mutex_t* lock )
|
|||
LeaveCriticalSection( lock );
|
||||
}
|
||||
|
||||
typedef void* (*adb_thread_func_t)(void* arg);
|
||||
typedef void (*adb_thread_func_t)(void* arg);
|
||||
typedef HANDLE adb_thread_t;
|
||||
|
||||
typedef void (*win_thread_func_t)(void* arg);
|
||||
struct adb_winthread_args {
|
||||
adb_thread_func_t func;
|
||||
void* arg;
|
||||
};
|
||||
|
||||
static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg) {
|
||||
uintptr_t tid = _beginthread((win_thread_func_t)func, 0, arg);
|
||||
return (tid != static_cast<uintptr_t>(-1L));
|
||||
static unsigned __stdcall adb_winthread_wrapper(void* heap_args) {
|
||||
// Move the arguments from the heap onto the thread's stack.
|
||||
adb_winthread_args thread_args = *static_cast<adb_winthread_args*>(heap_args);
|
||||
delete static_cast<adb_winthread_args*>(heap_args);
|
||||
thread_args.func(thread_args.arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline__ bool adb_thread_create(adb_thread_func_t func, void* arg,
|
||||
adb_thread_t* thread = nullptr) {
|
||||
adb_winthread_args* args = new adb_winthread_args{.func = func, .arg = arg};
|
||||
uintptr_t handle = _beginthreadex(nullptr, 0, adb_winthread_wrapper, args, 0, nullptr);
|
||||
if (handle != static_cast<uintptr_t>(0)) {
|
||||
if (thread) {
|
||||
*thread = reinterpret_cast<HANDLE>(handle);
|
||||
} else {
|
||||
CloseHandle(thread);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static __inline__ bool adb_thread_join(adb_thread_t thread) {
|
||||
switch (WaitForSingleObject(thread, INFINITE)) {
|
||||
case WAIT_OBJECT_0:
|
||||
CloseHandle(thread);
|
||||
return true;
|
||||
|
||||
case WAIT_FAILED:
|
||||
fprintf(stderr, "adb_thread_join failed: %s\n",
|
||||
android::base::SystemErrorCodeToString(GetLastError()).c_str());
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static __inline__ bool adb_thread_detach(adb_thread_t thread) {
|
||||
CloseHandle(thread);
|
||||
return true;
|
||||
}
|
||||
|
||||
static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
|
||||
_endthreadex(0);
|
||||
}
|
||||
|
||||
static __inline__ int adb_thread_setname(const std::string& name) {
|
||||
|
|
@ -130,6 +180,14 @@ static __inline__ int adb_thread_setname(const std::string& name) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static __inline__ adb_thread_t adb_thread_self() {
|
||||
return GetCurrentThread();
|
||||
}
|
||||
|
||||
static __inline__ bool adb_thread_equal(adb_thread_t lhs, adb_thread_t rhs) {
|
||||
return GetThreadId(lhs) == GetThreadId(rhs);
|
||||
}
|
||||
|
||||
static __inline__ unsigned long adb_thread_id()
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
|
|
@ -213,24 +271,6 @@ int unix_isatty(int fd);
|
|||
/* normally provided by <cutils/misc.h> */
|
||||
extern void* load_file(const char* pathname, unsigned* psize);
|
||||
|
||||
/* normally provided by "fdevent.h" */
|
||||
|
||||
#define FDE_READ 0x0001
|
||||
#define FDE_WRITE 0x0002
|
||||
#define FDE_ERROR 0x0004
|
||||
#define FDE_DONT_CLOSE 0x0080
|
||||
|
||||
typedef void (*fd_func)(int fd, unsigned events, void *userdata);
|
||||
|
||||
fdevent *fdevent_create(int fd, fd_func func, void *arg);
|
||||
void fdevent_destroy(fdevent *fde);
|
||||
void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg);
|
||||
void fdevent_remove(fdevent *item);
|
||||
void fdevent_set(fdevent *fde, unsigned events);
|
||||
void fdevent_add(fdevent *fde, unsigned events);
|
||||
void fdevent_del(fdevent *fde, unsigned events);
|
||||
void fdevent_loop();
|
||||
|
||||
static __inline__ void adb_sleep_ms( int mseconds )
|
||||
{
|
||||
Sleep( mseconds );
|
||||
|
|
@ -254,6 +294,14 @@ extern int adb_setsockopt(int fd, int level, int optname, const void* optva
|
|||
|
||||
extern int adb_socketpair( int sv[2] );
|
||||
|
||||
struct adb_pollfd {
|
||||
int fd;
|
||||
short events;
|
||||
short revents;
|
||||
};
|
||||
extern int adb_poll(adb_pollfd* fds, size_t nfds, int timeout);
|
||||
#define poll ___xxx_poll
|
||||
|
||||
static __inline__ int adb_is_absolute_host_path(const char* path) {
|
||||
return isalpha(path[0]) && path[1] == ':' && path[2] == '\\';
|
||||
}
|
||||
|
|
@ -406,14 +454,14 @@ size_t ParseCompleteUTF8(const char* first, const char* last, std::vector<char>*
|
|||
|
||||
#else /* !_WIN32 a.k.a. Unix */
|
||||
|
||||
#include "fdevent.h"
|
||||
#include <cutils/misc.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <cutils/threads.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -656,16 +704,53 @@ static __inline__ int adb_socket_accept(int serverfd, struct sockaddr* addr,
|
|||
#define unix_write adb_write
|
||||
#define unix_close adb_close
|
||||
|
||||
typedef void* (*adb_thread_func_t)( void* arg );
|
||||
// Win32 is limited to DWORDs for thread return values; limit the POSIX systems to this as well to
|
||||
// ensure compatibility.
|
||||
typedef void (*adb_thread_func_t)(void* arg);
|
||||
typedef pthread_t adb_thread_t;
|
||||
|
||||
static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg) {
|
||||
struct adb_pthread_args {
|
||||
adb_thread_func_t func;
|
||||
void* arg;
|
||||
};
|
||||
|
||||
static void* adb_pthread_wrapper(void* heap_args) {
|
||||
// Move the arguments from the heap onto the thread's stack.
|
||||
adb_pthread_args thread_args = *reinterpret_cast<adb_pthread_args*>(heap_args);
|
||||
delete static_cast<adb_pthread_args*>(heap_args);
|
||||
thread_args.func(thread_args.arg);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static __inline__ bool adb_thread_create(adb_thread_func_t start, void* arg,
|
||||
adb_thread_t* thread = nullptr) {
|
||||
pthread_t temp;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_setdetachstate(&attr, thread ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED);
|
||||
auto* pthread_args = new adb_pthread_args{.func = start, .arg = arg};
|
||||
errno = pthread_create(&temp, &attr, adb_pthread_wrapper, pthread_args);
|
||||
if (errno == 0) {
|
||||
if (thread) {
|
||||
*thread = temp;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_t thread;
|
||||
errno = pthread_create(&thread, &attr, start, arg);
|
||||
return (errno == 0);
|
||||
static __inline__ bool adb_thread_join(adb_thread_t thread) {
|
||||
errno = pthread_join(thread, nullptr);
|
||||
return errno == 0;
|
||||
}
|
||||
|
||||
static __inline__ bool adb_thread_detach(adb_thread_t thread) {
|
||||
errno = pthread_detach(thread);
|
||||
return errno == 0;
|
||||
}
|
||||
|
||||
static __inline__ void __attribute__((noreturn)) adb_thread_exit() {
|
||||
pthread_exit(nullptr);
|
||||
}
|
||||
|
||||
static __inline__ int adb_thread_setname(const std::string& name) {
|
||||
|
|
@ -716,6 +801,13 @@ static __inline__ int adb_socketpair( int sv[2] )
|
|||
#undef socketpair
|
||||
#define socketpair ___xxx_socketpair
|
||||
|
||||
typedef struct pollfd adb_pollfd;
|
||||
static __inline__ int adb_poll(adb_pollfd* fds, size_t nfds, int timeout) {
|
||||
return TEMP_FAILURE_RETRY(poll(fds, nfds, timeout));
|
||||
}
|
||||
|
||||
#define poll ___xxx_poll
|
||||
|
||||
static __inline__ void adb_sleep_ms( int mseconds )
|
||||
{
|
||||
usleep( mseconds*1000 );
|
||||
|
|
|
|||
217
adb/sysdeps_test.cpp
Normal file
217
adb/sysdeps_test.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <unistd.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "adb_io.h"
|
||||
#include "sysdeps.h"
|
||||
|
||||
static void increment_atomic_int(void* c) {
|
||||
sleep(1);
|
||||
reinterpret_cast<std::atomic<int>*>(c)->fetch_add(1);
|
||||
}
|
||||
|
||||
TEST(sysdeps_thread, smoke) {
|
||||
std::atomic<int> counter(0);
|
||||
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter));
|
||||
}
|
||||
|
||||
sleep(2);
|
||||
ASSERT_EQ(100, counter.load());
|
||||
}
|
||||
|
||||
TEST(sysdeps_thread, join) {
|
||||
std::atomic<int> counter(0);
|
||||
std::vector<adb_thread_t> threads(500);
|
||||
for (size_t i = 0; i < threads.size(); ++i) {
|
||||
ASSERT_TRUE(adb_thread_create(increment_atomic_int, &counter, &threads[i]));
|
||||
}
|
||||
|
||||
int current = counter.load();
|
||||
ASSERT_GE(current, 0);
|
||||
// Make sure that adb_thread_create actually creates threads, and doesn't do something silly
|
||||
// like synchronously run the function passed in. The sleep in increment_atomic_int should be
|
||||
// enough to keep this from being flakey.
|
||||
ASSERT_LT(current, 500);
|
||||
|
||||
for (const auto& thread : threads) {
|
||||
ASSERT_TRUE(adb_thread_join(thread));
|
||||
}
|
||||
|
||||
ASSERT_EQ(500, counter.load());
|
||||
}
|
||||
|
||||
TEST(sysdeps_thread, exit) {
|
||||
adb_thread_t thread;
|
||||
ASSERT_TRUE(adb_thread_create(
|
||||
[](void*) {
|
||||
adb_thread_exit();
|
||||
for (;;) continue;
|
||||
},
|
||||
nullptr, &thread));
|
||||
ASSERT_TRUE(adb_thread_join(thread));
|
||||
}
|
||||
|
||||
TEST(sysdeps_socketpair, smoke) {
|
||||
int fds[2];
|
||||
ASSERT_EQ(0, adb_socketpair(fds)) << strerror(errno);
|
||||
ASSERT_TRUE(WriteFdExactly(fds[0], "foo", 4));
|
||||
ASSERT_TRUE(WriteFdExactly(fds[1], "bar", 4));
|
||||
|
||||
char buf[4];
|
||||
ASSERT_TRUE(ReadFdExactly(fds[1], buf, 4));
|
||||
ASSERT_STREQ(buf, "foo");
|
||||
ASSERT_TRUE(ReadFdExactly(fds[0], buf, 4));
|
||||
ASSERT_STREQ(buf, "bar");
|
||||
ASSERT_EQ(0, adb_close(fds[0]));
|
||||
ASSERT_EQ(0, adb_close(fds[1]));
|
||||
}
|
||||
|
||||
TEST(sysdeps_fd, exhaustion) {
|
||||
std::vector<int> fds;
|
||||
int socketpair[2];
|
||||
|
||||
while (adb_socketpair(socketpair) == 0) {
|
||||
fds.push_back(socketpair[0]);
|
||||
fds.push_back(socketpair[1]);
|
||||
}
|
||||
|
||||
ASSERT_EQ(EMFILE, errno) << strerror(errno);
|
||||
for (int fd : fds) {
|
||||
ASSERT_EQ(0, adb_close(fd));
|
||||
}
|
||||
ASSERT_EQ(0, adb_socketpair(socketpair));
|
||||
ASSERT_EQ(socketpair[0], fds[0]);
|
||||
ASSERT_EQ(socketpair[1], fds[1]);
|
||||
ASSERT_EQ(0, adb_close(socketpair[0]));
|
||||
ASSERT_EQ(0, adb_close(socketpair[1]));
|
||||
}
|
||||
|
||||
class sysdeps_poll : public ::testing::Test {
|
||||
protected:
|
||||
int fds[2];
|
||||
void SetUp() override {
|
||||
ASSERT_EQ(0, adb_socketpair(fds)) << strerror(errno);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
if (fds[0] >= 0) {
|
||||
ASSERT_EQ(0, adb_close(fds[0]));
|
||||
}
|
||||
if (fds[1] >= 0) {
|
||||
ASSERT_EQ(0, adb_close(fds[1]));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(sysdeps_poll, smoke) {
|
||||
adb_pollfd pfd[2] = {};
|
||||
pfd[0].fd = fds[0];
|
||||
pfd[0].events = POLLRDNORM;
|
||||
pfd[1].fd = fds[1];
|
||||
pfd[1].events = POLLWRNORM;
|
||||
|
||||
pfd[0].revents = -1;
|
||||
pfd[1].revents = -1;
|
||||
EXPECT_EQ(1, adb_poll(pfd, 2, 0));
|
||||
EXPECT_EQ(0, pfd[0].revents);
|
||||
EXPECT_EQ(POLLWRNORM, pfd[1].revents);
|
||||
|
||||
ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
|
||||
|
||||
// Wait for the socketpair to be flushed.
|
||||
pfd[0].revents = -1;
|
||||
EXPECT_EQ(1, adb_poll(pfd, 1, 100));
|
||||
EXPECT_EQ(POLLRDNORM, pfd[0].revents);
|
||||
pfd[0].revents = -1;
|
||||
pfd[1].revents = -1;
|
||||
EXPECT_EQ(2, adb_poll(pfd, 2, 0));
|
||||
EXPECT_EQ(POLLRDNORM, pfd[0].revents);
|
||||
EXPECT_EQ(POLLWRNORM, pfd[1].revents);
|
||||
}
|
||||
|
||||
TEST_F(sysdeps_poll, timeout) {
|
||||
adb_pollfd pfd = {};
|
||||
pfd.fd = fds[0];
|
||||
pfd.events = POLLRDNORM;
|
||||
|
||||
EXPECT_EQ(0, adb_poll(&pfd, 1, 100));
|
||||
EXPECT_EQ(0, pfd.revents);
|
||||
|
||||
ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
|
||||
|
||||
EXPECT_EQ(1, adb_poll(&pfd, 1, 100));
|
||||
EXPECT_EQ(POLLRDNORM, pfd.revents);
|
||||
}
|
||||
|
||||
TEST_F(sysdeps_poll, invalid_fd) {
|
||||
adb_pollfd pfd[3] = {};
|
||||
pfd[0].fd = fds[0];
|
||||
pfd[0].events = POLLRDNORM;
|
||||
pfd[1].fd = INT_MAX;
|
||||
pfd[1].events = POLLRDNORM;
|
||||
pfd[2].fd = fds[1];
|
||||
pfd[2].events = POLLWRNORM;
|
||||
|
||||
ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
|
||||
|
||||
// Wait for the socketpair to be flushed.
|
||||
EXPECT_EQ(1, adb_poll(pfd, 1, 100));
|
||||
EXPECT_EQ(POLLRDNORM, pfd[0].revents);
|
||||
|
||||
EXPECT_EQ(3, adb_poll(pfd, 3, 0));
|
||||
EXPECT_EQ(POLLRDNORM, pfd[0].revents);
|
||||
EXPECT_EQ(POLLNVAL, pfd[1].revents);
|
||||
EXPECT_EQ(POLLWRNORM, pfd[2].revents);
|
||||
}
|
||||
|
||||
TEST_F(sysdeps_poll, duplicate_fd) {
|
||||
adb_pollfd pfd[2] = {};
|
||||
pfd[0].fd = fds[0];
|
||||
pfd[0].events = POLLRDNORM;
|
||||
pfd[1] = pfd[0];
|
||||
|
||||
EXPECT_EQ(0, adb_poll(pfd, 2, 0));
|
||||
EXPECT_EQ(0, pfd[0].revents);
|
||||
EXPECT_EQ(0, pfd[1].revents);
|
||||
|
||||
ASSERT_TRUE(WriteFdExactly(fds[1], "foo", 4));
|
||||
|
||||
EXPECT_EQ(2, adb_poll(pfd, 2, 100));
|
||||
EXPECT_EQ(POLLRDNORM, pfd[0].revents);
|
||||
EXPECT_EQ(POLLRDNORM, pfd[1].revents);
|
||||
}
|
||||
|
||||
TEST_F(sysdeps_poll, disconnect) {
|
||||
adb_pollfd pfd = {};
|
||||
pfd.fd = fds[0];
|
||||
pfd.events = POLLIN;
|
||||
|
||||
EXPECT_EQ(0, adb_poll(&pfd, 1, 0));
|
||||
EXPECT_EQ(0, pfd.revents);
|
||||
|
||||
EXPECT_EQ(0, adb_close(fds[1]));
|
||||
fds[1] = -1;
|
||||
|
||||
EXPECT_EQ(1, adb_poll(&pfd, 1, 100));
|
||||
|
||||
// Linux returns POLLIN | POLLHUP, Windows returns just POLLHUP.
|
||||
EXPECT_EQ(POLLHUP, pfd.revents & POLLHUP);
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -87,8 +87,12 @@ TEST(sysdeps_win32, adb_strerror) {
|
|||
TestAdbStrError(-1, "Unknown error");
|
||||
// Test very big, positive unknown error.
|
||||
TestAdbStrError(1000000, "Unknown error");
|
||||
|
||||
// Test success case.
|
||||
TestAdbStrError(0, "No error");
|
||||
// Wine returns "Success" for strerror(0), Windows returns "No error", so accept both.
|
||||
std::string success = adb_strerror(0);
|
||||
EXPECT_TRUE(success == "Success" || success == "No error") << "strerror(0) = " << success;
|
||||
|
||||
// Test error that regular strerror() should have a string for.
|
||||
TestAdbStrError(EPERM, "Operation not permitted");
|
||||
// Test error that regular strerror() doesn't have a string for, but that
|
||||
|
|
|
|||
|
|
@ -766,6 +766,22 @@ class FileOperationsTest(DeviceTest):
|
|||
if host_dir is not None:
|
||||
shutil.rmtree(host_dir)
|
||||
|
||||
@requires_non_root
|
||||
def test_push_error_reporting(self):
|
||||
"""Make sure that errors that occur while pushing a file get reported
|
||||
|
||||
Bug: http://b/26816782
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile() as tmp_file:
|
||||
tmp_file.write('\0' * 1024 * 1024)
|
||||
tmp_file.flush()
|
||||
try:
|
||||
self.device.push(local=tmp_file.name, remote='/system/')
|
||||
self.fail("push should not have succeeded")
|
||||
except subprocess.CalledProcessError as e:
|
||||
output = e.output
|
||||
|
||||
self.assertIn("Permission denied", output)
|
||||
|
||||
def _test_pull(self, remote_file, checksum):
|
||||
tmp_write = tempfile.NamedTemporaryFile(mode='wb', delete=False)
|
||||
|
|
|
|||
|
|
@ -190,8 +190,7 @@ void send_packet(apacket *p, atransport *t)
|
|||
//
|
||||
// read_transport thread reads data from a transport (representing a usb/tcp connection),
|
||||
// and makes the main thread call handle_packet().
|
||||
static void *read_transport_thread(void *_t)
|
||||
{
|
||||
static void read_transport_thread(void* _t) {
|
||||
atransport *t = reinterpret_cast<atransport*>(_t);
|
||||
apacket *p;
|
||||
|
||||
|
|
@ -244,13 +243,11 @@ oops:
|
|||
D("%s: read_transport thread is exiting", t->serial);
|
||||
kick_transport(t);
|
||||
transport_unref(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// write_transport thread gets packets sent by the main thread (through send_packet()),
|
||||
// and writes to a transport (representing a usb/tcp connection).
|
||||
static void *write_transport_thread(void *_t)
|
||||
{
|
||||
static void write_transport_thread(void* _t) {
|
||||
atransport *t = reinterpret_cast<atransport*>(_t);
|
||||
apacket *p;
|
||||
int active = 0;
|
||||
|
|
@ -295,7 +292,6 @@ static void *write_transport_thread(void *_t)
|
|||
D("%s: write_transport thread is exiting, fd %d", t->serial, t->fd);
|
||||
kick_transport(t);
|
||||
transport_unref(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kick_transport_locked(atransport* t) {
|
||||
|
|
|
|||
|
|
@ -121,8 +121,7 @@ int local_connect_arbitrary_ports(int console_port, int adb_port, std::string* e
|
|||
}
|
||||
|
||||
#if ADB_HOST
|
||||
static void *client_socket_thread(void *x)
|
||||
{
|
||||
static void client_socket_thread(void* x) {
|
||||
adb_thread_setname("client_socket_thread");
|
||||
D("transport: client_socket_thread() starting");
|
||||
while (true) {
|
||||
|
|
@ -135,13 +134,11 @@ static void *client_socket_thread(void *x)
|
|||
}
|
||||
sleep(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else // ADB_HOST
|
||||
|
||||
static void *server_socket_thread(void * arg)
|
||||
{
|
||||
static void server_socket_thread(void* arg) {
|
||||
int serverfd, fd;
|
||||
sockaddr_storage ss;
|
||||
sockaddr *addrp = reinterpret_cast<sockaddr*>(&ss);
|
||||
|
|
@ -174,7 +171,6 @@ static void *server_socket_thread(void * arg)
|
|||
}
|
||||
}
|
||||
D("transport: server_socket_thread() exiting");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is relevant only for ADB daemon running inside the emulator. */
|
||||
|
|
@ -220,14 +216,13 @@ static void *server_socket_thread(void * arg)
|
|||
* the transport registration is completed. That's why we need to send the
|
||||
* 'start' request after the transport is registered.
|
||||
*/
|
||||
static void *qemu_socket_thread(void * arg)
|
||||
{
|
||||
/* 'accept' request to the adb QEMUD service. */
|
||||
static const char _accept_req[] = "accept";
|
||||
/* 'start' request to the adb QEMUD service. */
|
||||
static const char _start_req[] = "start";
|
||||
/* 'ok' reply from the adb QEMUD service. */
|
||||
static const char _ok_resp[] = "ok";
|
||||
static void qemu_socket_thread(void* arg) {
|
||||
/* 'accept' request to the adb QEMUD service. */
|
||||
static const char _accept_req[] = "accept";
|
||||
/* 'start' request to the adb QEMUD service. */
|
||||
static const char _start_req[] = "start";
|
||||
/* 'ok' reply from the adb QEMUD service. */
|
||||
static const char _ok_resp[] = "ok";
|
||||
|
||||
const int port = (int) (uintptr_t) arg;
|
||||
int res, fd;
|
||||
|
|
@ -247,7 +242,7 @@ static const char _ok_resp[] = "ok";
|
|||
* implement adb QEMUD service. Fall back to the old TCP way. */
|
||||
D("adb service is not available. Falling back to TCP socket.");
|
||||
adb_thread_create(server_socket_thread, arg);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
|
|
@ -275,21 +270,21 @@ static const char _ok_resp[] = "ok";
|
|||
fd = qemu_pipe_open(con_name);
|
||||
if (fd < 0) {
|
||||
D("adb service become unavailable.");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
D("Unable to send the '%s' request to ADB service.", _accept_req);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
D("transport: qemu_socket_thread() exiting");
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
#endif // !ADB_HOST
|
||||
|
||||
void local_init(int port)
|
||||
{
|
||||
void* (*func)(void *);
|
||||
adb_thread_func_t func;
|
||||
const char* debug_name = "";
|
||||
|
||||
#if ADB_HOST
|
||||
|
|
|
|||
|
|
@ -571,7 +571,7 @@ static void register_device(const char* dev_name, const char* dev_path,
|
|||
register_usb_transport(done_usb, serial.c_str(), dev_path, done_usb->writeable);
|
||||
}
|
||||
|
||||
static void* device_poll_thread(void* unused) {
|
||||
static void device_poll_thread(void*) {
|
||||
adb_thread_setname("device poll");
|
||||
D("Created device thread");
|
||||
while (true) {
|
||||
|
|
@ -580,7 +580,6 @@ static void* device_poll_thread(void* unused) {
|
|||
kick_disconnected_devices();
|
||||
sleep(1);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void usb_init() {
|
||||
|
|
|
|||
|
|
@ -232,10 +232,7 @@ static const struct {
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void *usb_adb_open_thread(void *x)
|
||||
{
|
||||
static void usb_adb_open_thread(void* x) {
|
||||
struct usb_handle *usb = (struct usb_handle *)x;
|
||||
int fd;
|
||||
|
||||
|
|
@ -270,7 +267,7 @@ static void *usb_adb_open_thread(void *x)
|
|||
}
|
||||
|
||||
// never gets here
|
||||
return 0;
|
||||
abort();
|
||||
}
|
||||
|
||||
static int usb_adb_write(usb_handle *h, const void *data, int len)
|
||||
|
|
@ -434,8 +431,7 @@ err:
|
|||
return;
|
||||
}
|
||||
|
||||
static void *usb_ffs_open_thread(void *x)
|
||||
{
|
||||
static void usb_ffs_open_thread(void* x) {
|
||||
struct usb_handle *usb = (struct usb_handle *)x;
|
||||
|
||||
adb_thread_setname("usb ffs open");
|
||||
|
|
@ -462,7 +458,7 @@ static void *usb_ffs_open_thread(void *x)
|
|||
}
|
||||
|
||||
// never gets here
|
||||
return 0;
|
||||
abort();
|
||||
}
|
||||
|
||||
static int usb_ffs_write(usb_handle* h, const void* data, int len) {
|
||||
|
|
|
|||
|
|
@ -400,9 +400,7 @@ err_get_num_ep:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void* RunLoopThread(void* unused)
|
||||
{
|
||||
static void RunLoopThread(void* unused) {
|
||||
adb_thread_setname("RunLoop");
|
||||
InitUSB();
|
||||
|
||||
|
|
@ -420,7 +418,6 @@ void* RunLoopThread(void* unused)
|
|||
IONotificationPortDestroy(notificationPort);
|
||||
|
||||
LOG(DEBUG) << "RunLoopThread done";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void usb_cleanup() {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ static void kick_devices();
|
|||
|
||||
/// Entry point for thread that polls (every second) for new usb interfaces.
|
||||
/// This routine calls find_devices in infinite loop.
|
||||
void* device_poll_thread(void* unused);
|
||||
static void device_poll_thread(void*);
|
||||
|
||||
/// Initializes this module
|
||||
void usb_init();
|
||||
|
|
@ -172,7 +172,7 @@ int register_new_device(usb_handle* handle) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
void* device_poll_thread(void* unused) {
|
||||
void device_poll_thread(void*) {
|
||||
adb_thread_setname("Device Poll");
|
||||
D("Created device thread");
|
||||
|
||||
|
|
@ -180,8 +180,6 @@ void* device_poll_thread(void* unused) {
|
|||
find_devices();
|
||||
adb_sleep_ms(1000);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||
|
|
@ -203,7 +201,7 @@ static LRESULT CALLBACK _power_window_proc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
|||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static void* _power_notification_thread(void* unused) {
|
||||
static void _power_notification_thread(void*) {
|
||||
// This uses a thread with its own window message pump to get power
|
||||
// notifications. If adb runs from a non-interactive service account, this
|
||||
// might not work (not sure). If that happens to not work, we could use
|
||||
|
|
@ -255,8 +253,6 @@ static void* _power_notification_thread(void* unused) {
|
|||
// shutting down. Not a big deal since the whole process will be going away
|
||||
// soon anyway.
|
||||
D("Power notification thread exiting");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void usb_init() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue