aboutsummaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'daemon')
-rw-r--r--daemon/adb_wifi.cpp5
-rw-r--r--daemon/auth.cpp2
-rw-r--r--daemon/file_sync_service.cpp2
-rw-r--r--daemon/jdwp_service.cpp13
-rw-r--r--daemon/jdwp_service.h24
-rw-r--r--daemon/main.cpp5
-rw-r--r--daemon/restart_service_test.cpp76
-rw-r--r--daemon/services.cpp34
-rw-r--r--daemon/shell_service_test.cpp78
-rw-r--r--daemon/usb.cpp19
10 files changed, 161 insertions, 97 deletions
diff --git a/daemon/adb_wifi.cpp b/daemon/adb_wifi.cpp
index 2f9e9b4d..2de219d8 100644
--- a/daemon/adb_wifi.cpp
+++ b/daemon/adb_wifi.cpp
@@ -69,7 +69,7 @@ TlsServer::TlsServer(int port) : port_(port) {}
TlsServer::~TlsServer() {
fdevent* fde = fd_event_;
- fdevent_run_on_main_thread([fde]() {
+ fdevent_run_on_looper([fde]() {
if (fde != nullptr) {
fdevent_destroy(fde);
}
@@ -104,7 +104,7 @@ bool TlsServer::Start() {
LOG(INFO) << "adbwifi started on port " << port_;
std::unique_lock<std::mutex> lock(mutex);
- fdevent_run_on_main_thread([&]() {
+ fdevent_run_on_looper([&]() {
fd_event_ = fdevent_create(fd.release(), &TlsServer::StaticOnFdEvent, this);
if (fd_event_ == nullptr) {
LOG(ERROR) << "Failed to create fd event for TlsServer.";
@@ -194,6 +194,7 @@ static void start_wifi_enabled_observer() {
while (true) {
std::string toggled_val = wifi_enabled ? "0" : "1";
LOG(INFO) << "Waiting for " << kWifiEnabledProp << "=" << toggled_val;
+
if (WaitForProperty(kWifiEnabledProp, toggled_val)) {
wifi_enabled = !wifi_enabled;
LOG(INFO) << kWifiEnabledProp << " changed to " << toggled_val;
diff --git a/daemon/auth.cpp b/daemon/auth.cpp
index 2c3844ba..d2f6d6bb 100644
--- a/daemon/auth.cpp
+++ b/daemon/auth.cpp
@@ -209,7 +209,7 @@ void adbd_cloexec_auth_socket() {
static void adbd_auth_key_authorized(void* arg, uint64_t id) {
LOG(INFO) << "adb client " << id << " authorized";
- fdevent_run_on_main_thread([=]() {
+ fdevent_run_on_looper([=]() {
auto* transport = transport_from_callback_arg(arg);
if (!transport) {
LOG(ERROR) << "authorization received for deleted transport (" << id << "), ignoring";
diff --git a/daemon/file_sync_service.cpp b/daemon/file_sync_service.cpp
index b59da972..f594d646 100644
--- a/daemon/file_sync_service.cpp
+++ b/daemon/file_sync_service.cpp
@@ -317,7 +317,7 @@ static bool handle_send_file_data(borrowed_fd s, unique_fd fd, uint32_t* timesta
std::span<char> output;
DecodeResult result = decoder->Decode(&output);
if (result == DecodeResult::Error) {
- SendSyncFailErrno(s, "decompress failed");
+ SendSyncFail(s, "decompress failed");
return false;
}
diff --git a/daemon/jdwp_service.cpp b/daemon/jdwp_service.cpp
index adae9f7f..2501688c 100644
--- a/daemon/jdwp_service.cpp
+++ b/daemon/jdwp_service.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#if !ADB_HOST
-
#if !defined(__ANDROID_RECOVERY__)
#define TRACE_TAG JDWP
@@ -461,12 +459,16 @@ static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) {
}
static asocket* create_process_tracker_service_socket(TrackerKind kind) {
- auto t = std::make_unique<JdwpTracker>(kind, true);
+ std::unique_ptr<JdwpTracker> t = std::make_unique<JdwpTracker>(kind, true);
if (!t) {
LOG(FATAL) << "failed to allocate JdwpTracker";
}
- memset(t.get(), 0, sizeof(asocket));
+ /* Object layout (with an inheritance hierarchy) varies across arch (e.g
+ * armv7a/Android TV vs aarch64), so no assumptions can be made about
+ * accessing fields based on offsets (e.g memset(t.get(), 0, sizeof(asocket))
+ * might clobber an unintended memory location).
+ */
install_local_socket(t.get());
D("LS(%d): created new jdwp tracker service", t->id);
@@ -495,7 +497,7 @@ int init_jdwp(void) {
adb_thread_setname("jdwp control");
adbconnection_listen([](int fd, ProcessInfo process) {
LOG(INFO) << "jdwp connection from " << process.pid;
- fdevent_run_on_main_thread([fd, process] {
+ fdevent_run_on_looper([fd, process] {
unique_fd ufd(fd);
auto proc = std::make_unique<JdwpProcess>(std::move(ufd), process);
if (!proc) {
@@ -534,4 +536,3 @@ int init_jdwp() {
}
#endif /* defined(__ANDROID_RECOVERY__) */
-#endif /* !ADB_HOST */
diff --git a/daemon/jdwp_service.h b/daemon/jdwp_service.h
new file mode 100644
index 00000000..1daa0f9d
--- /dev/null
+++ b/daemon/jdwp_service.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 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 "adb_unique_fd.h"
+#include "socket.h"
+
+int init_jdwp(void);
+asocket* create_jdwp_service_socket();
+asocket* create_jdwp_tracker_service_socket();
+asocket* create_app_tracker_service_socket();
+unique_fd create_jdwp_connection_fd(int jdwp_pid); \ No newline at end of file
diff --git a/daemon/main.cpp b/daemon/main.cpp
index 1efa797c..677e853b 100644
--- a/daemon/main.cpp
+++ b/daemon/main.cpp
@@ -57,6 +57,7 @@
#include "socket_spec.h"
#include "transport.h"
+#include "daemon/jdwp_service.h"
#include "daemon/mdns.h"
#include "daemon/watchdog.h"
@@ -159,6 +160,9 @@ static void drop_privileges(int server_port) {
if (root_seclabel != nullptr) {
if (selinux_android_setcon(root_seclabel) < 0) {
+ // If we failed to become root, don't try again to avoid a
+ // restart loop.
+ android::base::SetProperty("service.adb.root", "0");
LOG(FATAL) << "Could not set SELinux context";
}
}
@@ -317,6 +321,7 @@ int main(int argc, char** argv) {
{"device_banner", required_argument, nullptr, 'b'},
{"version", no_argument, nullptr, 'v'},
{"logpostfsdata", no_argument, nullptr, 'l'},
+ {nullptr, no_argument, nullptr, 0},
};
int option_index = 0;
diff --git a/daemon/restart_service_test.cpp b/daemon/restart_service_test.cpp
new file mode 100644
index 00000000..d2ae67cf
--- /dev/null
+++ b/daemon/restart_service_test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2023 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 "restart_service.h"
+
+#include <time.h>
+#include <string>
+
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <gtest/gtest.h>
+
+#include "services.h"
+#include "sysdeps.h"
+#include "test_utils/test_utils.h"
+
+using namespace test_utils;
+
+// Test successful execution of tcp restart.
+TEST(RestartServiceTest, RestartTcpServiceValidPortSuccess) {
+ // Identify an available port from the system allocated pool.
+ // The objective is to do a best guess attempt at randomizing the
+ // specified port on which the restart service listens.
+ unique_fd dontcare;
+ const int assigned_port(test_utils::GetUnassignedPort(dontcare));
+
+ unique_fd command_fd_ = create_service_thread(
+ "tcp", std::bind(restart_tcp_service, std::placeholders::_1, assigned_port));
+ EXPECT_GE(command_fd_.get(), 0);
+ test_utils::ExpectLinesEqual(
+ ReadRaw(command_fd_),
+ {android::base::StringPrintf("restarting in TCP mode port: %d", assigned_port)});
+
+ EXPECT_EQ(android::base::GetProperty("service.adb.tcp.port", ""),
+ std::to_string(assigned_port));
+}
+
+// Test failure path of tcp restart.
+TEST(RestartServiceTest, RestartTcpServiceInvalidPortFailure) {
+ const std::string port_str = android::base::GetProperty("service.adb.tcp.port", "");
+
+ const int port = -5;
+ unique_fd command_fd_ = create_service_thread(
+ "tcp", std::bind(restart_tcp_service, std::placeholders::_1, port));
+ EXPECT_GE(command_fd_, 0);
+ test_utils::ExpectLinesEqual(ReadRaw(command_fd_),
+ {android::base::StringPrintf("invalid port %d", port)});
+
+ // Validate that there's no mutation.
+ EXPECT_EQ(android::base::GetProperty("service.adb.tcp.port", ""), port_str);
+}
+
+// Test successful execution of usb restart.
+TEST(RestartServiceTest, RestartUsbServiceSuccess) {
+ unique_fd command_fd_ = create_service_thread("usb", restart_usb_service);
+ EXPECT_GE(command_fd_, 0);
+
+ test_utils::ExpectLinesEqual(ReadRaw(command_fd_),
+ {android::base::StringPrintf("restarting in USB mode")});
+
+ EXPECT_EQ(android::base::GetProperty("service.adb.tcp.port", ""), "0");
+}
diff --git a/daemon/services.cpp b/daemon/services.cpp
index d86b54a0..07fbe328 100644
--- a/daemon/services.cpp
+++ b/daemon/services.cpp
@@ -49,10 +49,12 @@
#include "adb_utils.h"
#include "services.h"
#include "socket_spec.h"
+#include "sysdeps.h"
#include "transport.h"
#include "daemon/file_sync_service.h"
#include "daemon/framebuffer_service.h"
+#include "daemon/jdwp_service.h"
#include "daemon/logging.h"
#include "daemon/restart_service.h"
#include "daemon/shell_service.h"
@@ -131,7 +133,7 @@ static void spin_service(unique_fd fd) {
return;
}
- fdevent_run_on_main_thread([fd = pipe_read.release()]() {
+ fdevent_run_on_looper([fd = pipe_read.release()]() {
fdevent* fde = fdevent_create(
fd, [](int, unsigned, void*) {}, nullptr);
fdevent_add(fde, FDE_READ);
@@ -161,9 +163,14 @@ static void spin_service(unique_fd fd) {
}
struct ServiceSocket : public asocket {
- ServiceSocket() {
+ ServiceSocket() = delete;
+ explicit ServiceSocket(atransport* transport) {
+ CHECK(transport);
install_local_socket(this);
+ this->transport = transport;
this->enqueue = [](asocket* self, apacket::payload_type data) {
+ // TODO: This interface currently can't give any backpressure.
+ send_ready(self->id, self->peer->id, self->transport, data.size());
return static_cast<ServiceSocket*>(self)->Enqueue(std::move(data));
};
this->ready = [](asocket* self) { return static_cast<ServiceSocket*>(self)->Ready(); };
@@ -171,6 +178,11 @@ struct ServiceSocket : public asocket {
}
virtual ~ServiceSocket() = default;
+ ServiceSocket(const ServiceSocket& copy) = delete;
+ ServiceSocket(ServiceSocket&& move) = delete;
+ ServiceSocket& operator=(const ServiceSocket& copy) = delete;
+ ServiceSocket& operator=(ServiceSocket&& move) = delete;
+
virtual int Enqueue(apacket::payload_type data) { return -1; }
virtual void Ready() {}
virtual void Close() {
@@ -188,9 +200,9 @@ struct ServiceSocket : public asocket {
};
struct SinkSocket : public ServiceSocket {
- explicit SinkSocket(size_t byte_count) {
+ explicit SinkSocket(atransport* transport, size_t byte_count)
+ : ServiceSocket(transport), bytes_left_(byte_count) {
LOG(INFO) << "Creating new SinkSocket with capacity " << byte_count;
- bytes_left_ = byte_count;
}
virtual ~SinkSocket() { LOG(INFO) << "SinkSocket destroyed"; }
@@ -210,9 +222,9 @@ struct SinkSocket : public ServiceSocket {
};
struct SourceSocket : public ServiceSocket {
- explicit SourceSocket(size_t byte_count) {
+ explicit SourceSocket(atransport* transport, size_t byte_count)
+ : ServiceSocket(transport), bytes_left_(byte_count) {
LOG(INFO) << "Creating new SourceSocket with capacity " << byte_count;
- bytes_left_ = byte_count;
}
virtual ~SourceSocket() { LOG(INFO) << "SourceSocket destroyed"; }
@@ -235,7 +247,7 @@ struct SourceSocket : public ServiceSocket {
size_t bytes_left_;
};
-asocket* daemon_service_to_socket(std::string_view name) {
+asocket* daemon_service_to_socket(std::string_view name, atransport* transport) {
if (name == "jdwp") {
return create_jdwp_service_socket();
} else if (name == "track-jdwp") {
@@ -247,13 +259,13 @@ asocket* daemon_service_to_socket(std::string_view name) {
if (!ParseUint(&byte_count, name)) {
return nullptr;
}
- return new SinkSocket(byte_count);
+ return new SinkSocket(transport, byte_count);
} else if (android::base::ConsumePrefix(&name, "source:")) {
uint64_t byte_count = 0;
if (!ParseUint(&byte_count, name)) {
return nullptr;
}
- return new SourceSocket(byte_count);
+ return new SourceSocket(transport, byte_count);
}
return nullptr;
@@ -308,7 +320,9 @@ unique_fd daemon_service_to_fd(std::string_view name, atransport* transport) {
}
#endif
- if (android::base::ConsumePrefix(&name, "jdwp:")) {
+ if (android::base::ConsumePrefix(&name, "dev:")) {
+ return unique_fd{unix_open(name, O_RDWR | O_CLOEXEC)};
+ } else if (android::base::ConsumePrefix(&name, "jdwp:")) {
pid_t pid;
if (!ParseUint(&pid, name)) {
return unique_fd{};
diff --git a/daemon/shell_service_test.cpp b/daemon/shell_service_test.cpp
index cdd8dbed..f61aaebd 100644
--- a/daemon/shell_service_test.cpp
+++ b/daemon/shell_service_test.cpp
@@ -29,6 +29,9 @@
#include "adb_io.h"
#include "shell_protocol.h"
#include "sysdeps.h"
+#include "test_utils/test_utils.h"
+
+using namespace test_utils;
class ShellServiceTest : public ::testing::Test {
public:
@@ -74,81 +77,6 @@ void ShellServiceTest::StartTestCommandInProcess(std::string name, Command comma
ASSERT_TRUE(command_fd_ >= 0);
}
-namespace {
-
-// Reads raw data from |fd| until it closes or errors.
-std::string ReadRaw(borrowed_fd fd) {
- char buffer[1024];
- char *cur_ptr = buffer, *end_ptr = buffer + sizeof(buffer);
-
- while (1) {
- int bytes = adb_read(fd, cur_ptr, end_ptr - cur_ptr);
- if (bytes <= 0) {
- return std::string(buffer, cur_ptr);
- }
- cur_ptr += bytes;
- }
-}
-
-// Reads shell protocol data from |fd| until it closes or errors. Fills
-// |stdout| and |stderr| with their respective data, and returns the exit code
-// read from the protocol or -1 if an exit code packet was not received.
-int ReadShellProtocol(borrowed_fd fd, std::string* stdout, std::string* stderr) {
- int exit_code = -1;
- stdout->clear();
- stderr->clear();
-
- auto protocol = std::make_unique<ShellProtocol>(fd.get());
- while (protocol->Read()) {
- switch (protocol->id()) {
- case ShellProtocol::kIdStdout:
- stdout->append(protocol->data(), protocol->data_length());
- break;
- case ShellProtocol::kIdStderr:
- stderr->append(protocol->data(), protocol->data_length());
- break;
- case ShellProtocol::kIdExit:
- EXPECT_EQ(-1, exit_code) << "Multiple exit packets received";
- EXPECT_EQ(1u, protocol->data_length());
- exit_code = protocol->data()[0];
- break;
- default:
- ADD_FAILURE() << "Unidentified packet ID: " << protocol->id();
- }
- }
-
- return exit_code;
-}
-
-// Checks if each line in |lines| exists in the same order in |output|. Blank
-// lines in |output| are ignored for simplicity.
-bool ExpectLinesEqual(const std::string& output,
- const std::vector<std::string>& lines) {
- auto output_lines = android::base::Split(output, "\r\n");
- size_t i = 0;
-
- for (const std::string& line : lines) {
- // Skip empty lines in output.
- while (i < output_lines.size() && output_lines[i].empty()) {
- ++i;
- }
- if (i >= output_lines.size()) {
- ADD_FAILURE() << "Ran out of output lines";
- return false;
- }
- EXPECT_EQ(line, output_lines[i]);
- ++i;
- }
-
- while (i < output_lines.size() && output_lines[i].empty()) {
- ++i;
- }
- EXPECT_EQ(i, output_lines.size()) << "Found unmatched output lines";
- return true;
-}
-
-} // namespace
-
// Tests a raw subprocess with no protocol.
TEST_F(ShellServiceTest, RawNoProtocolSubprocess) {
// [ -t 0 ] checks if stdin is connected to a terminal.
diff --git a/daemon/usb.cpp b/daemon/usb.cpp
index 6c3f735e..f9e085fb 100644
--- a/daemon/usb.cpp
+++ b/daemon/usb.cpp
@@ -61,10 +61,10 @@ using android::base::StringPrintf;
// Also, each submitted operation does an allocation in the kernel of that size, so we want to
// minimize our queue depth while still maintaining a deep enough queue to keep the USB stack fed.
static constexpr size_t kUsbReadQueueDepth = 8;
-static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE;
+static constexpr size_t kUsbReadSize = 16384;
static constexpr size_t kUsbWriteQueueDepth = 8;
-static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE;
+static constexpr size_t kUsbWriteSize = 16384;
static const char* to_string(enum usb_functionfs_event_type type) {
switch (type) {
@@ -567,6 +567,10 @@ struct UsbFfsConnection : public Connection {
memcpy(&msg, block->payload.data(), sizeof(msg));
LOG(DEBUG) << "USB read:" << dump_header(&msg);
incoming_header_ = msg;
+
+ if (msg.command == A_CNXN) {
+ CancelWrites();
+ }
} else {
size_t bytes_left = incoming_header_->data_length - incoming_payload_.size();
if (block->payload.size() > bytes_left) {
@@ -676,6 +680,17 @@ struct UsbFfsConnection : public Connection {
}
}
+ void CancelWrites() {
+ std::lock_guard<std::mutex> lock(write_mutex_);
+ for (size_t i = 0; i < writes_submitted_; ++i) {
+ struct io_event res;
+ if (write_requests_[i].pending == true) {
+ LOG(INFO) << "cancelling pending write# " << i;
+ io_cancel(aio_context_.get(), &write_requests_[i].control, &res);
+ }
+ }
+ }
+
void HandleError(const std::string& error) {
std::call_once(error_flag_, [&]() {
if (transport_) {