Merge "Clean up CLOEXEC in debuggerd."
diff --git a/adb/Android.mk b/adb/Android.mk
index b792bd4..e0997ea 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -50,6 +50,7 @@
adb_listeners.cpp \
adb_trace.cpp \
adb_utils.cpp \
+ fdevent.cpp \
sockets.cpp \
transport.cpp \
transport_local.cpp \
@@ -58,6 +59,8 @@
LIBADB_TEST_SRCS := \
adb_io_test.cpp \
adb_utils_test.cpp \
+ fdevent_test.cpp \
+ socket_test.cpp \
sysdeps_test.cpp \
transport_test.cpp \
@@ -75,12 +78,10 @@
$(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 \
@@ -88,14 +89,6 @@
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 \
diff --git a/adb/adb_utils.cpp b/adb/adb_utils.cpp
index 8a16e51..26e376c 100644
--- a/adb/adb_utils.cpp
+++ b/adb/adb_utils.cpp
@@ -213,6 +213,7 @@
}
#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) {
diff --git a/adb/fdevent.cpp b/adb/fdevent.cpp
index 386f221..902548e 100644
--- a/adb/fdevent.cpp
+++ b/adb/fdevent.cpp
@@ -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 @@
struct PollNode {
fdevent* fde;
- ::pollfd pollfd;
+ adb_pollfd pollfd;
PollNode(fdevent* fde) : fde(fde) {
memset(&pollfd, 0, sizeof(pollfd));
@@ -72,18 +71,19 @@
// 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 @@
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 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 @@
}
#if !ADB_HOST
+
+#include <sys/ioctl.h>
+
static void fdevent_subproc_event_func(int fd, unsigned ev,
void* /* userdata */)
{
@@ -363,6 +366,10 @@
#endif // !ADB_HOST
while (true) {
+ if (terminate_loop) {
+ return;
+ }
+
D("--- --- waiting for events");
fdevent_process();
@@ -375,6 +382,10 @@
}
}
+void fdevent_terminate_loop() {
+ terminate_loop = true;
+}
+
size_t fdevent_installed_count() {
return g_poll_node_map.size();
}
@@ -383,4 +394,5 @@
g_poll_node_map.clear();
g_pending_list.clear();
main_thread_valid = false;
+ terminate_loop = false;
}
diff --git a/adb/fdevent.h b/adb/fdevent.h
index 657fde5..207f9b7 100644
--- a/adb/fdevent.h
+++ b/adb/fdevent.h
@@ -76,9 +76,9 @@
*/
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
diff --git a/adb/fdevent_test.cpp b/adb/fdevent_test.cpp
index 7fe3d37..c933ed5 100644
--- a/adb/fdevent_test.cpp
+++ b/adb/fdevent_test.cpp
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
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));
}
diff --git a/adb/fdevent_test.h b/adb/fdevent_test.h
new file mode 100644
index 0000000..c853bce
--- /dev/null
+++ b/adb/fdevent_test.h
@@ -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));
+ }
+};
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 51fc143..85aaa61 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -88,7 +88,8 @@
: 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 @@
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 @@
p += sizeof(SyncRequest);
WriteOrDie(lpath, rpath, &buf[0], (p - &buf[0]));
+ expect_done_ = true;
total_bytes_ += data_length;
return true;
}
@@ -220,6 +232,11 @@
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 @@
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 @@
uint64_t expected_total_bytes_;
bool expect_multiple_files_;
+ bool expect_done_;
LinePrinter line_printer_;
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index 29c6629..926dbcf 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -183,8 +183,6 @@
}
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 @@
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 @@
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 @@
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)) {
}
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 38382c1..460e9dc 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -41,25 +41,25 @@
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;
};
diff --git a/adb/services.cpp b/adb/services.cpp
index 75cbe5d..2eef1c2 100644
--- a/adb/services.cpp
+++ b/adb/services.cpp
@@ -49,6 +49,7 @@
#include "remount_service.h"
#include "services.h"
#include "shell_service.h"
+#include "sysdeps.h"
#include "transport.h"
struct stinfo {
@@ -369,12 +370,21 @@
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);
diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp
index 03cab64..471ca09 100644
--- a/adb/socket_test.cpp
+++ b/adb/socket_test.cpp
@@ -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);
- usleep(1000);
+ 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));
+
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 @@
s->peer = cause_close_s;
cause_close_s->ready(cause_close_s);
- InstallDummySocket();
fdevent_loop();
}
@@ -176,21 +145,19 @@
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 @@
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 @@
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 @@
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__)
diff --git a/adb/sysdeps.h b/adb/sysdeps.h
index 3bae09e..7af2979 100644
--- a/adb/sysdeps.h
+++ b/adb/sysdeps.h
@@ -180,6 +180,14 @@
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();
@@ -263,24 +271,6 @@
/* 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 );
@@ -304,6 +294,14 @@
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] == '\\';
}
@@ -456,14 +454,14 @@
#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>
@@ -803,6 +801,13 @@
#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 );
diff --git a/adb/sysdeps_test.cpp b/adb/sysdeps_test.cpp
index 360eaa7..78efea8 100644
--- a/adb/sysdeps_test.cpp
+++ b/adb/sysdeps_test.cpp
@@ -18,6 +18,7 @@
#include <unistd.h>
#include <atomic>
+#include "adb_io.h"
#include "sysdeps.h"
static void increment_atomic_int(void* c) {
@@ -67,3 +68,150 @@
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);
+}
diff --git a/adb/sysdeps_win32.cpp b/adb/sysdeps_win32.cpp
index 0b08981..7eae186 100644
--- a/adb/sysdeps_win32.cpp
+++ b/adb/sysdeps_win32.cpp
@@ -29,6 +29,7 @@
#include <memory>
#include <string>
#include <unordered_map>
+#include <vector>
#include <cutils/sockets.h>
@@ -39,6 +40,7 @@
#include <android-base/utf8.h>
#include "adb.h"
+#include "adb_utils.h"
extern void fatal(const char *fmt, ...);
@@ -54,7 +56,6 @@
int (*_fh_lseek)(FH, int, int);
int (*_fh_read)(FH, void*, int);
int (*_fh_write)(FH, const void*, int);
- void (*_fh_hook)(FH, int, EventHook);
} FHClassRec;
static void _fh_file_init(FH);
@@ -62,7 +63,6 @@
static int _fh_file_lseek(FH, int, int);
static int _fh_file_read(FH, void*, int);
static int _fh_file_write(FH, const void*, int);
-static void _fh_file_hook(FH, int, EventHook);
static const FHClassRec _fh_file_class = {
_fh_file_init,
@@ -70,7 +70,6 @@
_fh_file_lseek,
_fh_file_read,
_fh_file_write,
- _fh_file_hook
};
static void _fh_socket_init(FH);
@@ -78,7 +77,6 @@
static int _fh_socket_lseek(FH, int, int);
static int _fh_socket_read(FH, void*, int);
static int _fh_socket_write(FH, const void*, int);
-static void _fh_socket_hook(FH, int, EventHook);
static const FHClassRec _fh_socket_class = {
_fh_socket_init,
@@ -86,7 +84,6 @@
_fh_socket_lseek,
_fh_socket_read,
_fh_socket_write,
- _fh_socket_hook
};
#define assert(cond) \
@@ -174,9 +171,6 @@
/**************************************************************************/
/**************************************************************************/
-/* used to emulate unix-domain socket pairs */
-typedef struct SocketPairRec_* SocketPair;
-
typedef struct FHRec_
{
FHClass clazz;
@@ -185,10 +179,8 @@
union {
HANDLE handle;
SOCKET socket;
- SocketPair pair;
} u;
- HANDLE event;
int mask;
char name[32];
@@ -197,10 +189,8 @@
#define fh_handle u.handle
#define fh_socket u.socket
-#define fh_pair u.pair
-#define WIN32_FH_BASE 100
-
+#define WIN32_FH_BASE 2048
#define WIN32_MAX_FHS 128
static adb_mutex_t _win32_lock;
@@ -250,17 +240,10 @@
adb_mutex_lock( &_win32_lock );
- // Search entire array, starting from _win32_fh_next.
- for (int nn = 0; nn < WIN32_MAX_FHS; nn++) {
- // Keep incrementing _win32_fh_next to avoid giving out an index that
- // was recently closed, to try to avoid use-after-free.
- const int index = _win32_fh_next++;
- // Handle wrap-around of _win32_fh_next.
- if (_win32_fh_next == WIN32_MAX_FHS) {
- _win32_fh_next = 0;
- }
- if (_win32_fhs[index].clazz == NULL) {
- f = &_win32_fhs[index];
+ for (int i = _win32_fh_next; i < WIN32_MAX_FHS; ++i) {
+ if (_win32_fhs[i].clazz == NULL) {
+ f = &_win32_fhs[i];
+ _win32_fh_next = i + 1;
goto Exit;
}
}
@@ -285,6 +268,12 @@
// Use lock so that closing only happens once and so that _fh_alloc can't
// allocate a FH that we're in the middle of closing.
adb_mutex_lock(&_win32_lock);
+
+ int offset = f - _win32_fhs;
+ if (_win32_fh_next > offset) {
+ _win32_fh_next = offset;
+ }
+
if (f->used) {
f->clazz->_fh_close( f );
f->name[0] = '\0';
@@ -672,19 +661,56 @@
}
}
-static void _fh_socket_init( FH f ) {
- f->fh_socket = INVALID_SOCKET;
- f->event = WSACreateEvent();
- if (f->event == WSA_INVALID_EVENT) {
- D("WSACreateEvent failed: %s",
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
-
- // _event_socket_start assumes that this field is INVALID_HANDLE_VALUE
- // on failure, instead of NULL which is what Windows really returns on
- // error. It might be better to change all the other code to look for
- // NULL, but that is a much riskier change.
- f->event = INVALID_HANDLE_VALUE;
+extern int adb_poll(adb_pollfd* fds, size_t nfds, int timeout) {
+ // WSAPoll doesn't handle invalid/non-socket handles, so we need to handle them ourselves.
+ int skipped = 0;
+ std::vector<WSAPOLLFD> sockets;
+ std::vector<adb_pollfd*> original;
+ for (size_t i = 0; i < nfds; ++i) {
+ FH fh = _fh_from_int(fds[i].fd, __func__);
+ if (!fh || !fh->used || fh->clazz != &_fh_socket_class) {
+ D("adb_poll received bad FD %d", fds[i].fd);
+ fds[i].revents = POLLNVAL;
+ ++skipped;
+ } else {
+ WSAPOLLFD wsapollfd = {
+ .fd = fh->u.socket,
+ .events = static_cast<short>(fds[i].events)
+ };
+ sockets.push_back(wsapollfd);
+ original.push_back(&fds[i]);
+ }
}
+
+ if (sockets.empty()) {
+ return skipped;
+ }
+
+ int result = WSAPoll(sockets.data(), sockets.size(), timeout);
+ if (result == SOCKET_ERROR) {
+ _socket_set_errno(WSAGetLastError());
+ return -1;
+ }
+
+ // Map the results back onto the original set.
+ for (size_t i = 0; i < sockets.size(); ++i) {
+ original[i]->revents = sockets[i].revents;
+ }
+
+ // WSAPoll appears to return the number of unique FDs with avaiable events, instead of how many
+ // of the pollfd elements have a non-zero revents field, which is what it and poll are specified
+ // to do. Ignore its result and calculate the proper return value.
+ result = 0;
+ for (size_t i = 0; i < nfds; ++i) {
+ if (fds[i].revents != 0) {
+ ++result;
+ }
+ }
+ return result;
+}
+
+static void _fh_socket_init(FH f) {
+ f->fh_socket = INVALID_SOCKET;
f->mask = 0;
}
@@ -700,18 +726,12 @@
#endif
}
if (closesocket(f->fh_socket) == SOCKET_ERROR) {
- D("closesocket failed: %s",
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
+ // Don't set errno here, since adb_close will ignore it.
+ const DWORD err = WSAGetLastError();
+ D("closesocket failed: %s", android::base::SystemErrorCodeToString(err).c_str());
}
f->fh_socket = INVALID_SOCKET;
}
- if (f->event != NULL) {
- if (!CloseHandle(f->event)) {
- D("CloseHandle failed: %s",
- android::base::SystemErrorCodeToString(GetLastError()).c_str());
- }
- f->event = NULL;
- }
f->mask = 0;
return 0;
}
@@ -820,16 +840,15 @@
int network_loopback_client(int port, int type, std::string* error) {
struct sockaddr_in addr;
- SOCKET s;
+ SOCKET s;
- unique_fh f(_fh_alloc(&_fh_socket_class));
+ unique_fh f(_fh_alloc(&_fh_socket_class));
if (!f) {
*error = strerror(errno);
return -1;
}
- if (!_winsock_init)
- _init_winsock();
+ if (!_winsock_init) _init_winsock();
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
@@ -837,30 +856,32 @@
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
s = socket(AF_INET, type, GetSocketProtocolFromSocketType(type));
- if(s == INVALID_SOCKET) {
+ if (s == INVALID_SOCKET) {
+ const DWORD err = WSAGetLastError();
*error = android::base::StringPrintf("cannot create socket: %s",
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
+ android::base::SystemErrorCodeToString(err).c_str());
D("%s", error->c_str());
+ _socket_set_errno(err);
return -1;
}
f->fh_socket = s;
- if(connect(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
+ if (connect(s, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
// Save err just in case inet_ntoa() or ntohs() changes the last error.
const DWORD err = WSAGetLastError();
*error = android::base::StringPrintf("cannot connect to %s:%u: %s",
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
- android::base::SystemErrorCodeToString(err).c_str());
- D("could not connect to %s:%d: %s",
- type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
+ inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
+ android::base::SystemErrorCodeToString(err).c_str());
+ D("could not connect to %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port,
+ error->c_str());
+ _socket_set_errno(err);
return -1;
}
const int fd = _fh_to_int(f.get());
- snprintf( f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd,
- type != SOCK_STREAM ? "udp:" : "", port );
- D( "port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp",
- fd );
+ snprintf(f->name, sizeof(f->name), "%d(lo-client:%s%d)", fd, type != SOCK_STREAM ? "udp:" : "",
+ port);
+ D("port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp", fd);
f.release();
return fd;
}
@@ -868,20 +889,18 @@
#define LISTEN_BACKLOG 4
// interface_address is INADDR_LOOPBACK or INADDR_ANY.
-static int _network_server(int port, int type, u_long interface_address,
- std::string* error) {
+static int _network_server(int port, int type, u_long interface_address, std::string* error) {
struct sockaddr_in addr;
- SOCKET s;
- int n;
+ SOCKET s;
+ int n;
- unique_fh f(_fh_alloc(&_fh_socket_class));
+ unique_fh f(_fh_alloc(&_fh_socket_class));
if (!f) {
*error = strerror(errno);
return -1;
}
- if (!_winsock_init)
- _init_winsock();
+ if (!_winsock_init) _init_winsock();
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
@@ -892,9 +911,11 @@
// IPv4 and IPv6.
s = socket(AF_INET, type, GetSocketProtocolFromSocketType(type));
if (s == INVALID_SOCKET) {
+ const DWORD err = WSAGetLastError();
*error = android::base::StringPrintf("cannot create socket: %s",
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
+ android::base::SystemErrorCodeToString(err).c_str());
D("%s", error->c_str());
+ _socket_set_errno(err);
return -1;
}
@@ -903,40 +924,41 @@
// Note: SO_REUSEADDR on Windows allows multiple processes to bind to the
// same port, so instead use SO_EXCLUSIVEADDRUSE.
n = 1;
- if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n,
- sizeof(n)) == SOCKET_ERROR) {
- *error = android::base::StringPrintf(
- "cannot set socket option SO_EXCLUSIVEADDRUSE: %s",
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
+ if (setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&n, sizeof(n)) == SOCKET_ERROR) {
+ const DWORD err = WSAGetLastError();
+ *error = android::base::StringPrintf("cannot set socket option SO_EXCLUSIVEADDRUSE: %s",
+ android::base::SystemErrorCodeToString(err).c_str());
D("%s", error->c_str());
+ _socket_set_errno(err);
return -1;
}
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) == SOCKET_ERROR) {
+ if (bind(s, (struct sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) {
// Save err just in case inet_ntoa() or ntohs() changes the last error.
const DWORD err = WSAGetLastError();
- *error = android::base::StringPrintf("cannot bind to %s:%u: %s",
- inet_ntoa(addr.sin_addr), ntohs(addr.sin_port),
- android::base::SystemErrorCodeToString(err).c_str());
- D("could not bind to %s:%d: %s",
- type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
+ *error = android::base::StringPrintf("cannot bind to %s:%u: %s", inet_ntoa(addr.sin_addr),
+ ntohs(addr.sin_port),
+ android::base::SystemErrorCodeToString(err).c_str());
+ D("could not bind to %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
+ _socket_set_errno(err);
return -1;
}
if (type == SOCK_STREAM) {
if (listen(s, LISTEN_BACKLOG) == SOCKET_ERROR) {
- *error = android::base::StringPrintf("cannot listen on socket: %s",
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
- D("could not listen on %s:%d: %s",
- type != SOCK_STREAM ? "udp" : "tcp", port, error->c_str());
+ const DWORD err = WSAGetLastError();
+ *error = android::base::StringPrintf(
+ "cannot listen on socket: %s", android::base::SystemErrorCodeToString(err).c_str());
+ D("could not listen on %s:%d: %s", type != SOCK_STREAM ? "udp" : "tcp", port,
+ error->c_str());
+ _socket_set_errno(err);
return -1;
}
}
const int fd = _fh_to_int(f.get());
- snprintf( f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd,
- interface_address == INADDR_LOOPBACK ? "lo" : "any",
- type != SOCK_STREAM ? "udp:" : "", port );
- D( "port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp",
- fd );
+ snprintf(f->name, sizeof(f->name), "%d(%s-server:%s%d)", fd,
+ interface_address == INADDR_LOOPBACK ? "lo" : "any", type != SOCK_STREAM ? "udp:" : "",
+ port);
+ D("port %d type %s => fd %d", port, type != SOCK_STREAM ? "udp" : "tcp", fd);
f.release();
return fd;
}
@@ -970,54 +992,57 @@
struct addrinfo* addrinfo_ptr = nullptr;
#if (NTDDI_VERSION >= NTDDI_WINXPSP2) || (_WIN32_WINNT >= _WIN32_WINNT_WS03)
- // TODO: When the Android SDK tools increases the Windows system
- // requirements >= WinXP SP2, switch to android::base::UTF8ToWide() + GetAddrInfoW().
+// TODO: When the Android SDK tools increases the Windows system
+// requirements >= WinXP SP2, switch to android::base::UTF8ToWide() + GetAddrInfoW().
#else
- // Otherwise, keep using getaddrinfo(), or do runtime API detection
- // with GetProcAddress("GetAddrInfoW").
+// Otherwise, keep using getaddrinfo(), or do runtime API detection
+// with GetProcAddress("GetAddrInfoW").
#endif
if (getaddrinfo(host.c_str(), port_str, &hints, &addrinfo_ptr) != 0) {
- *error = android::base::StringPrintf(
- "cannot resolve host '%s' and port %s: %s", host.c_str(),
- port_str, android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
+ const DWORD err = WSAGetLastError();
+ *error = android::base::StringPrintf("cannot resolve host '%s' and port %s: %s",
+ host.c_str(), port_str,
+ android::base::SystemErrorCodeToString(err).c_str());
+
D("%s", error->c_str());
+ _socket_set_errno(err);
return -1;
}
- std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*>
- addrinfo(addrinfo_ptr, freeaddrinfo);
+ std::unique_ptr<struct addrinfo, decltype(freeaddrinfo)*> addrinfo(addrinfo_ptr, freeaddrinfo);
addrinfo_ptr = nullptr;
// TODO: Try all the addresses if there's more than one? This just uses
// the first. Or, could call WSAConnectByName() (Windows Vista and newer)
// which tries all addresses, takes a timeout and more.
- SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype,
- addrinfo->ai_protocol);
- if(s == INVALID_SOCKET) {
+ SOCKET s = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
+ if (s == INVALID_SOCKET) {
+ const DWORD err = WSAGetLastError();
*error = android::base::StringPrintf("cannot create socket: %s",
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
+ android::base::SystemErrorCodeToString(err).c_str());
D("%s", error->c_str());
+ _socket_set_errno(err);
return -1;
}
f->fh_socket = s;
// TODO: Implement timeouts for Windows. Seems like the default in theory
// (according to http://serverfault.com/a/671453) and in practice is 21 sec.
- if(connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) {
+ if (connect(s, addrinfo->ai_addr, addrinfo->ai_addrlen) == SOCKET_ERROR) {
// TODO: Use WSAAddressToString or inet_ntop on address.
- *error = android::base::StringPrintf("cannot connect to %s:%s: %s",
- host.c_str(), port_str,
- android::base::SystemErrorCodeToString(WSAGetLastError()).c_str());
- D("could not connect to %s:%s:%s: %s",
- type != SOCK_STREAM ? "udp" : "tcp", host.c_str(), port_str,
- error->c_str());
+ const DWORD err = WSAGetLastError();
+ *error = android::base::StringPrintf("cannot connect to %s:%s: %s", host.c_str(), port_str,
+ android::base::SystemErrorCodeToString(err).c_str());
+ D("could not connect to %s:%s:%s: %s", type != SOCK_STREAM ? "udp" : "tcp", host.c_str(),
+ port_str, error->c_str());
+ _socket_set_errno(err);
return -1;
}
const int fd = _fh_to_int(f.get());
- snprintf( f->name, sizeof(f->name), "%d(net-client:%s%d)", fd,
- type != SOCK_STREAM ? "udp:" : "", port );
- D( "host '%s' port %d type %s => fd %d", host.c_str(), port,
- type != SOCK_STREAM ? "udp" : "tcp", fd );
+ snprintf(f->name, sizeof(f->name), "%d(net-client:%s%d)", fd, type != SOCK_STREAM ? "udp:" : "",
+ port);
+ D("host '%s' port %d type %s => fd %d", host.c_str(), port, type != SOCK_STREAM ? "udp" : "tcp",
+ fd);
f.release();
return fd;
}
@@ -1083,6 +1108,25 @@
return result;
}
+int adb_getsockname(int fd, struct sockaddr* sockaddr, socklen_t* optlen) {
+ FH fh = _fh_from_int(fd, __func__);
+
+ if (!fh || fh->clazz != &_fh_socket_class) {
+ D("adb_getsockname: invalid fd %d", fd);
+ errno = EBADF;
+ return -1;
+ }
+
+ int result = getsockname(fh->fh_socket, sockaddr, optlen);
+ if (result == SOCKET_ERROR) {
+ const DWORD err = WSAGetLastError();
+ D("adb_getsockname: setsockopt on fd %d failed: %s\n", fd,
+ android::base::SystemErrorCodeToString(err).c_str());
+ _socket_set_errno(err);
+ result = -1;
+ }
+ return result;
+}
int adb_shutdown(int fd)
{
@@ -1105,1352 +1149,85 @@
return 0;
}
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
-/***** emulated socketpairs *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
+// Emulate socketpair(2) by binding and connecting to a socket.
+int adb_socketpair(int sv[2]) {
+ int server = -1;
+ int client = -1;
+ int accepted = -1;
+ sockaddr_storage addr_storage;
+ socklen_t addr_len = sizeof(addr_storage);
+ sockaddr_in* addr = nullptr;
+ std::string error;
-/* we implement socketpairs directly in use space for the following reasons:
- * - it avoids copying data from/to the Nt kernel
- * - it allows us to implement fdevent hooks easily and cheaply, something
- * that is not possible with standard Win32 pipes !!
- *
- * basically, we use two circular buffers, each one corresponding to a given
- * direction.
- *
- * each buffer is implemented as two regions:
- *
- * region A which is (a_start,a_end)
- * region B which is (0, b_end) with b_end <= a_start
- *
- * an empty buffer has: a_start = a_end = b_end = 0
- *
- * a_start is the pointer where we start reading data
- * a_end is the pointer where we start writing data, unless it is BUFFER_SIZE,
- * then you start writing at b_end
- *
- * the buffer is full when b_end == a_start && a_end == BUFFER_SIZE
- *
- * there is room when b_end < a_start || a_end < BUFER_SIZE
- *
- * when reading, a_start is incremented, it a_start meets a_end, then
- * we do: a_start = 0, a_end = b_end, b_end = 0, and keep going on..
- */
-
-#define BIP_BUFFER_SIZE 4096
-
-#if 0
-#include <stdio.h>
-# define BIPD(x) D x
-# define BIPDUMP bip_dump_hex
-
-static void bip_dump_hex( const unsigned char* ptr, size_t len )
-{
- int nn, len2 = len;
-
- if (len2 > 8) len2 = 8;
-
- for (nn = 0; nn < len2; nn++)
- printf("%02x", ptr[nn]);
- printf(" ");
-
- for (nn = 0; nn < len2; nn++) {
- int c = ptr[nn];
- if (c < 32 || c > 127)
- c = '.';
- printf("%c", c);
- }
- printf("\n");
- fflush(stdout);
-}
-
-#else
-# define BIPD(x) do {} while (0)
-# define BIPDUMP(p,l) BIPD(p)
-#endif
-
-typedef struct BipBufferRec_
-{
- int a_start;
- int a_end;
- int b_end;
- int fdin;
- int fdout;
- int closed;
- int can_write; /* boolean */
- HANDLE evt_write; /* event signaled when one can write to a buffer */
- int can_read; /* boolean */
- HANDLE evt_read; /* event signaled when one can read from a buffer */
- CRITICAL_SECTION lock;
- unsigned char buff[ BIP_BUFFER_SIZE ];
-
-} BipBufferRec, *BipBuffer;
-
-static void
-bip_buffer_init( BipBuffer buffer )
-{
- D( "bit_buffer_init %p", buffer );
- buffer->a_start = 0;
- buffer->a_end = 0;
- buffer->b_end = 0;
- buffer->can_write = 1;
- buffer->can_read = 0;
- buffer->fdin = 0;
- buffer->fdout = 0;
- buffer->closed = 0;
- buffer->evt_write = CreateEvent( NULL, TRUE, TRUE, NULL );
- buffer->evt_read = CreateEvent( NULL, TRUE, FALSE, NULL );
- InitializeCriticalSection( &buffer->lock );
-}
-
-static void
-bip_buffer_close( BipBuffer bip )
-{
- bip->closed = 1;
-
- if (!bip->can_read) {
- SetEvent( bip->evt_read );
- }
- if (!bip->can_write) {
- SetEvent( bip->evt_write );
- }
-}
-
-static void
-bip_buffer_done( BipBuffer bip )
-{
- BIPD(( "bip_buffer_done: %d->%d", bip->fdin, bip->fdout ));
- CloseHandle( bip->evt_read );
- CloseHandle( bip->evt_write );
- DeleteCriticalSection( &bip->lock );
-}
-
-static int
-bip_buffer_write( BipBuffer bip, const void* src, int len )
-{
- int avail, count = 0;
-
- if (len <= 0)
- return 0;
-
- BIPD(( "bip_buffer_write: enter %d->%d len %d", bip->fdin, bip->fdout, len ));
- BIPDUMP( src, len );
-
- if (bip->closed) {
- errno = EPIPE;
- return -1;
+ server = network_loopback_server(0, SOCK_STREAM, &error);
+ if (server < 0) {
+ D("adb_socketpair: failed to create server: %s", error.c_str());
+ goto fail;
}
- EnterCriticalSection( &bip->lock );
-
- while (!bip->can_write) {
- int ret;
- LeaveCriticalSection( &bip->lock );
-
- if (bip->closed) {
- errno = EPIPE;
- return -1;
- }
- /* spinlocking here is probably unfair, but let's live with it */
- ret = WaitForSingleObject( bip->evt_write, INFINITE );
- if (ret != WAIT_OBJECT_0) { /* buffer probably closed */
- D( "bip_buffer_write: error %d->%d WaitForSingleObject returned %d, error %ld", bip->fdin, bip->fdout, ret, GetLastError() );
- return 0;
- }
- if (bip->closed) {
- errno = EPIPE;
- return -1;
- }
- EnterCriticalSection( &bip->lock );
+ if (adb_getsockname(server, reinterpret_cast<sockaddr*>(&addr_storage), &addr_len) < 0) {
+ D("adb_socketpair: adb_getsockname failed: %s", strerror(errno));
+ goto fail;
}
- BIPD(( "bip_buffer_write: exec %d->%d len %d", bip->fdin, bip->fdout, len ));
-
- avail = BIP_BUFFER_SIZE - bip->a_end;
- if (avail > 0)
- {
- /* we can append to region A */
- if (avail > len)
- avail = len;
-
- memcpy( bip->buff + bip->a_end, src, avail );
- src = (const char *)src + avail;
- count += avail;
- len -= avail;
-
- bip->a_end += avail;
- if (bip->a_end == BIP_BUFFER_SIZE && bip->a_start == 0) {
- bip->can_write = 0;
- ResetEvent( bip->evt_write );
- goto Exit;
- }
+ if (addr_storage.ss_family != AF_INET) {
+ D("adb_socketpair: unknown address family received: %d", addr_storage.ss_family);
+ errno = ECONNABORTED;
+ goto fail;
}
- if (len == 0)
- goto Exit;
-
- avail = bip->a_start - bip->b_end;
- assert( avail > 0 ); /* since can_write is TRUE */
-
- if (avail > len)
- avail = len;
-
- memcpy( bip->buff + bip->b_end, src, avail );
- count += avail;
- bip->b_end += avail;
-
- if (bip->b_end == bip->a_start) {
- bip->can_write = 0;
- ResetEvent( bip->evt_write );
+ addr = reinterpret_cast<sockaddr_in*>(&addr_storage);
+ D("adb_socketpair: bound on port %d", ntohs(addr->sin_port));
+ client = network_loopback_client(ntohs(addr->sin_port), SOCK_STREAM, &error);
+ if (client < 0) {
+ D("adb_socketpair: failed to connect client: %s", error.c_str());
+ goto fail;
}
-Exit:
- assert( count > 0 );
-
- if ( !bip->can_read ) {
- bip->can_read = 1;
- SetEvent( bip->evt_read );
+ accepted = adb_socket_accept(server, nullptr, nullptr);
+ if (accepted < 0) {
+ D("adb_socketpair: failed to accept: %s", strerror(errno));
+ goto fail;
}
-
- BIPD(( "bip_buffer_write: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d",
- bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
- LeaveCriticalSection( &bip->lock );
-
- return count;
- }
-
-static int
-bip_buffer_read( BipBuffer bip, void* dst, int len )
-{
- int avail, count = 0;
-
- if (len <= 0)
- return 0;
-
- BIPD(( "bip_buffer_read: enter %d->%d len %d", bip->fdin, bip->fdout, len ));
-
- EnterCriticalSection( &bip->lock );
- while ( !bip->can_read )
- {
-#if 0
- LeaveCriticalSection( &bip->lock );
- errno = EAGAIN;
- return -1;
-#else
- int ret;
- LeaveCriticalSection( &bip->lock );
-
- if (bip->closed) {
- errno = EPIPE;
- return -1;
- }
-
- ret = WaitForSingleObject( bip->evt_read, INFINITE );
- if (ret != WAIT_OBJECT_0) { /* probably closed buffer */
- D( "bip_buffer_read: error %d->%d WaitForSingleObject returned %d, error %ld", bip->fdin, bip->fdout, ret, GetLastError());
- return 0;
- }
- if (bip->closed) {
- errno = EPIPE;
- return -1;
- }
- EnterCriticalSection( &bip->lock );
-#endif
- }
-
- BIPD(( "bip_buffer_read: exec %d->%d len %d", bip->fdin, bip->fdout, len ));
-
- avail = bip->a_end - bip->a_start;
- assert( avail > 0 ); /* since can_read is TRUE */
-
- if (avail > len)
- avail = len;
-
- memcpy( dst, bip->buff + bip->a_start, avail );
- dst = (char *)dst + avail;
- count += avail;
- len -= avail;
-
- bip->a_start += avail;
- if (bip->a_start < bip->a_end)
- goto Exit;
-
- bip->a_start = 0;
- bip->a_end = bip->b_end;
- bip->b_end = 0;
-
- avail = bip->a_end;
- if (avail > 0) {
- if (avail > len)
- avail = len;
- memcpy( dst, bip->buff, avail );
- count += avail;
- bip->a_start += avail;
-
- if ( bip->a_start < bip->a_end )
- goto Exit;
-
- bip->a_start = bip->a_end = 0;
- }
-
- bip->can_read = 0;
- ResetEvent( bip->evt_read );
-
-Exit:
- assert( count > 0 );
-
- if (!bip->can_write ) {
- bip->can_write = 1;
- SetEvent( bip->evt_write );
- }
-
- BIPDUMP( (const unsigned char*)dst - count, count );
- BIPD(( "bip_buffer_read: exit %d->%d count %d (as=%d ae=%d be=%d cw=%d cr=%d",
- bip->fdin, bip->fdout, count, bip->a_start, bip->a_end, bip->b_end, bip->can_write, bip->can_read ));
- LeaveCriticalSection( &bip->lock );
-
- return count;
-}
-
-typedef struct SocketPairRec_
-{
- BipBufferRec a2b_bip;
- BipBufferRec b2a_bip;
- FH a_fd;
- int used;
-
-} SocketPairRec;
-
-void _fh_socketpair_init( FH f )
-{
- f->fh_pair = NULL;
-}
-
-static int
-_fh_socketpair_close( FH f )
-{
- if ( f->fh_pair ) {
- SocketPair pair = f->fh_pair;
-
- if ( f == pair->a_fd ) {
- pair->a_fd = NULL;
- }
-
- bip_buffer_close( &pair->b2a_bip );
- bip_buffer_close( &pair->a2b_bip );
-
- if ( --pair->used == 0 ) {
- bip_buffer_done( &pair->b2a_bip );
- bip_buffer_done( &pair->a2b_bip );
- free( pair );
- }
- f->fh_pair = NULL;
- }
+ adb_close(server);
+ sv[0] = client;
+ sv[1] = accepted;
return 0;
-}
-static int
-_fh_socketpair_lseek( FH f, int pos, int origin )
-{
- errno = ESPIPE;
+fail:
+ if (server >= 0) {
+ adb_close(server);
+ }
+ if (client >= 0) {
+ adb_close(client);
+ }
+ if (accepted >= 0) {
+ adb_close(accepted);
+ }
return -1;
}
-static int
-_fh_socketpair_read( FH f, void* buf, int len )
-{
- SocketPair pair = f->fh_pair;
- BipBuffer bip;
+bool set_file_block_mode(int fd, bool block) {
+ FH fh = _fh_from_int(fd, __func__);
- if (!pair)
- return -1;
-
- if ( f == pair->a_fd )
- bip = &pair->b2a_bip;
- else
- bip = &pair->a2b_bip;
-
- return bip_buffer_read( bip, buf, len );
-}
-
-static int
-_fh_socketpair_write( FH f, const void* buf, int len )
-{
- SocketPair pair = f->fh_pair;
- BipBuffer bip;
-
- if (!pair)
- return -1;
-
- if ( f == pair->a_fd )
- bip = &pair->a2b_bip;
- else
- bip = &pair->b2a_bip;
-
- return bip_buffer_write( bip, buf, len );
-}
-
-
-static void _fh_socketpair_hook( FH f, int event, EventHook hook ); /* forward */
-
-static const FHClassRec _fh_socketpair_class =
-{
- _fh_socketpair_init,
- _fh_socketpair_close,
- _fh_socketpair_lseek,
- _fh_socketpair_read,
- _fh_socketpair_write,
- _fh_socketpair_hook
-};
-
-
-int adb_socketpair(int sv[2]) {
- SocketPair pair;
-
- unique_fh fa(_fh_alloc(&_fh_socketpair_class));
- if (!fa) {
- return -1;
- }
- unique_fh fb(_fh_alloc(&_fh_socketpair_class));
- if (!fb) {
- return -1;
+ if (!fh || !fh->used) {
+ errno = EBADF;
+ return false;
}
- pair = reinterpret_cast<SocketPair>(malloc(sizeof(*pair)));
- if (pair == NULL) {
- D("adb_socketpair: not enough memory to allocate pipes" );
- return -1;
- }
-
- bip_buffer_init( &pair->a2b_bip );
- bip_buffer_init( &pair->b2a_bip );
-
- fa->fh_pair = pair;
- fb->fh_pair = pair;
- pair->used = 2;
- pair->a_fd = fa.get();
-
- sv[0] = _fh_to_int(fa.get());
- sv[1] = _fh_to_int(fb.get());
-
- pair->a2b_bip.fdin = sv[0];
- pair->a2b_bip.fdout = sv[1];
- pair->b2a_bip.fdin = sv[1];
- pair->b2a_bip.fdout = sv[0];
-
- snprintf( fa->name, sizeof(fa->name), "%d(pair:%d)", sv[0], sv[1] );
- snprintf( fb->name, sizeof(fb->name), "%d(pair:%d)", sv[1], sv[0] );
- D( "adb_socketpair: returns (%d, %d)", sv[0], sv[1] );
- fa.release();
- fb.release();
- return 0;
-}
-
-/**************************************************************************/
-/**************************************************************************/
-/***** *****/
-/***** fdevents emulation *****/
-/***** *****/
-/***** this is a very simple implementation, we rely on the fact *****/
-/***** that ADB doesn't use FDE_ERROR. *****/
-/***** *****/
-/**************************************************************************/
-/**************************************************************************/
-
-#define FATAL(fmt, ...) fatal("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
-
-#if DEBUG
-static void dump_fde(fdevent *fde, const char *info)
-{
- fprintf(stderr,"FDE #%03d %c%c%c %s\n", fde->fd,
- fde->state & FDE_READ ? 'R' : ' ',
- fde->state & FDE_WRITE ? 'W' : ' ',
- fde->state & FDE_ERROR ? 'E' : ' ',
- info);
-}
-#else
-#define dump_fde(fde, info) do { } while(0)
-#endif
-
-#define FDE_EVENTMASK 0x00ff
-#define FDE_STATEMASK 0xff00
-
-#define FDE_ACTIVE 0x0100
-#define FDE_PENDING 0x0200
-#define FDE_CREATED 0x0400
-
-static void fdevent_plist_enqueue(fdevent *node);
-static void fdevent_plist_remove(fdevent *node);
-static fdevent *fdevent_plist_dequeue(void);
-
-static fdevent list_pending = {
- .next = &list_pending,
- .prev = &list_pending,
-};
-
-static fdevent **fd_table = 0;
-static int fd_table_max = 0;
-
-typedef struct EventLooperRec_* EventLooper;
-
-typedef struct EventHookRec_
-{
- EventHook next;
- FH fh;
- HANDLE h;
- int wanted; /* wanted event flags */
- int ready; /* ready event flags */
- void* aux;
- void (*prepare)( EventHook hook );
- int (*start) ( EventHook hook );
- void (*stop) ( EventHook hook );
- int (*check) ( EventHook hook );
- int (*peek) ( EventHook hook );
-} EventHookRec;
-
-static EventHook _free_hooks;
-
-static EventHook
-event_hook_alloc(FH fh) {
- EventHook hook = _free_hooks;
- if (hook != NULL) {
- _free_hooks = hook->next;
+ if (fh->clazz == &_fh_socket_class) {
+ u_long x = !block;
+ if (ioctlsocket(fh->u.socket, FIONBIO, &x) != 0) {
+ _socket_set_errno(WSAGetLastError());
+ return false;
+ }
+ return true;
} else {
- hook = reinterpret_cast<EventHook>(malloc(sizeof(*hook)));
- if (hook == NULL)
- fatal( "could not allocate event hook\n" );
- }
- hook->next = NULL;
- hook->fh = fh;
- hook->wanted = 0;
- hook->ready = 0;
- hook->h = INVALID_HANDLE_VALUE;
- hook->aux = NULL;
-
- hook->prepare = NULL;
- hook->start = NULL;
- hook->stop = NULL;
- hook->check = NULL;
- hook->peek = NULL;
-
- return hook;
-}
-
-static void
-event_hook_free( EventHook hook )
-{
- hook->fh = NULL;
- hook->wanted = 0;
- hook->ready = 0;
- hook->next = _free_hooks;
- _free_hooks = hook;
-}
-
-
-static void
-event_hook_signal( EventHook hook )
-{
- FH f = hook->fh;
- int fd = _fh_to_int(f);
- fdevent* fde = fd_table[ fd - WIN32_FH_BASE ];
-
- if (fde != NULL && fde->fd == fd) {
- if ((fde->state & FDE_PENDING) == 0) {
- fde->state |= FDE_PENDING;
- fdevent_plist_enqueue( fde );
- }
- fde->events |= hook->wanted;
+ errno = ENOTSOCK;
+ return false;
}
}
-
-#define MAX_LOOPER_HANDLES WIN32_MAX_FHS
-
-typedef struct EventLooperRec_
-{
- EventHook hooks;
- HANDLE htab[ MAX_LOOPER_HANDLES ];
- int htab_count;
-
-} EventLooperRec;
-
-static EventHook*
-event_looper_find_p( EventLooper looper, FH fh )
-{
- EventHook *pnode = &looper->hooks;
- EventHook node = *pnode;
- for (;;) {
- if ( node == NULL || node->fh == fh )
- break;
- pnode = &node->next;
- node = *pnode;
- }
- return pnode;
-}
-
-static void
-event_looper_hook( EventLooper looper, int fd, int events )
-{
- FH f = _fh_from_int(fd, __func__);
- EventHook *pnode;
- EventHook node;
-
- if (f == NULL) /* invalid arg */ {
- D("event_looper_hook: invalid fd=%d", fd);
- return;
- }
-
- pnode = event_looper_find_p( looper, f );
- node = *pnode;
- if ( node == NULL ) {
- node = event_hook_alloc( f );
- node->next = *pnode;
- *pnode = node;
- }
-
- if ( (node->wanted & events) != events ) {
- /* this should update start/stop/check/peek */
- D("event_looper_hook: call hook for %d (new=%x, old=%x)",
- fd, node->wanted, events);
- f->clazz->_fh_hook( f, events & ~node->wanted, node );
- node->wanted |= events;
- } else {
- D("event_looper_hook: ignoring events %x for %d wanted=%x)",
- events, fd, node->wanted);
- }
-}
-
-static void
-event_looper_unhook( EventLooper looper, int fd, int events )
-{
- FH fh = _fh_from_int(fd, __func__);
- EventHook *pnode = event_looper_find_p( looper, fh );
- EventHook node = *pnode;
-
- if (node != NULL) {
- int events2 = events & node->wanted;
- if ( events2 == 0 ) {
- D( "event_looper_unhook: events %x not registered for fd %d", events, fd );
- return;
- }
- node->wanted &= ~events2;
- if (!node->wanted) {
- *pnode = node->next;
- event_hook_free( node );
- }
- }
-}
-
-/*
- * A fixer for WaitForMultipleObjects on condition that there are more than 64
- * handles to wait on.
- *
- * In cetain cases DDMS may establish more than 64 connections with ADB. For
- * instance, this may happen if there are more than 64 processes running on a
- * device, or there are multiple devices connected (including the emulator) with
- * the combined number of running processes greater than 64. In this case using
- * WaitForMultipleObjects to wait on connection events simply wouldn't cut,
- * because of the API limitations (64 handles max). So, we need to provide a way
- * to scale WaitForMultipleObjects to accept an arbitrary number of handles. The
- * easiest (and "Microsoft recommended") way to do that would be dividing the
- * handle array into chunks with the chunk size less than 64, and fire up as many
- * waiting threads as there are chunks. Then each thread would wait on a chunk of
- * handles, and will report back to the caller which handle has been set.
- * Here is the implementation of that algorithm.
- */
-
-/* Number of handles to wait on in each wating thread. */
-#define WAIT_ALL_CHUNK_SIZE 63
-
-/* Descriptor for a wating thread */
-typedef struct WaitForAllParam {
- /* A handle to an event to signal when waiting is over. This handle is shared
- * accross all the waiting threads, so each waiting thread knows when any
- * other thread has exited, so it can exit too. */
- HANDLE main_event;
- /* Upon exit from a waiting thread contains the index of the handle that has
- * been signaled. The index is an absolute index of the signaled handle in
- * the original array. This pointer is shared accross all the waiting threads
- * and it's not guaranteed (due to a race condition) that when all the
- * waiting threads exit, the value contained here would indicate the first
- * handle that was signaled. This is fine, because the caller cares only
- * about any handle being signaled. It doesn't care about the order, nor
- * about the whole list of handles that were signaled. */
- LONG volatile *signaled_index;
- /* Array of handles to wait on in a waiting thread. */
- HANDLE* handles;
- /* Number of handles in 'handles' array to wait on. */
- int handles_count;
- /* Index inside the main array of the first handle in the 'handles' array. */
- int first_handle_index;
- /* Waiting thread handle. */
- HANDLE thread;
-} WaitForAllParam;
-
-/* Waiting thread routine. */
-static unsigned __stdcall
-_in_waiter_thread(void* arg)
-{
- HANDLE wait_on[WAIT_ALL_CHUNK_SIZE + 1];
- int res;
- WaitForAllParam* const param = (WaitForAllParam*)arg;
-
- /* We have to wait on the main_event in order to be notified when any of the
- * sibling threads is exiting. */
- wait_on[0] = param->main_event;
- /* The rest of the handles go behind the main event handle. */
- memcpy(wait_on + 1, param->handles, param->handles_count * sizeof(HANDLE));
-
- res = WaitForMultipleObjects(param->handles_count + 1, wait_on, FALSE, INFINITE);
- if (res > 0 && res < (param->handles_count + 1)) {
- /* One of the original handles got signaled. Save its absolute index into
- * the output variable. */
- InterlockedCompareExchange(param->signaled_index,
- res - 1L + param->first_handle_index, -1L);
- }
-
- /* Notify the caller (and the siblings) that the wait is over. */
- SetEvent(param->main_event);
-
- _endthreadex(0);
- return 0;
-}
-
-/* WaitForMultipeObjects fixer routine.
- * Param:
- * handles Array of handles to wait on.
- * handles_count Number of handles in the array.
- * Return:
- * (>= 0 && < handles_count) - Index of the signaled handle in the array, or
- * WAIT_FAILED on an error.
- */
-static int
-_wait_for_all(HANDLE* handles, int handles_count)
-{
- WaitForAllParam* threads;
- HANDLE main_event;
- int chunks, chunk, remains;
-
- /* This variable is going to be accessed by several threads at the same time,
- * this is bound to fail randomly when the core is run on multi-core machines.
- * To solve this, we need to do the following (1 _and_ 2):
- * 1. Use the "volatile" qualifier to ensure the compiler doesn't optimize
- * out the reads/writes in this function unexpectedly.
- * 2. Ensure correct memory ordering. The "simple" way to do that is to wrap
- * all accesses inside a critical section. But we can also use
- * InterlockedCompareExchange() which always provide a full memory barrier
- * on Win32.
- */
- volatile LONG sig_index = -1;
-
- /* Calculate number of chunks, and allocate thread param array. */
- chunks = handles_count / WAIT_ALL_CHUNK_SIZE;
- remains = handles_count % WAIT_ALL_CHUNK_SIZE;
- threads = (WaitForAllParam*)malloc((chunks + (remains ? 1 : 0)) *
- sizeof(WaitForAllParam));
- if (threads == NULL) {
- D("Unable to allocate thread array for %d handles.", handles_count);
- return (int)WAIT_FAILED;
- }
-
- /* Create main event to wait on for all waiting threads. This is a "manualy
- * reset" event that will remain set once it was set. */
- main_event = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (main_event == NULL) {
- D("Unable to create main event. Error: %ld", GetLastError());
- free(threads);
- return (int)WAIT_FAILED;
- }
-
- /*
- * Initialize waiting thread parameters.
- */
-
- for (chunk = 0; chunk < chunks; chunk++) {
- threads[chunk].main_event = main_event;
- threads[chunk].signaled_index = &sig_index;
- threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
- threads[chunk].handles = handles + threads[chunk].first_handle_index;
- threads[chunk].handles_count = WAIT_ALL_CHUNK_SIZE;
- }
- if (remains) {
- threads[chunk].main_event = main_event;
- threads[chunk].signaled_index = &sig_index;
- threads[chunk].first_handle_index = WAIT_ALL_CHUNK_SIZE * chunk;
- threads[chunk].handles = handles + threads[chunk].first_handle_index;
- threads[chunk].handles_count = remains;
- chunks++;
- }
-
- /* Start the waiting threads. */
- for (chunk = 0; chunk < chunks; chunk++) {
- /* Note that using adb_thread_create is not appropriate here, since we
- * need a handle to wait on for thread termination. */
- threads[chunk].thread = (HANDLE)_beginthreadex(NULL, 0, _in_waiter_thread,
- &threads[chunk], 0, NULL);
- if (threads[chunk].thread == NULL) {
- /* Unable to create a waiter thread. Collapse. */
- D("Unable to create a waiting thread %d of %d. errno=%d",
- chunk, chunks, errno);
- chunks = chunk;
- SetEvent(main_event);
- break;
- }
- }
-
- /* Wait on any of the threads to get signaled. */
- WaitForSingleObject(main_event, INFINITE);
-
- /* Wait on all the waiting threads to exit. */
- for (chunk = 0; chunk < chunks; chunk++) {
- WaitForSingleObject(threads[chunk].thread, INFINITE);
- CloseHandle(threads[chunk].thread);
- }
-
- CloseHandle(main_event);
- free(threads);
-
-
- const int ret = (int)InterlockedCompareExchange(&sig_index, -1, -1);
- return (ret >= 0) ? ret : (int)WAIT_FAILED;
-}
-
-static EventLooperRec win32_looper;
-
-static void fdevent_init(void)
-{
- win32_looper.htab_count = 0;
- win32_looper.hooks = NULL;
-}
-
-static void fdevent_connect(fdevent *fde)
-{
- EventLooper looper = &win32_looper;
- int events = fde->state & FDE_EVENTMASK;
-
- if (events != 0)
- event_looper_hook( looper, fde->fd, events );
-}
-
-static void fdevent_disconnect(fdevent *fde)
-{
- EventLooper looper = &win32_looper;
- int events = fde->state & FDE_EVENTMASK;
-
- if (events != 0)
- event_looper_unhook( looper, fde->fd, events );
-}
-
-static void fdevent_update(fdevent *fde, unsigned events)
-{
- EventLooper looper = &win32_looper;
- unsigned events0 = fde->state & FDE_EVENTMASK;
-
- if (events != events0) {
- int removes = events0 & ~events;
- int adds = events & ~events0;
- if (removes) {
- D("fdevent_update: remove %x from %d", removes, fde->fd);
- event_looper_unhook( looper, fde->fd, removes );
- }
- if (adds) {
- D("fdevent_update: add %x to %d", adds, fde->fd);
- event_looper_hook ( looper, fde->fd, adds );
- }
- }
-}
-
-static void fdevent_process()
-{
- EventLooper looper = &win32_looper;
- EventHook hook;
- int gotone = 0;
-
- /* if we have at least one ready hook, execute it/them */
- for (hook = looper->hooks; hook; hook = hook->next) {
- hook->ready = 0;
- if (hook->prepare) {
- hook->prepare(hook);
- if (hook->ready != 0) {
- event_hook_signal( hook );
- gotone = 1;
- }
- }
- }
-
- /* nothing's ready yet, so wait for something to happen */
- if (!gotone)
- {
- looper->htab_count = 0;
-
- for (hook = looper->hooks; hook; hook = hook->next)
- {
- if (hook->start && !hook->start(hook)) {
- D( "fdevent_process: error when starting a hook" );
- return;
- }
- if (hook->h != INVALID_HANDLE_VALUE) {
- int nn;
-
- for (nn = 0; nn < looper->htab_count; nn++)
- {
- if ( looper->htab[nn] == hook->h )
- goto DontAdd;
- }
- looper->htab[ looper->htab_count++ ] = hook->h;
- DontAdd:
- ;
- }
- }
-
- if (looper->htab_count == 0) {
- D( "fdevent_process: nothing to wait for !!" );
- return;
- }
-
- do
- {
- int wait_ret;
-
- D( "adb_win32: waiting for %d events", looper->htab_count );
- if (looper->htab_count > MAXIMUM_WAIT_OBJECTS) {
- D("handle count %d exceeds MAXIMUM_WAIT_OBJECTS.", looper->htab_count);
- wait_ret = _wait_for_all(looper->htab, looper->htab_count);
- } else {
- wait_ret = WaitForMultipleObjects( looper->htab_count, looper->htab, FALSE, INFINITE );
- }
- if (wait_ret == (int)WAIT_FAILED) {
- D( "adb_win32: wait failed, error %ld", GetLastError() );
- } else {
- D( "adb_win32: got one (index %d)", wait_ret );
-
- /* according to Cygwin, some objects like consoles wake up on "inappropriate" events
- * like mouse movements. we need to filter these with the "check" function
- */
- if ((unsigned)wait_ret < (unsigned)looper->htab_count)
- {
- for (hook = looper->hooks; hook; hook = hook->next)
- {
- if ( looper->htab[wait_ret] == hook->h &&
- (!hook->check || hook->check(hook)) )
- {
- D( "adb_win32: signaling %s for %x", hook->fh->name, hook->ready );
- event_hook_signal( hook );
- gotone = 1;
- break;
- }
- }
- }
- }
- }
- while (!gotone);
-
- for (hook = looper->hooks; hook; hook = hook->next) {
- if (hook->stop)
- hook->stop( hook );
- }
- }
-
- for (hook = looper->hooks; hook; hook = hook->next) {
- if (hook->peek && hook->peek(hook))
- event_hook_signal( hook );
- }
-}
-
-
-static void fdevent_register(fdevent *fde)
-{
- int fd = fde->fd - WIN32_FH_BASE;
-
- if(fd < 0) {
- FATAL("bogus negative fd (%d)\n", fde->fd);
- }
-
- if(fd >= fd_table_max) {
- int oldmax = fd_table_max;
- if(fde->fd > 32000) {
- FATAL("bogus huuuuge fd (%d)\n", fde->fd);
- }
- if(fd_table_max == 0) {
- fdevent_init();
- fd_table_max = 256;
- }
- while(fd_table_max <= fd) {
- fd_table_max *= 2;
- }
- fd_table = reinterpret_cast<fdevent**>(realloc(fd_table, sizeof(fdevent*) * fd_table_max));
- if(fd_table == 0) {
- FATAL("could not expand fd_table to %d entries\n", fd_table_max);
- }
- memset(fd_table + oldmax, 0, sizeof(int) * (fd_table_max - oldmax));
- }
-
- fd_table[fd] = fde;
-}
-
-static void fdevent_unregister(fdevent *fde)
-{
- int fd = fde->fd - WIN32_FH_BASE;
-
- if((fd < 0) || (fd >= fd_table_max)) {
- FATAL("fd out of range (%d)\n", fde->fd);
- }
-
- if(fd_table[fd] != fde) {
- FATAL("fd_table out of sync");
- }
-
- fd_table[fd] = 0;
-
- if(!(fde->state & FDE_DONT_CLOSE)) {
- dump_fde(fde, "close");
- adb_close(fde->fd);
- }
-}
-
-static void fdevent_plist_enqueue(fdevent *node)
-{
- fdevent *list = &list_pending;
-
- node->next = list;
- node->prev = list->prev;
- node->prev->next = node;
- list->prev = node;
-}
-
-static void fdevent_plist_remove(fdevent *node)
-{
- node->prev->next = node->next;
- node->next->prev = node->prev;
- node->next = 0;
- node->prev = 0;
-}
-
-static fdevent *fdevent_plist_dequeue(void)
-{
- fdevent *list = &list_pending;
- fdevent *node = list->next;
-
- if(node == list) return 0;
-
- list->next = node->next;
- list->next->prev = list;
- node->next = 0;
- node->prev = 0;
-
- return node;
-}
-
-fdevent *fdevent_create(int fd, fd_func func, void *arg)
-{
- fdevent *fde = (fdevent*) malloc(sizeof(fdevent));
- if(fde == 0) return 0;
- fdevent_install(fde, fd, func, arg);
- fde->state |= FDE_CREATED;
- return fde;
-}
-
-void fdevent_destroy(fdevent *fde)
-{
- if(fde == 0) return;
- if(!(fde->state & FDE_CREATED)) {
- FATAL("fde %p not created by fdevent_create()\n", fde);
- }
- fdevent_remove(fde);
-}
-
-void fdevent_install(fdevent *fde, int fd, fd_func func, void *arg)
-{
- memset(fde, 0, sizeof(fdevent));
- fde->state = FDE_ACTIVE;
- fde->fd = fd;
- fde->func = func;
- fde->arg = arg;
-
- fdevent_register(fde);
- dump_fde(fde, "connect");
- fdevent_connect(fde);
- fde->state |= FDE_ACTIVE;
-}
-
-void fdevent_remove(fdevent *fde)
-{
- if(fde->state & FDE_PENDING) {
- fdevent_plist_remove(fde);
- }
-
- if(fde->state & FDE_ACTIVE) {
- fdevent_disconnect(fde);
- dump_fde(fde, "disconnect");
- fdevent_unregister(fde);
- }
-
- fde->state = 0;
- fde->events = 0;
-}
-
-
-void fdevent_set(fdevent *fde, unsigned events)
-{
- events &= FDE_EVENTMASK;
-
- if((fde->state & FDE_EVENTMASK) == (int)events) return;
-
- if(fde->state & FDE_ACTIVE) {
- fdevent_update(fde, events);
- dump_fde(fde, "update");
- }
-
- fde->state = (fde->state & FDE_STATEMASK) | events;
-
- if(fde->state & FDE_PENDING) {
- /* if we're pending, make sure
- ** we don't signal an event that
- ** is no longer wanted.
- */
- fde->events &= (~events);
- if(fde->events == 0) {
- fdevent_plist_remove(fde);
- fde->state &= (~FDE_PENDING);
- }
- }
-}
-
-void fdevent_add(fdevent *fde, unsigned events)
-{
- fdevent_set(
- fde, (fde->state & FDE_EVENTMASK) | (events & FDE_EVENTMASK));
-}
-
-void fdevent_del(fdevent *fde, unsigned events)
-{
- fdevent_set(
- fde, (fde->state & FDE_EVENTMASK) & (~(events & FDE_EVENTMASK)));
-}
-
-void fdevent_loop()
-{
- fdevent *fde;
-
- for(;;) {
-#if DEBUG
- fprintf(stderr,"--- ---- waiting for events\n");
-#endif
- fdevent_process();
-
- while((fde = fdevent_plist_dequeue())) {
- unsigned events = fde->events;
- fde->events = 0;
- fde->state &= (~FDE_PENDING);
- dump_fde(fde, "callback");
- fde->func(fde->fd, events, fde->arg);
- }
- }
-}
-
-/** FILE EVENT HOOKS
- **/
-
-static void _event_file_prepare( EventHook hook )
-{
- if (hook->wanted & (FDE_READ|FDE_WRITE)) {
- /* we can always read/write */
- hook->ready |= hook->wanted & (FDE_READ|FDE_WRITE);
- }
-}
-
-static int _event_file_peek( EventHook hook )
-{
- return (hook->wanted & (FDE_READ|FDE_WRITE));
-}
-
-static void _fh_file_hook( FH f, int events, EventHook hook )
-{
- hook->h = f->fh_handle;
- hook->prepare = _event_file_prepare;
- hook->peek = _event_file_peek;
-}
-
-/** SOCKET EVENT HOOKS
- **/
-
-static void _event_socket_verify( EventHook hook, WSANETWORKEVENTS* evts )
-{
- if ( evts->lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE) ) {
- if (hook->wanted & FDE_READ)
- hook->ready |= FDE_READ;
- if ((evts->iErrorCode[FD_READ] != 0) && hook->wanted & FDE_ERROR)
- hook->ready |= FDE_ERROR;
- }
- if ( evts->lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE) ) {
- if (hook->wanted & FDE_WRITE)
- hook->ready |= FDE_WRITE;
- if ((evts->iErrorCode[FD_WRITE] != 0) && hook->wanted & FDE_ERROR)
- hook->ready |= FDE_ERROR;
- }
- if ( evts->lNetworkEvents & FD_OOB ) {
- if (hook->wanted & FDE_ERROR)
- hook->ready |= FDE_ERROR;
- }
-}
-
-static void _event_socket_prepare( EventHook hook )
-{
- WSANETWORKEVENTS evts;
-
- /* look if some of the events we want already happened ? */
- if (!WSAEnumNetworkEvents( hook->fh->fh_socket, NULL, &evts ))
- _event_socket_verify( hook, &evts );
-}
-
-static int _socket_wanted_to_flags( int wanted )
-{
- int flags = 0;
- if (wanted & FDE_READ)
- flags |= FD_READ | FD_ACCEPT | FD_CLOSE;
-
- if (wanted & FDE_WRITE)
- flags |= FD_WRITE | FD_CONNECT | FD_CLOSE;
-
- if (wanted & FDE_ERROR)
- flags |= FD_OOB;
-
- return flags;
-}
-
-static int _event_socket_start( EventHook hook )
-{
- /* create an event which we're going to wait for */
- FH fh = hook->fh;
- long flags = _socket_wanted_to_flags( hook->wanted );
-
- hook->h = fh->event;
- if (hook->h == INVALID_HANDLE_VALUE) {
- D( "_event_socket_start: no event for %s", fh->name );
- return 0;
- }
-
- if ( flags != fh->mask ) {
- D( "_event_socket_start: hooking %s for %x (flags %ld)", hook->fh->name, hook->wanted, flags );
- if ( WSAEventSelect( fh->fh_socket, hook->h, flags ) ) {
- D( "_event_socket_start: WSAEventSelect() for %s failed, error %d", hook->fh->name, WSAGetLastError() );
- CloseHandle( hook->h );
- hook->h = INVALID_HANDLE_VALUE;
- exit(1);
- return 0;
- }
- fh->mask = flags;
- }
- return 1;
-}
-
-static void _event_socket_stop( EventHook hook )
-{
- hook->h = INVALID_HANDLE_VALUE;
-}
-
-static int _event_socket_check( EventHook hook )
-{
- int result = 0;
- FH fh = hook->fh;
- WSANETWORKEVENTS evts;
-
- if (!WSAEnumNetworkEvents( fh->fh_socket, hook->h, &evts ) ) {
- _event_socket_verify( hook, &evts );
- result = (hook->ready != 0);
- if (result) {
- ResetEvent( hook->h );
- }
- }
- D( "_event_socket_check %s returns %d", fh->name, result );
- return result;
-}
-
-static int _event_socket_peek( EventHook hook )
-{
- WSANETWORKEVENTS evts;
- FH fh = hook->fh;
-
- /* look if some of the events we want already happened ? */
- if (!WSAEnumNetworkEvents( fh->fh_socket, NULL, &evts )) {
- _event_socket_verify( hook, &evts );
- if (hook->ready)
- ResetEvent( hook->h );
- }
-
- return hook->ready != 0;
-}
-
-
-
-static void _fh_socket_hook( FH f, int events, EventHook hook )
-{
- hook->prepare = _event_socket_prepare;
- hook->start = _event_socket_start;
- hook->stop = _event_socket_stop;
- hook->check = _event_socket_check;
- hook->peek = _event_socket_peek;
-
- // TODO: check return value?
- _event_socket_start( hook );
-}
-
-/** SOCKETPAIR EVENT HOOKS
- **/
-
-static void _event_socketpair_prepare( EventHook hook )
-{
- FH fh = hook->fh;
- SocketPair pair = fh->fh_pair;
- BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
- BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
- if (hook->wanted & FDE_READ && rbip->can_read)
- hook->ready |= FDE_READ;
-
- if (hook->wanted & FDE_WRITE && wbip->can_write)
- hook->ready |= FDE_WRITE;
- }
-
- static int _event_socketpair_start( EventHook hook )
- {
- FH fh = hook->fh;
- SocketPair pair = fh->fh_pair;
- BipBuffer rbip = (pair->a_fd == fh) ? &pair->b2a_bip : &pair->a2b_bip;
- BipBuffer wbip = (pair->a_fd == fh) ? &pair->a2b_bip : &pair->b2a_bip;
-
- if (hook->wanted == FDE_READ)
- hook->h = rbip->evt_read;
-
- else if (hook->wanted == FDE_WRITE)
- hook->h = wbip->evt_write;
-
- else {
- D("_event_socketpair_start: can't handle FDE_READ+FDE_WRITE" );
- return 0;
- }
- D( "_event_socketpair_start: hook %s for %x wanted=%x",
- hook->fh->name, _fh_to_int(fh), hook->wanted);
- return 1;
-}
-
-static int _event_socketpair_peek( EventHook hook )
-{
- _event_socketpair_prepare( hook );
- return hook->ready != 0;
-}
-
-static void _fh_socketpair_hook( FH fh, int events, EventHook hook )
-{
- hook->prepare = _event_socketpair_prepare;
- hook->start = _event_socketpair_start;
- hook->peek = _event_socketpair_peek;
-}
-
-
static adb_mutex_t g_console_output_buffer_lock;
void
diff --git a/adb/test_device.py b/adb/test_device.py
index afc061a..18174a2 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -766,6 +766,22 @@
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)
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 2022ae7..b33dd28 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -323,11 +323,10 @@
" cc=%d", props.batteryCycleCount);
}
} else {
- snprintf(dmesgline, sizeof(dmesgline),
+ len = snprintf(dmesgline, sizeof(dmesgline),
"battery none");
}
- len = strlen(dmesgline);
snprintf(dmesgline + len, sizeof(dmesgline) - len, " chg=%s%s%s",
props.chargerAcOnline ? "a" : "",
props.chargerUsbOnline ? "u" : "",
@@ -341,6 +340,17 @@
props.chargerWirelessOnline;
}
+int BatteryMonitor::getChargeStatus() {
+ int result = BATTERY_STATUS_UNKNOWN;
+ if (!mHealthdConfig->batteryStatusPath.isEmpty()) {
+ char buf[128];
+ if (readFromFile(mHealthdConfig->batteryStatusPath, buf, sizeof(buf)) > 0) {
+ result = getBatteryStatus(buf);
+ }
+ }
+ return result;
+}
+
status_t BatteryMonitor::getProperty(int id, struct BatteryProperty *val) {
status_t ret = BAD_VALUE;
diff --git a/healthd/include/healthd/BatteryMonitor.h b/healthd/include/healthd/BatteryMonitor.h
index 31c4e09..440f2e4 100644
--- a/healthd/include/healthd/BatteryMonitor.h
+++ b/healthd/include/healthd/BatteryMonitor.h
@@ -40,6 +40,7 @@
BatteryMonitor();
void init(struct healthd_config *hc);
bool update(void);
+ int getChargeStatus();
status_t getProperty(int id, struct BatteryProperty *val);
void dumpState(int fd);
diff --git a/include/log/log.h b/include/log/log.h
index 1bd9165..6ad6f0a 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -484,15 +484,19 @@
*/
/*
- * Event log entry types. These must match up with the declarations in
- * java/android/android/util/EventLog.java.
+ * Event log entry types.
*/
typedef enum {
- EVENT_TYPE_INT = 0,
- EVENT_TYPE_LONG = 1,
- EVENT_TYPE_STRING = 2,
- EVENT_TYPE_LIST = 3,
- EVENT_TYPE_FLOAT = 4,
+ /* Special markers for android_log_list_element type */
+ EVENT_TYPE_LIST_STOP = '\n', /* declare end of list */
+ EVENT_TYPE_UNKNOWN = '?', /* protocol error */
+
+ /* must match with declaration in java/android/android/util/EventLog.java */
+ EVENT_TYPE_INT = 0, /* uint32_t */
+ EVENT_TYPE_LONG = 1, /* uint64_t */
+ EVENT_TYPE_STRING = 2,
+ EVENT_TYPE_LIST = 3,
+ EVENT_TYPE_FLOAT = 4,
} AndroidEventLogType;
#define sizeof_AndroidEventLogType sizeof(typeof_AndroidEventLogType)
#define typeof_AndroidEventLogType unsigned char
@@ -522,7 +526,85 @@
#define LOG_EVENT_STRING(_tag, _value) \
(void) __android_log_bswrite(_tag, _value);
#endif
-/* TODO: something for LIST */
+
+typedef enum log_id {
+ LOG_ID_MIN = 0,
+
+#ifndef LINT_RLOG
+ LOG_ID_MAIN = 0,
+#endif
+ LOG_ID_RADIO = 1,
+#ifndef LINT_RLOG
+ LOG_ID_EVENTS = 2,
+ LOG_ID_SYSTEM = 3,
+ LOG_ID_CRASH = 4,
+ LOG_ID_SECURITY = 5,
+ LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
+#endif
+
+ LOG_ID_MAX
+} log_id_t;
+#define sizeof_log_id_t sizeof(typeof_log_id_t)
+#define typeof_log_id_t unsigned char
+
+/* For manipulating lists of events. */
+
+#define ANDROID_MAX_LIST_NEST_DEPTH 8
+
+/*
+ * The opaque context used to manipulate lists of events.
+ */
+typedef struct android_log_context_internal *android_log_context;
+
+/*
+ * Elements returned when reading a list of events.
+ */
+typedef struct {
+ AndroidEventLogType type;
+ uint16_t complete;
+ uint16_t len;
+ union {
+ int32_t int32;
+ int64_t int64;
+ char *string;
+ float float32;
+ } data;
+} android_log_list_element;
+
+/*
+ * Creates a context associated with an event tag to write elements to
+ * the list of events.
+ */
+android_log_context create_android_logger(uint32_t tag);
+
+/* All lists must be braced by a begin and end call */
+/*
+ * NB: If the first level braces are missing when specifying multiple
+ * elements, we will manufacturer a list to embrace it for your API
+ * convenience. For a single element, it will remain solitary.
+ */
+int android_log_write_list_begin(android_log_context ctx);
+int android_log_write_list_end(android_log_context ctx);
+
+int android_log_write_int32(android_log_context ctx, int32_t value);
+int android_log_write_int64(android_log_context ctx, int64_t value);
+int android_log_write_string8(android_log_context ctx, const char *value);
+int android_log_write_float32(android_log_context ctx, float value);
+
+/* Submit the composed list context to the specified logger id */
+/* NB: LOG_ID_EVENTS and LOG_ID_SECURITY only valid binary buffers */
+int android_log_write_list(android_log_context ctx, log_id_t id);
+
+/*
+ * Creates a context from a raw buffer representing a list of events to be read.
+ */
+android_log_context create_android_log_parser(const char *msg, size_t len);
+
+android_log_list_element android_log_read_next(android_log_context ctx);
+android_log_list_element android_log_peek_next(android_log_context ctx);
+
+/* Finished with reader or writer context */
+int android_log_destroy(android_log_context *ctx);
/*
* ===========================================================================
@@ -585,26 +667,6 @@
(__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE) != 0)
#endif
-typedef enum log_id {
- LOG_ID_MIN = 0,
-
-#ifndef LINT_RLOG
- LOG_ID_MAIN = 0,
-#endif
- LOG_ID_RADIO = 1,
-#ifndef LINT_RLOG
- LOG_ID_EVENTS = 2,
- LOG_ID_SYSTEM = 3,
- LOG_ID_CRASH = 4,
- LOG_ID_SECURITY = 5,
- LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
-#endif
-
- LOG_ID_MAX
-} log_id_t;
-#define sizeof_log_id_t sizeof(typeof_log_id_t)
-#define typeof_log_id_t unsigned char
-
/*
* Use the per-tag properties "log.tag.<tagname>" to generate a runtime
* result of non-zero to expose a log. prio is ANDROID_LOG_VERBOSE to
diff --git a/liblog/Android.mk b/liblog/Android.mk
index a183db8..c7b76d8 100644
--- a/liblog/Android.mk
+++ b/liblog/Android.mk
@@ -28,6 +28,7 @@
liblog_target_sources := logd_write.c log_event_write.c event_tag_map.c log_time.cpp log_is_loggable.c
liblog_target_sources += logprint.c
liblog_target_sources += log_read.c
+liblog_target_sources += log_event_list.c
# Shared and static library for host
# ========================================================
diff --git a/liblog/fake_log_device.c b/liblog/fake_log_device.c
index 4942c08..aa88bed 100644
--- a/liblog/fake_log_device.c
+++ b/liblog/fake_log_device.c
@@ -469,13 +469,13 @@
if (numLines > MAX_LINES)
numLines = MAX_LINES;
- numVecs = numLines*3; // 3 iovecs per line.
+ numVecs = numLines * 3; // 3 iovecs per line.
if (numVecs > INLINE_VECS) {
vec = (struct iovec*)malloc(sizeof(struct iovec)*numVecs);
if (vec == NULL) {
msg = "LOG: write failed, no memory";
- numVecs = 3;
- numLines = 1;
+ numVecs = INLINE_VECS;
+ numLines = numVecs / 3;
vec = stackVec;
}
}
diff --git a/liblog/log_event_list.c b/liblog/log_event_list.c
new file mode 100644
index 0000000..50a27c0
--- /dev/null
+++ b/liblog/log_event_list.c
@@ -0,0 +1,520 @@
+/*
+ * 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 <errno.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <log/log.h>
+#include <log/logger.h>
+
+#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
+
+typedef struct {
+ uint32_t tag;
+ unsigned pos; /* Read/write position into buffer */
+ unsigned count[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* Number of elements */
+ unsigned list[ANDROID_MAX_LIST_NEST_DEPTH + 1]; /* pos for list counter */
+ unsigned list_nest_depth;
+ unsigned len; /* Length or raw buffer. */
+ bool overflow;
+ bool list_stop; /* next call decrement list_nest_depth and issue a stop */
+ enum {
+ kAndroidLoggerRead = 1,
+ kAndroidLoggerWrite = 2,
+ } read_write_flag;
+ uint8_t storage[LOGGER_ENTRY_MAX_PAYLOAD];
+} android_log_context_internal;
+
+android_log_context create_android_logger(uint32_t tag) {
+ size_t needed, i;
+ android_log_context_internal *context;
+
+ context = calloc(1, sizeof(android_log_context_internal));
+ if (!context) {
+ return NULL;
+ }
+ context->tag = tag;
+ context->read_write_flag = kAndroidLoggerWrite;
+ needed = sizeof(uint8_t) + sizeof(uint8_t);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ }
+ /* Everything is a list */
+ context->storage[context->pos + 0] = EVENT_TYPE_LIST;
+ context->list[0] = context->pos + 1;
+ context->pos += needed;
+
+ return (android_log_context)context;
+}
+
+android_log_context create_android_log_parser(const char *msg, size_t len) {
+ android_log_context_internal *context;
+ size_t i;
+
+ context = calloc(1, sizeof(android_log_context_internal));
+ if (!context) {
+ return NULL;
+ }
+ len = (len <= MAX_EVENT_PAYLOAD) ? len : MAX_EVENT_PAYLOAD;
+ context->len = len;
+ memcpy(context->storage, msg, len);
+ context->read_write_flag = kAndroidLoggerRead;
+
+ return (android_log_context)context;
+}
+
+int android_log_destroy(android_log_context *ctx) {
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)*ctx;
+ if (!context) {
+ return -EBADF;
+ }
+ memset(context, 0, sizeof(*context));
+ free(context);
+ *ctx = NULL;
+ return 0;
+}
+
+int android_log_write_list_begin(android_log_context ctx) {
+ size_t needed;
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)ctx;
+ if (!context ||
+ (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ needed = sizeof(uint8_t) + sizeof(uint8_t);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ context->count[context->list_nest_depth]++;
+ context->list_nest_depth++;
+ if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ context->storage[context->pos + 0] = EVENT_TYPE_LIST;
+ context->storage[context->pos + 1] = 0;
+ context->list[context->list_nest_depth] = context->pos + 1;
+ context->count[context->list_nest_depth] = 0;
+ context->pos += needed;
+ return 0;
+}
+
+static inline void copy4LE(uint8_t *buf, uint32_t val)
+{
+ buf[0] = val & 0xFF;
+ buf[1] = (val >> 8) & 0xFF;
+ buf[2] = (val >> 16) & 0xFF;
+ buf[3] = (val >> 24) & 0xFF;
+}
+
+int android_log_write_int32(android_log_context ctx, int32_t value) {
+ size_t needed;
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ needed = sizeof(uint8_t) + sizeof(value);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_INT;
+ copy4LE(&context->storage[context->pos + 1], value);
+ context->pos += needed;
+ return 0;
+}
+
+static inline void copy8LE(uint8_t *buf, uint64_t val)
+{
+ buf[0] = val & 0xFF;
+ buf[1] = (val >> 8) & 0xFF;
+ buf[2] = (val >> 16) & 0xFF;
+ buf[3] = (val >> 24) & 0xFF;
+ buf[4] = (val >> 32) & 0xFF;
+ buf[5] = (val >> 40) & 0xFF;
+ buf[6] = (val >> 48) & 0xFF;
+ buf[7] = (val >> 56) & 0xFF;
+}
+
+int android_log_write_int64(android_log_context ctx, int64_t value) {
+ size_t needed;
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ needed = sizeof(uint8_t) + sizeof(value);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_LONG;
+ copy8LE(&context->storage[context->pos + 1], value);
+ context->pos += needed;
+ return 0;
+}
+
+int android_log_write_string8(android_log_context ctx, const char *value) {
+ size_t needed;
+ int32_t len;
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ if (!value) {
+ return -EINVAL;
+ }
+ len = strlen(value);
+ needed = sizeof(uint8_t) + sizeof(len) + len;
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ /* Truncate string for delivery */
+ len = MAX_EVENT_PAYLOAD - context->pos - 1 - sizeof(len);
+ if (len <= 0) {
+ context->overflow = true;
+ return -EIO;
+ }
+ }
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_STRING;
+ copy4LE(&context->storage[context->pos + 1], len);
+ memcpy(&context->storage[context->pos + 5], value, len);
+ context->pos += needed;
+ return 0;
+}
+
+int android_log_write_float32(android_log_context ctx, float value) {
+ size_t needed;
+ uint32_t ivalue;
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->overflow) {
+ return -EIO;
+ }
+ needed = sizeof(uint8_t) + sizeof(ivalue);
+ if ((context->pos + needed) > MAX_EVENT_PAYLOAD) {
+ context->overflow = true;
+ return -EIO;
+ }
+ ivalue = *(uint32_t *)&value;
+ context->count[context->list_nest_depth]++;
+ context->storage[context->pos + 0] = EVENT_TYPE_FLOAT;
+ copy4LE(&context->storage[context->pos + 1], ivalue);
+ context->pos += needed;
+ return 0;
+}
+
+int android_log_write_list_end(android_log_context ctx) {
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->overflow = true;
+ context->list_nest_depth--;
+ return -EOVERFLOW;
+ }
+ if (!context->list_nest_depth) {
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ if (context->list[context->list_nest_depth] <= 0) {
+ context->list_nest_depth--;
+ context->overflow = true;
+ return -EOVERFLOW;
+ }
+ context->storage[context->list[context->list_nest_depth]] =
+ context->count[context->list_nest_depth];
+ context->list_nest_depth--;
+ return 0;
+}
+
+/*
+ * Logs the list of elements to the event log.
+ */
+int android_log_write_list(android_log_context ctx, log_id_t id) {
+ android_log_context_internal *context;
+ const char *msg;
+ ssize_t len;
+
+ if ((id != LOG_ID_EVENTS) && (id != LOG_ID_SECURITY)) {
+ return -EINVAL;
+ }
+
+ context = (android_log_context_internal *)ctx;
+ if (!context || (kAndroidLoggerWrite != context->read_write_flag)) {
+ return -EBADF;
+ }
+ if (context->list_nest_depth) {
+ return -EIO;
+ }
+ /* NB: if there was overflow, then log is truncated. Nothing reported */
+ context->storage[1] = context->count[0];
+ len = context->len = context->pos;
+ msg = (const char *)context->storage;
+ /* it'snot a list */
+ if (context->count[0] <= 1) {
+ len -= sizeof(uint8_t) + sizeof(uint8_t);
+ if (len < 0) {
+ len = 0;
+ }
+ msg += sizeof(uint8_t) + sizeof(uint8_t);
+ }
+ return (id == LOG_ID_EVENTS) ?
+ __android_log_bwrite(context->tag, msg, len) :
+ __android_log_security_bwrite(context->tag, msg, len);
+}
+
+/*
+ * Extract a 4-byte value from a byte stream.
+ */
+static inline uint32_t get4LE(const uint8_t* src)
+{
+ return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+}
+
+/*
+ * Extract an 8-byte value from a byte stream.
+ */
+static inline uint64_t get8LE(const uint8_t* src)
+{
+ uint32_t low = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
+ uint32_t high = src[4] | (src[5] << 8) | (src[6] << 16) | (src[7] << 24);
+ return ((uint64_t) high << 32) | (uint64_t) low;
+}
+
+/*
+ * Gets the next element. Parsing errors result in an EVENT_TYPE_UNKNOWN type.
+ * If there is nothing to process, the complete field is set to non-zero. If
+ * an EVENT_TYPE_UNKNOWN type is returned once, and the caller does not check
+ * this and continues to call this function, the behavior is undefined
+ * (although it won't crash).
+ */
+static android_log_list_element android_log_read_next_internal(
+ android_log_context ctx, int peek) {
+ android_log_list_element elem;
+ unsigned pos;
+ android_log_context_internal *context;
+
+ context = (android_log_context_internal *)ctx;
+
+ memset(&elem, 0, sizeof(elem));
+
+ /* Nothing to parse from this context, so return complete. */
+ if (!context || (kAndroidLoggerRead != context->read_write_flag) ||
+ (context->list_nest_depth > ANDROID_MAX_LIST_NEST_DEPTH) ||
+ (context->count[context->list_nest_depth] >=
+ (MAX_EVENT_PAYLOAD / (sizeof(uint8_t) + sizeof(uint8_t))))) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ if (context &&
+ (context->list_stop ||
+ ((context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) &&
+ !context->count[context->list_nest_depth]))) {
+ elem.type = EVENT_TYPE_LIST_STOP;
+ }
+ elem.complete = true;
+ return elem;
+ }
+
+ /*
+ * Use a different variable to update the position in case this
+ * operation is a "peek".
+ */
+ pos = context->pos;
+ if (context->list_stop) {
+ elem.type = EVENT_TYPE_LIST_STOP;
+ elem.complete = !context->count[0] && (!context->list_nest_depth ||
+ ((context->list_nest_depth == 1) && !context->count[1]));
+ if (!peek) {
+ /* Suck in superfluous stop */
+ if (context->storage[pos] == EVENT_TYPE_LIST_STOP) {
+ context->pos = pos + 1;
+ }
+ if (context->list_nest_depth) {
+ --context->list_nest_depth;
+ if (context->count[context->list_nest_depth]) {
+ context->list_stop = false;
+ }
+ } else {
+ context->list_stop = false;
+ }
+ }
+ return elem;
+ }
+ if ((pos + 1) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = true;
+ return elem;
+ }
+
+ elem.type = context->storage[pos++];
+ switch ((int)elem.type) {
+ case EVENT_TYPE_FLOAT:
+ /* Rely on union to translate elem.data.int32 into elem.data.float32 */
+ /* FALLTHRU */
+ case EVENT_TYPE_INT:
+ elem.len = sizeof(int32_t);
+ if ((pos + elem.len) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ return elem;
+ }
+ elem.data.int32 = get4LE(&context->storage[pos]);
+ /* common tangeable object suffix */
+ pos += elem.len;
+ elem.complete = !context->list_nest_depth && !context->count[0];
+ if (!peek) {
+ if (!context->count[context->list_nest_depth] ||
+ !--(context->count[context->list_nest_depth])) {
+ context->list_stop = true;
+ }
+ context->pos = pos;
+ }
+ return elem;
+
+ case EVENT_TYPE_LONG:
+ elem.len = sizeof(int64_t);
+ if ((pos + elem.len) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ return elem;
+ }
+ elem.data.int64 = get8LE(&context->storage[pos]);
+ /* common tangeable object suffix */
+ pos += elem.len;
+ elem.complete = !context->list_nest_depth && !context->count[0];
+ if (!peek) {
+ if (!context->count[context->list_nest_depth] ||
+ !--(context->count[context->list_nest_depth])) {
+ context->list_stop = true;
+ }
+ context->pos = pos;
+ }
+ return elem;
+
+ case EVENT_TYPE_STRING:
+ if ((pos + sizeof(int32_t)) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = true;
+ return elem;
+ }
+ elem.len = get4LE(&context->storage[pos]);
+ pos += sizeof(int32_t);
+ if ((pos + elem.len) > context->len) {
+ elem.len = context->len - pos; /* truncate string */
+ elem.complete = true;
+ if (!elem.len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ return elem;
+ }
+ }
+ elem.data.string = (char *)&context->storage[pos];
+ /* common tangeable object suffix */
+ pos += elem.len;
+ elem.complete = !context->list_nest_depth && !context->count[0];
+ if (!peek) {
+ if (!context->count[context->list_nest_depth] ||
+ !--(context->count[context->list_nest_depth])) {
+ context->list_stop = true;
+ }
+ context->pos = pos;
+ }
+ return elem;
+
+ case EVENT_TYPE_LIST:
+ if ((pos + sizeof(uint8_t)) > context->len) {
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = true;
+ return elem;
+ }
+ elem.complete = context->list_nest_depth >= ANDROID_MAX_LIST_NEST_DEPTH;
+ if (peek) {
+ return elem;
+ }
+ if (context->count[context->list_nest_depth]) {
+ context->count[context->list_nest_depth]--;
+ }
+ context->list_stop = !context->storage[pos];
+ context->list_nest_depth++;
+ if (context->list_nest_depth <= ANDROID_MAX_LIST_NEST_DEPTH) {
+ context->count[context->list_nest_depth] = context->storage[pos];
+ }
+ context->pos = pos + sizeof(uint8_t);
+ return elem;
+
+ case EVENT_TYPE_LIST_STOP: /* Suprise Newline terminates lists. */
+ if (!peek) {
+ context->pos = pos;
+ }
+ elem.type = EVENT_TYPE_UNKNOWN;
+ elem.complete = !context->list_nest_depth;
+ if (context->list_nest_depth > 0) {
+ elem.type = EVENT_TYPE_LIST_STOP;
+ if (!peek) {
+ context->list_nest_depth--;
+ }
+ }
+ return elem;
+
+ default:
+ elem.type = EVENT_TYPE_UNKNOWN;
+ return elem;
+ }
+}
+
+android_log_list_element android_log_read_next(android_log_context ctx) {
+ return android_log_read_next_internal(ctx, 0);
+}
+
+android_log_list_element android_log_peek_next(android_log_context ctx) {
+ return android_log_read_next_internal(ctx, 1);
+}
diff --git a/liblog/log_read.c b/liblog/log_read.c
index 1aff272..fc63d2c 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -503,10 +503,7 @@
}
if (logger_list->pid) {
- n = snprintf(cp, remaining, " pid=%u", logger_list->pid);
- n = min(n, remaining);
- remaining -= n;
- cp += n;
+ snprintf(cp, remaining, " pid=%u", logger_list->pid);
}
return send_log_msg(NULL, NULL, buf, len);
@@ -657,7 +654,6 @@
preread_count = 0;
}
- ret = 0;
while(1) {
if (preread_count < sizeof(buf)) {
ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
@@ -834,7 +830,6 @@
if (logger_list->pid) {
ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
ret = min(ret, remaining);
- remaining -= ret;
cp += ret;
}
@@ -867,7 +862,6 @@
logger_list->sock = sock;
}
- ret = 0;
while(1) {
memset(log_msg, 0, sizeof(*log_msg));
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index f8d4c4c..1317853 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013-2014 The Android Open Source Project
+ * Copyright (C) 2013-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.
@@ -1741,3 +1741,529 @@
android_logger_list_close(logger_list);
}
+
+static int is_real_element(int type) {
+ return ((type == EVENT_TYPE_INT) ||
+ (type == EVENT_TYPE_LONG) ||
+ (type == EVENT_TYPE_STRING) ||
+ (type == EVENT_TYPE_FLOAT));
+}
+
+int android_log_buffer_to_string(const char *msg, size_t len,
+ char *strOut, size_t strOutLen) {
+ android_log_context context = create_android_log_parser(msg, len);
+ android_log_list_element elem;
+ bool overflow = false;
+ /* Reserve 1 byte for null terminator. */
+ size_t origStrOutLen = strOutLen--;
+
+ if (!context) {
+ return -EBADF;
+ }
+
+ memset(&elem, 0, sizeof(elem));
+
+ size_t outCount;
+
+ do {
+ elem = android_log_read_next(context);
+ switch ((int)elem.type) {
+ case EVENT_TYPE_LIST:
+ if (strOutLen == 0) {
+ overflow = true;
+ } else {
+ *strOut++ = '[';
+ strOutLen--;
+ }
+ break;
+
+ case EVENT_TYPE_LIST_STOP:
+ if (strOutLen == 0) {
+ overflow = true;
+ } else {
+ *strOut++ = ']';
+ strOutLen--;
+ }
+ break;
+
+ case EVENT_TYPE_INT:
+ /*
+ * snprintf also requires room for the null terminator, which
+ * we don't care about but we have allocated enough room for
+ * that
+ */
+ outCount = snprintf(strOut, strOutLen + 1,
+ "%" PRId32, elem.data.int32);
+ if (outCount <= strOutLen) {
+ strOut += outCount;
+ strOutLen -= outCount;
+ } else {
+ overflow = true;
+ }
+ break;
+
+ case EVENT_TYPE_LONG:
+ /*
+ * snprintf also requires room for the null terminator, which
+ * we don't care about but we have allocated enough room for
+ * that
+ */
+ outCount = snprintf(strOut, strOutLen + 1,
+ "%" PRId64, elem.data.int64);
+ if (outCount <= strOutLen) {
+ strOut += outCount;
+ strOutLen -= outCount;
+ } else {
+ overflow = true;
+ }
+ break;
+
+ case EVENT_TYPE_FLOAT:
+ /*
+ * snprintf also requires room for the null terminator, which
+ * we don't care about but we have allocated enough room for
+ * that
+ */
+ outCount = snprintf(strOut, strOutLen + 1, "%f", elem.data.float32);
+ if (outCount <= strOutLen) {
+ strOut += outCount;
+ strOutLen -= outCount;
+ } else {
+ overflow = true;
+ }
+ break;
+
+ default:
+ elem.complete = true;
+ break;
+
+ case EVENT_TYPE_UNKNOWN:
+#if 0 // Ideal purity in the test, we want to complain about UNKNOWN showing up
+ if (elem.complete) {
+ break;
+ }
+#endif
+ elem.data.string = const_cast<char *>("<unknown>");
+ elem.len = strlen(elem.data.string);
+ /* FALLTHRU */
+ case EVENT_TYPE_STRING:
+ if (elem.len <= strOutLen) {
+ memcpy(strOut, elem.data.string, elem.len);
+ strOut += elem.len;
+ strOutLen -= elem.len;
+ } else if (strOutLen > 0) {
+ /* copy what we can */
+ memcpy(strOut, elem.data.string, strOutLen);
+ strOut += strOutLen;
+ strOutLen = 0;
+ overflow = true;
+ }
+ break;
+ }
+
+ if (elem.complete) {
+ break;
+ }
+ /* Determine whether to put a comma or not. */
+ if (!overflow && (is_real_element(elem.type) ||
+ (elem.type == EVENT_TYPE_LIST_STOP))) {
+ android_log_list_element next = android_log_peek_next(context);
+ if (!next.complete && (is_real_element(next.type) ||
+ (next.type == EVENT_TYPE_LIST))) {
+ if (strOutLen == 0) {
+ overflow = true;
+ } else {
+ *strOut++ = ',';
+ strOutLen--;
+ }
+ }
+ }
+ } while ((elem.type != EVENT_TYPE_UNKNOWN) && !overflow && !elem.complete);
+
+ android_log_destroy(&context);
+
+ if (overflow) {
+ if (strOutLen < origStrOutLen) {
+ /* leave an indicator */
+ *(strOut-1) = '!';
+ } else {
+ /* nothing was written at all */
+ *strOut++ = '!';
+ }
+ }
+ *strOut++ = '\0';
+
+ if ((elem.type == EVENT_TYPE_UNKNOWN) && !elem.complete) {
+ fprintf(stderr, "Binary log entry conversion failed\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const char *event_test_int32(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint32_t);
+
+ return "1076895760";
+}
+
+static const char *event_test_int64(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint64_t);
+
+ return "-9191740941672636400";
+}
+
+static const char *event_test_list_int64(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint64_t);
+
+ return "[-9191740941672636400]";
+}
+
+static const char *event_test_simple_automagic_list(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ // The convenience API where we allow a simple list to be
+ // created without explicit begin or end calls.
+ EXPECT_LE(0, android_log_write_int32(ctx, 0x40302010));
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x8070605040302010));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint64_t);
+
+ return "[1076895760,-9191740941672636400]";
+}
+
+static const char *event_test_list_empty(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint8_t);
+
+ return "[]";
+}
+
+static const char *event_test_complex_nested_list(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+
+ EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
+ EXPECT_LE(0, android_log_write_int32(ctx, 0x01020304));
+ EXPECT_LE(0, android_log_write_int64(ctx, 0x0102030405060708));
+ EXPECT_LE(0, android_log_write_string8(ctx, "Hello World"));
+ EXPECT_LE(0, android_log_write_list_begin(ctx)); // [
+ EXPECT_LE(0, android_log_write_int32(ctx, 1));
+ EXPECT_LE(0, android_log_write_int32(ctx, 2));
+ EXPECT_LE(0, android_log_write_int32(ctx, 3));
+ EXPECT_LE(0, android_log_write_int32(ctx, 4));
+ EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
+ EXPECT_LE(0, android_log_write_float32(ctx, 1.0102030405060708));
+ EXPECT_LE(0, android_log_write_list_end(ctx)); // ]
+
+ //
+ // This one checks for the automagic list creation because a list
+ // begin and end was missing for it! This is actually an <oops> corner
+ // case, and not the behavior we morally support. The automagic API is to
+ // allow for a simple case of a series of objects in a single list. e.g.
+ // int32,int32,int32,string -> [int32,int32,int32,string]
+ //
+ EXPECT_LE(0, android_log_write_string8(ctx, "dlroW olleH"));
+
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint8_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint64_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) +
+ sizeof("Hello World") - 1 +
+ sizeof(uint8_t) + sizeof(uint8_t) +
+ 4 * (sizeof(uint8_t) + sizeof(uint32_t)) +
+ sizeof(uint8_t) + sizeof(uint32_t) +
+ sizeof(uint8_t) + sizeof(uint32_t) +
+ sizeof("dlroW olleH") - 1;
+
+ return "[[16909060,72623859790382856,Hello World,[1,2,3,4],1.010203],dlroW olleH]";
+}
+
+static const char *event_test_7_level_prefix(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 1));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 2));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 3));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 4));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 5));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 6));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 7));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) + 7 *
+ (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
+
+ return "[[[[[[[1],2],3],4],5],6],7]";
+}
+
+static const char *event_test_7_level_suffix(uint32_t tag, size_t &expected_len) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(tag)));
+ if (!ctx) {
+ return NULL;
+ }
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 1));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 2));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 3));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 4));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 5));
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, 6));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list_end(ctx));
+ EXPECT_LE(0, android_log_write_list(ctx, LOG_ID_EVENTS));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+
+ expected_len = sizeof(uint32_t) + 6 *
+ (sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint8_t) + sizeof(uint32_t));
+
+ return "[1,[2,[3,[4,[5,[6]]]]]]";
+}
+
+// make sure all user buffers are flushed
+static void print_barrier() {
+ std::cout.flush();
+ fflush(stdout);
+ std::cerr.flush();
+ fflush(stderr); // everything else is paranoia ...
+}
+
+static void create_android_logger(const char *(*fn)(uint32_t tag, size_t &expected_len)) {
+ struct logger_list *logger_list;
+
+ pid_t pid = getpid();
+
+ ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+ LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, pid)));
+
+ log_time ts(android_log_clockid());
+
+ size_t expected_len;
+ const char *expected_string = (*fn)(1005, expected_len);
+
+ if (!expected_string) {
+ android_logger_list_close(logger_list);
+ return;
+ }
+
+ usleep(1000000);
+
+ int count = 0;
+
+ for (;;) {
+ log_msg log_msg;
+ if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+ break;
+ }
+
+ ASSERT_EQ(log_msg.entry.pid, pid);
+
+ if ((log_msg.entry.sec < (ts.tv_sec - 1))
+ || ((ts.tv_sec + 1) < log_msg.entry.sec)
+ || ((size_t)log_msg.entry.len != expected_len)
+ || (log_msg.id() != LOG_ID_EVENTS)) {
+ continue;
+ }
+
+ char *eventData = log_msg.msg();
+
+ ++count;
+
+ AndroidLogFormat *logformat = android_log_format_new();
+ EXPECT_TRUE(NULL != logformat);
+ AndroidLogEntry entry;
+ char msgBuf[1024];
+ int processBinaryLogBuffer = android_log_processBinaryLogBuffer(
+ &log_msg.entry_v1, &entry, NULL, msgBuf, sizeof(msgBuf));
+ EXPECT_EQ(0, processBinaryLogBuffer);
+ if (processBinaryLogBuffer == 0) {
+ print_barrier();
+ int printLogLine = android_log_printLogLine(
+ logformat, fileno(stderr), &entry);
+ print_barrier();
+ EXPECT_EQ(20 + (int)strlen(expected_string), printLogLine);
+ }
+ android_log_format_free(logformat);
+
+ // test buffer reading API
+ snprintf(msgBuf, sizeof(msgBuf), "I/[%d]", get4LE(eventData));
+ print_barrier();
+ fprintf(stderr, "%-10s(%5u): ", msgBuf, pid);
+ memset(msgBuf, 0, sizeof(msgBuf));
+ int buffer_to_string = android_log_buffer_to_string(
+ eventData + sizeof(uint32_t),
+ log_msg.entry.len - sizeof(uint32_t),
+ msgBuf, sizeof(msgBuf));
+ fprintf(stderr, "%s\n", msgBuf);
+ print_barrier();
+ EXPECT_EQ(0, buffer_to_string);
+ EXPECT_EQ(strlen(expected_string), strlen(msgBuf));
+ EXPECT_EQ(0, strcmp(expected_string, msgBuf));
+ }
+
+ EXPECT_EQ(1, count);
+
+ android_logger_list_close(logger_list);
+}
+
+TEST(liblog, create_android_logger_int32) {
+ create_android_logger(event_test_int32);
+}
+
+TEST(liblog, create_android_logger_int64) {
+ create_android_logger(event_test_int64);
+}
+
+TEST(liblog, create_android_logger_list_int64) {
+ create_android_logger(event_test_list_int64);
+}
+
+TEST(liblog, create_android_logger_simple_automagic_list) {
+ create_android_logger(event_test_simple_automagic_list);
+}
+
+TEST(liblog, create_android_logger_list_empty) {
+ create_android_logger(event_test_list_empty);
+}
+
+TEST(liblog, create_android_logger_complex_nested_list) {
+ create_android_logger(event_test_complex_nested_list);
+}
+
+TEST(liblog, create_android_logger_7_level_prefix) {
+ create_android_logger(event_test_7_level_prefix);
+}
+
+TEST(liblog, create_android_logger_7_level_suffix) {
+ create_android_logger(event_test_7_level_suffix);
+}
+
+TEST(liblog, create_android_logger_overflow) {
+ android_log_context ctx;
+
+ EXPECT_TRUE(NULL != (ctx = create_android_logger(1005)));
+ if (ctx) {
+ for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ }
+ EXPECT_GT(0, android_log_write_list_begin(ctx));
+ /* One more for good measure, must be permanently unhappy */
+ EXPECT_GT(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ EXPECT_TRUE(NULL == ctx);
+ }
+
+ ASSERT_TRUE(NULL != (ctx = create_android_logger(1005)));
+ for (size_t i = 0; i < ANDROID_MAX_LIST_NEST_DEPTH; ++i) {
+ EXPECT_LE(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_write_int32(ctx, i));
+ }
+ EXPECT_GT(0, android_log_write_list_begin(ctx));
+ /* One more for good measure, must be permanently unhappy */
+ EXPECT_GT(0, android_log_write_list_begin(ctx));
+ EXPECT_LE(0, android_log_destroy(&ctx));
+ ASSERT_TRUE(NULL == ctx);
+}
diff --git a/libmemunreachable/MemUnreachable.cpp b/libmemunreachable/MemUnreachable.cpp
index cb3f1a5..eca26eb 100644
--- a/libmemunreachable/MemUnreachable.cpp
+++ b/libmemunreachable/MemUnreachable.cpp
@@ -224,16 +224,19 @@
// ptrace all the threads
if (!thread_capture.CaptureThreads()) {
+ continue_parent_sem.Post();
return 1;
}
// collect register contents and stacks
if (!thread_capture.CapturedThreadInfo(thread_info)) {
+ continue_parent_sem.Post();
return 1;
}
// snapshot /proc/pid/maps
if (!ProcessMappings(parent_pid, mappings)) {
+ continue_parent_sem.Post();
return 1;
}
@@ -306,7 +309,7 @@
// Wait for the collection thread to signal that it is ready to fork the
// heap walker process.
- continue_parent_sem.Wait(100s);
+ continue_parent_sem.Wait(30s);
// Re-enable malloc so the collection thread can fork.
}
@@ -347,7 +350,7 @@
std::ostringstream oss;
oss << " " << std::dec << size;
- oss << " bytes at ";
+ oss << " bytes unreachable at ";
oss << std::hex << begin;
oss << std::endl;
@@ -405,7 +408,7 @@
std::string GetUnreachableMemoryString(bool log_contents, size_t limit) {
UnreachableMemoryInfo info;
if (!GetUnreachableMemory(info, limit)) {
- return "Failed to get unreachable memory";
+ return "Failed to get unreachable memory\n";
}
return info.ToString(log_contents);
diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h
index da07253..2dec71f 100644
--- a/libnativeloader/include/nativeloader/native_loader.h
+++ b/libnativeloader/include/nativeloader/native_loader.h
@@ -19,6 +19,9 @@
#include "jni.h"
#include <stdint.h>
+#if defined(__ANDROID__)
+#include <android/dlext.h>
+#endif
namespace android {
@@ -27,6 +30,13 @@
jobject class_loader, bool is_shared, jstring library_path,
jstring permitted_path);
+#if defined(__ANDROID__)
+// Look up linker namespace by class_loader. Returns nullptr if
+// there is no namespace associated with the class_loader.
+__attribute__((visibility("default")))
+android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader);
+#endif
+
}; // namespace android
#endif // NATIVE_BRIDGE_H_
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index a7a0713..a64b972 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -79,10 +79,10 @@
std::lock_guard<std::mutex> guard(mutex_);
- auto it = FindNamespaceByClassLoader(env, class_loader);
+ android_namespace_t* ns = FindNamespaceByClassLoader(env, class_loader);
- if (it != namespaces_.end()) {
- return it->second;
+ if (ns != nullptr) {
+ return ns;
}
uint64_t namespace_type = ANDROID_NAMESPACE_TYPE_ISOLATED;
@@ -90,20 +90,27 @@
namespace_type |= ANDROID_NAMESPACE_TYPE_SHARED;
}
- android_namespace_t* ns =
- android_create_namespace("classloader-namespace",
- nullptr,
- library_path.c_str(),
- namespace_type,
- java_permitted_path != nullptr ?
- permitted_path.c_str() :
- nullptr);
+ ns = android_create_namespace("classloader-namespace",
+ nullptr,
+ library_path.c_str(),
+ namespace_type,
+ java_permitted_path != nullptr ?
+ permitted_path.c_str() :
+ nullptr);
namespaces_.push_back(std::make_pair(env->NewWeakGlobalRef(class_loader), ns));
return ns;
}
+ android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ auto it = std::find_if(namespaces_.begin(), namespaces_.end(),
+ [&](const std::pair<jweak, android_namespace_t*>& value) {
+ return env->IsSameObject(value.first, class_loader);
+ });
+ return it != namespaces_.end() ? it->second : nullptr;
+ }
+
private:
void PreloadPublicLibraries() {
// android_init_namespaces() expects all the public libraries
@@ -122,14 +129,6 @@
return initialized_;
}
- std::vector<std::pair<jweak, android_namespace_t*>>::const_iterator
- FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
- return std::find_if(namespaces_.begin(), namespaces_.end(),
- [&](const std::pair<jweak, android_namespace_t*>& value) {
- return env->IsSameObject(value.first, class_loader);
- });
- }
-
bool initialized_;
std::mutex mutex_;
std::vector<std::pair<jweak, android_namespace_t*>> namespaces_;
@@ -169,4 +168,10 @@
#endif
}
+#if defined(__ANDROID__)
+android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader) {
+ return g_namespaces->FindNamespaceByClassLoader(env, class_loader);
+}
+#endif
+
}; // android namespace