diff options
Diffstat (limited to 'daemon')
-rw-r--r-- | daemon/adb_wifi.cpp | 5 | ||||
-rw-r--r-- | daemon/auth.cpp | 2 | ||||
-rw-r--r-- | daemon/file_sync_service.cpp | 2 | ||||
-rw-r--r-- | daemon/jdwp_service.cpp | 13 | ||||
-rw-r--r-- | daemon/jdwp_service.h | 24 | ||||
-rw-r--r-- | daemon/main.cpp | 5 | ||||
-rw-r--r-- | daemon/restart_service_test.cpp | 76 | ||||
-rw-r--r-- | daemon/services.cpp | 34 | ||||
-rw-r--r-- | daemon/shell_service_test.cpp | 78 | ||||
-rw-r--r-- | daemon/usb.cpp | 19 |
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_) { |