diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h --- a/lldb/include/lldb/Target/Platform.h +++ b/lldb/include/lldb/Target/Platform.h @@ -1143,6 +1143,33 @@ operator=(const OptionGroupPlatformSSH &) = delete; }; +class OptionGroupPlatformAndroid : public lldb_private::OptionGroup { +public: + OptionGroupPlatformAndroid() = default; + + ~OptionGroupPlatformAndroid() override = default; + + lldb_private::Status + SetOptionValue(uint32_t option_idx, llvm::StringRef option_value, + ExecutionContext *execution_context) override; + + void OptionParsingStarting(ExecutionContext *execution_context) override; + + llvm::ArrayRef GetDefinitions() override; + + // Instance variables to hold the values for command options. + + std::string m_android_serial; + std::string m_adb_server_port; + std::string m_platform_local_port; + std::string m_gdb_local_port; + +private: + OptionGroupPlatformAndroid(const OptionGroupPlatformAndroid &) = delete; + const OptionGroupPlatformAndroid & + operator=(const OptionGroupPlatformAndroid &) = delete; +}; + class OptionGroupPlatformCaching : public lldb_private::OptionGroup { public: OptionGroupPlatformCaching() = default; diff --git a/lldb/source/Plugins/Platform/Android/AdbClient.h b/lldb/source/Plugins/Platform/Android/AdbClient.h --- a/lldb/source/Plugins/Platform/Android/AdbClient.h +++ b/lldb/source/Plugins/Platform/Android/AdbClient.h @@ -73,17 +73,24 @@ std::unique_ptr m_conn; }; - static Status CreateByDeviceID(const std::string &device_id, AdbClient &adb); + static Status CreateByDeviceID(const std::string &device_id, + const std::string &server_port, + AdbClient &adb); AdbClient(); - explicit AdbClient(const std::string &device_id); + explicit AdbClient(const std::string &device_id, + const std::string &server_port); ~AdbClient(); const std::string &GetDeviceID() const; + const std::string &GetServerPort() const; + Status GetDevices(DeviceIDList &device_list); + Status GetSerialNo(std::string *output); + Status SetPortForwarding(const uint16_t local_port, const uint16_t remote_port); @@ -108,6 +115,8 @@ void SetDeviceID(const std::string &device_id); + void SetServerPort(const std::string &server_port); + Status SendMessage(const std::string &packet, const bool reconnect = true); Status SendDeviceMessage(const std::string &packet); @@ -131,6 +140,7 @@ Status ReadAllBytes(void *buffer, size_t size); std::string m_device_id; + std::string m_server_port; std::unique_ptr m_conn; }; diff --git a/lldb/source/Plugins/Platform/Android/AdbClient.cpp b/lldb/source/Plugins/Platform/Android/AdbClient.cpp --- a/lldb/source/Plugins/Platform/Android/AdbClient.cpp +++ b/lldb/source/Plugins/Platform/Android/AdbClient.cpp @@ -89,8 +89,16 @@ } Status AdbClient::CreateByDeviceID(const std::string &device_id, + const std::string &server_port, AdbClient &adb) { Status error; + std::string port = "5037"; + if (!server_port.empty()) + port = server_port; + else if (const char *env_port = std::getenv("ANDROID_ADB_SERVER_PORT")) + port = env_port; + adb.SetServerPort(port); + std::string android_serial; if (!device_id.empty()) android_serial = device_id; @@ -105,7 +113,7 @@ if (connected_devices.size() != 1) return Status("Expected a single connected device, got instead %zu - try " - "setting 'ANDROID_SERIAL'", + "using --android-serial or setting 'ANDROID_SERIAL'", connected_devices.size()); adb.SetDeviceID(connected_devices.front()); } else { @@ -116,7 +124,9 @@ AdbClient::AdbClient() = default; -AdbClient::AdbClient(const std::string &device_id) : m_device_id(device_id) {} +AdbClient::AdbClient(const std::string &device_id, + const std::string &server_port) + : m_device_id(device_id), m_server_port(server_port) {} AdbClient::~AdbClient() = default; @@ -124,16 +134,18 @@ m_device_id = device_id; } +void AdbClient::SetServerPort(const std::string &server_port) { + m_server_port = server_port; +} + const std::string &AdbClient::GetDeviceID() const { return m_device_id; } +const std::string &AdbClient::GetServerPort() const { return m_server_port; } + Status AdbClient::Connect() { Status error; m_conn = std::make_unique(); - std::string port = "5037"; - if (const char *env_port = std::getenv("ANDROID_ADB_SERVER_PORT")) { - port = env_port; - } - std::string uri = "connect://127.0.0.1:" + port; + std::string uri = "connect://127.0.0.1:" + m_server_port; m_conn->Connect(uri.c_str(), &error); return error; @@ -166,6 +178,24 @@ return error; } +Status AdbClient::GetSerialNo(std::string *output) { + const char *message = "get-serialno"; + auto error = SendDeviceMessage(message); + if (error.Fail()) + return error; + + error = ReadResponseStatus(); + if (error.Fail()) + return error; + + std::vector output_buffer; + error = ReadMessage(output_buffer); + if (error.Success() && output) + output->assign(output_buffer.begin(), output_buffer.end()); + + return error; +} + Status AdbClient::SetPortForwarding(const uint16_t local_port, const uint16_t remote_port) { char message[48]; diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h --- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.h +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.h @@ -13,6 +13,7 @@ #include #include "Plugins/Platform/Linux/PlatformLinux.h" +#include "lldb/Interpreter/Options.h" #include "AdbClient.h" @@ -42,6 +43,9 @@ // lldb_private::Platform functions + lldb_private::OptionGroupOptions * + GetConnectionOptions(lldb_private::CommandInterpreter &interpreter) override; + Status ConnectRemote(Args &args) override; Status GetFile(const FileSpec &source, const FileSpec &destination) override; @@ -71,14 +75,18 @@ GetLibdlFunctionDeclarations(lldb_private::Process *process) override; private: + std::unique_ptr + m_option_group_platform_android; + AdbClient::SyncService *GetSyncService(Status &error); std::unique_ptr m_adb_sync_svc; std::string m_device_id; + std::string m_adb_server_port; uint32_t m_sdk_version; }; -} // namespace platofor_android +} // namespace platform_android } // namespace lldb_private #endif // LLDB_SOURCE_PLUGINS_PLATFORM_ANDROID_PLATFORMANDROID_H diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp --- a/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp @@ -128,7 +128,22 @@ } PlatformAndroid::PlatformAndroid(bool is_host) - : PlatformLinux(is_host), m_sdk_version(0) {} + : PlatformLinux(is_host), + m_option_group_platform_android(new OptionGroupPlatformAndroid()), + m_sdk_version(0) {} + +lldb_private::OptionGroupOptions *PlatformAndroid::GetConnectionOptions( + lldb_private::CommandInterpreter &interpreter) { + auto iter = m_options.find(&interpreter), end = m_options.end(); + if (iter == end) { + std::unique_ptr options( + new OptionGroupOptions()); + options->Append(m_option_group_platform_android.get()); + m_options[&interpreter] = std::move(options); + } + + return m_options.at(&interpreter).get(); +} llvm::StringRef PlatformAndroid::GetPluginDescriptionStatic(bool is_host) { if (is_host) @@ -138,13 +153,11 @@ Status PlatformAndroid::ConnectRemote(Args &args) { m_device_id.clear(); + m_adb_server_port.clear(); if (IsHost()) return Status("can't connect to the host platform, always connected"); - if (!m_remote_platform_sp) - m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer()); - const char *url = args.GetArgumentAtIndex(0); if (!url) return Status("URL is null."); @@ -154,16 +167,42 @@ if (parsed_url->hostname != "localhost") m_device_id = parsed_url->hostname.str(); - auto error = PlatformLinux::ConnectRemote(args); - if (error.Success()) { - AdbClient adb; - error = AdbClient::CreateByDeviceID(m_device_id, adb); - if (error.Fail()) - return error; - - m_device_id = adb.GetDeviceID(); + std::string platform_local_port; + std::string gdb_local_port; + const auto &option = m_option_group_platform_android.get(); + if (option) { + if (!option->m_android_serial.empty()) + m_device_id = option->m_android_serial; + if (!option->m_adb_server_port.empty()) + m_adb_server_port = option->m_adb_server_port; + if (!option->m_platform_local_port.empty()) + platform_local_port = option->m_platform_local_port; + if (!option->m_gdb_local_port.empty()) + gdb_local_port = option->m_gdb_local_port; } - return error; + + AdbClient adb; + auto error = AdbClient::CreateByDeviceID(m_device_id, m_adb_server_port, adb); + if (error.Fail()) + return error; + + std::string serial; + error = adb.GetSerialNo(&serial); + if (error.Fail()) + return error; + + Log *log = GetLog(LLDBLog::Platform); + LLDB_LOGF(log, "PlatformAndroid::%s() connected to '%s'", __FUNCTION__, + serial.c_str()); + + m_device_id = adb.GetDeviceID(); + m_adb_server_port = adb.GetServerPort(); + + if (!m_remote_platform_sp) + m_remote_platform_sp = PlatformSP(new PlatformAndroidRemoteGDBServer( + m_device_id, m_adb_server_port, platform_local_port, gdb_local_port)); + + return PlatformLinux::ConnectRemote(args); } Status PlatformAndroid::GetFile(const FileSpec &source, @@ -200,7 +239,7 @@ // mode == 0 can signify that adbd cannot access the file due security // constraints - try "cat ..." as a fallback. - AdbClient adb(m_device_id); + AdbClient adb(m_device_id, m_adb_server_port); char cmd[PATH_MAX]; snprintf(cmd, sizeof(cmd), "cat '%s'", source_file.c_str()); @@ -260,7 +299,7 @@ return m_sdk_version; std::string version_string; - AdbClient adb(m_device_id); + AdbClient adb(m_device_id, m_adb_server_port); Status error = adb.Shell("getprop ro.build.version.sdk", seconds(5), &version_string); version_string = llvm::StringRef(version_string).trim().str(); @@ -298,7 +337,7 @@ nullptr) return Status("Symtab already available in the module"); - AdbClient adb(m_device_id); + AdbClient adb(m_device_id, m_adb_server_port); std::string tmpdir; Status error = adb.Shell("mktemp --directory --tmpdir /data/local/tmp", seconds(5), &tmpdir); @@ -370,7 +409,7 @@ if (m_adb_sync_svc && m_adb_sync_svc->IsConnected()) return m_adb_sync_svc.get(); - AdbClient adb(m_device_id); + AdbClient adb(m_device_id, m_adb_server_port); m_adb_sync_svc = adb.GetSyncService(error); return (error.Success()) ? m_adb_sync_svc.get() : nullptr; } diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h --- a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h @@ -24,7 +24,11 @@ class PlatformAndroidRemoteGDBServer : public platform_gdb_server::PlatformRemoteGDBServer { public: - PlatformAndroidRemoteGDBServer() = default; + PlatformAndroidRemoteGDBServer() = delete; + explicit PlatformAndroidRemoteGDBServer(const std::string &device_id, + const std::string &adb_server_port, + const std::string &platform_local_port, + const std::string &gdb_local_port); ~PlatformAndroidRemoteGDBServer() override; @@ -40,11 +44,18 @@ protected: std::string m_device_id; + std::string m_adb_server_port; + std::string m_platform_local_port; + std::string m_gdb_local_port; std::map m_port_forwards; llvm::Optional m_socket_namespace; bool LaunchGDBServer(lldb::pid_t &pid, std::string &connect_url) override; + uint16_t GetPlatformLocalPort(); + + uint16_t GetGDBLocalPort(); + bool KillSpawnedProcess(lldb::pid_t pid) override; void DeleteForwardPort(lldb::pid_t pid); diff --git a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp --- a/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp +++ b/lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp @@ -28,15 +28,10 @@ const uint16_t local_port, const uint16_t remote_port, llvm::StringRef remote_socket_name, const llvm::Optional &socket_namespace, - std::string &device_id) { + const std::string &device_id, const std::string &adb_server_port) { Log *log = GetLog(LLDBLog::Platform); - AdbClient adb; - auto error = AdbClient::CreateByDeviceID(device_id, adb); - if (error.Fail()) - return error; - - device_id = adb.GetDeviceID(); + AdbClient adb(device_id, adb_server_port); LLDB_LOGF(log, "Connected to Android device \"%s\"", device_id.c_str()); if (remote_port != 0) { @@ -56,8 +51,9 @@ } static Status DeleteForwardPortWithAdb(uint16_t local_port, - const std::string &device_id) { - AdbClient adb(device_id); + const std::string &device_id, + const std::string &adb_server_port) { + AdbClient adb(device_id, adb_server_port); return adb.DeletePortForwarding(local_port); } @@ -74,9 +70,16 @@ return error; } +PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer( + const std::string &device_id, const std::string &adb_server_port, + const std::string &platform_local_port, const std::string &gdb_local_port) + : m_device_id(device_id), m_adb_server_port(adb_server_port), + m_platform_local_port(platform_local_port), + m_gdb_local_port(gdb_local_port) {} + PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer() { for (const auto &it : m_port_forwards) - DeleteForwardPortWithAdb(it.second, m_device_id); + DeleteForwardPortWithAdb(it.second, m_device_id, m_adb_server_port); } bool PlatformAndroidRemoteGDBServer::LaunchGDBServer(lldb::pid_t &pid, @@ -90,10 +93,7 @@ Log *log = GetLog(LLDBLog::Platform); - uint16_t local_port = 0; - const char *gdbstub_port = std::getenv("ANDROID_PLATFORM_LOCAL_GDB_PORT"); - if (gdbstub_port) - local_port = std::stoi(gdbstub_port); + uint16_t local_port = GetGDBLocalPort(); auto error = MakeConnectURL(pid, local_port, remote_port, socket_name.c_str(), connect_url); @@ -103,6 +103,17 @@ return error.Success(); } +uint16_t PlatformAndroidRemoteGDBServer::GetGDBLocalPort() { + if (!m_gdb_local_port.empty()) { + return std::stoi(m_gdb_local_port); + } else { + const char *gdbstub_port = std::getenv("ANDROID_PLATFORM_LOCAL_GDB_PORT"); + if (gdbstub_port) + return std::stoi(gdbstub_port); + } + return 0; +} + bool PlatformAndroidRemoteGDBServer::KillSpawnedProcess(lldb::pid_t pid) { assert(IsConnected()); DeleteForwardPort(pid); @@ -110,8 +121,6 @@ } Status PlatformAndroidRemoteGDBServer::ConnectRemote(Args &args) { - m_device_id.clear(); - if (args.GetArgumentCount() != 1) return Status( "\"platform connect\" takes a single argument: "); @@ -122,7 +131,7 @@ llvm::Optional parsed_url = URI::Parse(url); if (!parsed_url) return Status("Invalid URL: %s", url); - if (parsed_url->hostname != "localhost") + if (!parsed_url->hostname.empty() && parsed_url->hostname != "localhost") m_device_id = parsed_url->hostname.str(); m_socket_namespace.reset(); @@ -131,10 +140,7 @@ else if (parsed_url->scheme == "unix-abstract-connect") m_socket_namespace = AdbClient::UnixSocketNamespaceAbstract; - uint16_t local_port = 0; - const char *platform_local_port = std::getenv("ANDROID_PLATFORM_LOCAL_PORT"); - if (platform_local_port) - local_port = std::stoi(platform_local_port); + uint16_t local_port = GetPlatformLocalPort(); std::string connect_url; auto error = MakeConnectURL(g_remote_platform_pid, local_port, @@ -156,6 +162,18 @@ return error; } +uint16_t PlatformAndroidRemoteGDBServer::GetPlatformLocalPort() { + if (!m_platform_local_port.empty()) { + return std::stoi(m_platform_local_port); + } else { + const char *platform_local_port = + std::getenv("ANDROID_PLATFORM_LOCAL_PORT"); + if (platform_local_port) + return std::stoi(platform_local_port); + } + return 0; +} + Status PlatformAndroidRemoteGDBServer::DisconnectRemote() { DeleteForwardPort(g_remote_platform_pid); return PlatformRemoteGDBServer::DisconnectRemote(); @@ -169,7 +187,8 @@ return; const auto port = it->second; - const auto error = DeleteForwardPortWithAdb(port, m_device_id); + const auto error = + DeleteForwardPortWithAdb(port, m_device_id, m_adb_server_port); if (error.Fail()) { LLDB_LOGF(log, "Failed to delete port forwarding (pid=%" PRIu64 @@ -188,8 +207,9 @@ Status error; auto forward = [&](const uint16_t local, const uint16_t remote) { - error = ForwardPortWithAdb(local, remote, remote_socket_name, - m_socket_namespace, m_device_id); + error = + ForwardPortWithAdb(local, remote, remote_socket_name, + m_socket_namespace, m_device_id, m_adb_server_port); if (error.Success()) { m_port_forwards[pid] = local; std::ostringstream url_str; diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -1350,6 +1350,23 @@ "Platform-specific options required for SSH to work."}, }; +static constexpr OptionDefinition g_android_option_table[] = { + {LLDB_OPT_SET_ALL, false, "android-serial", 's', + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, + "Android device serial for ADB to use (overrides $ANDROID_SERIAL.)"}, + {LLDB_OPT_SET_ALL, false, "adb-server-port", 'p', + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, + "Local server port to connect ADB (overrides $ANDROID_ADB_SERVER_PORT.)"}, + {LLDB_OPT_SET_ALL, false, "platform-local-port", 'l', + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, + "Local TCP port for the platform port forwarding " + "(overrides $ANDROID_PLATFORM_LOCAL_PORT.)"}, + {LLDB_OPT_SET_ALL, false, "gdb-local-port", 'g', + OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommandName, + "Local TCP port for GDB port forwarding " + "(overrides $ANDROID_PLATFORM_LOCAL_GDB_PORT.)"}, +}; + static constexpr OptionDefinition g_caching_option_table[] = { {LLDB_OPT_SET_ALL, false, "local-cache-dir", 'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypePath, @@ -1437,6 +1454,49 @@ return error; } +llvm::ArrayRef OptionGroupPlatformAndroid::GetDefinitions() { + return llvm::makeArrayRef(g_android_option_table); +} + +void OptionGroupPlatformAndroid::OptionParsingStarting( + ExecutionContext *execution_context) { + m_android_serial.clear(); + m_adb_server_port.clear(); + m_gdb_local_port.clear(); + m_platform_local_port.clear(); +} + +lldb_private::Status +OptionGroupPlatformAndroid::SetOptionValue(uint32_t option_idx, + llvm::StringRef option_arg, + ExecutionContext *execution_context) { + Status error; + char short_option = (char)GetDefinitions()[option_idx].short_option; + switch (short_option) { + case 's': + m_android_serial.assign(std::string(option_arg)); + break; + + case 'p': + m_adb_server_port.assign(std::string(option_arg)); + break; + + case 'l': + m_platform_local_port.assign(std::string(option_arg)); + break; + + case 'g': + m_gdb_local_port.assign(std::string(option_arg)); + break; + + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); + break; + } + + return error; +} + llvm::ArrayRef OptionGroupPlatformCaching::GetDefinitions() { return llvm::makeArrayRef(g_caching_option_table); } diff --git a/lldb/unittests/Platform/Android/AdbClientTest.cpp b/lldb/unittests/Platform/Android/AdbClientTest.cpp --- a/lldb/unittests/Platform/Android/AdbClientTest.cpp +++ b/lldb/unittests/Platform/Android/AdbClientTest.cpp @@ -26,25 +26,51 @@ class AdbClientTest : public ::testing::Test { public: - void SetUp() override { set_env("ANDROID_SERIAL", ""); } + void SetUp() override { + set_env("ANDROID_SERIAL", ""); + set_env("ANDROID_ADB_SERVER_PORT", ""); + } - void TearDown() override { set_env("ANDROID_SERIAL", ""); } + void TearDown() override { + set_env("ANDROID_SERIAL", ""); + set_env("ANDROID_ADB_SERVER_PORT", ""); + } }; TEST(AdbClientTest, CreateByDeviceId) { AdbClient adb; - Status error = AdbClient::CreateByDeviceID("device1", adb); + Status error = AdbClient::CreateByDeviceID("device1", "", adb); EXPECT_TRUE(error.Success()); EXPECT_EQ("device1", adb.GetDeviceID()); + EXPECT_EQ("5037", adb.GetServerPort()); } TEST(AdbClientTest, CreateByDeviceId_ByEnvVar) { set_env("ANDROID_SERIAL", "device2"); AdbClient adb; - Status error = AdbClient::CreateByDeviceID("", adb); + Status error = AdbClient::CreateByDeviceID("", "", adb); EXPECT_TRUE(error.Success()); EXPECT_EQ("device2", adb.GetDeviceID()); + EXPECT_EQ("5037", adb.GetServerPort()); +} + +TEST(AdbClientTest, CreateByDeviceId_WithServerPort) { + AdbClient adb; + Status error = AdbClient::CreateByDeviceID("device1", "5038", adb); + EXPECT_TRUE(error.Success()); + EXPECT_EQ("device1", adb.GetDeviceID()); + EXPECT_EQ("5038", adb.GetServerPort()); +} + +TEST(AdbClientTest, CreateByDeviceId_WithServerPortEnvVar) { + set_env("ANDROID_ADB_SERVER_PORT", "5039"); + + AdbClient adb; + Status error = AdbClient::CreateByDeviceID("device1", "", adb); + EXPECT_TRUE(error.Success()); + EXPECT_EQ("device1", adb.GetDeviceID()); + EXPECT_EQ("5039", adb.GetServerPort()); } } // end namespace platform_android diff --git a/lldb/unittests/Platform/Android/CMakeLists.txt b/lldb/unittests/Platform/Android/CMakeLists.txt --- a/lldb/unittests/Platform/Android/CMakeLists.txt +++ b/lldb/unittests/Platform/Android/CMakeLists.txt @@ -1,7 +1,8 @@ include_directories(${LLDB_SOURCE_DIR}/source/Plugins/Platform/Android) -add_lldb_unittest(AdbClientTests +add_lldb_unittest(PlatformAndroidTests AdbClientTest.cpp + PlatformAndroidRemoteGDBServerTest.cpp LINK_LIBS lldbPluginPlatformAndroid diff --git a/lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp b/lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp new file mode 100644 --- /dev/null +++ b/lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp @@ -0,0 +1,102 @@ +//===-- PlatformAndroidRemoteGDBServerTest.cpp ----------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h" +#include "gtest/gtest.h" +#include + +static void set_env(const char *var, const char *value) { +#ifdef _WIN32 + _putenv_s(var, value); +#else + setenv(var, value, true); +#endif +} + +using namespace lldb; +using namespace lldb_private; + +namespace lldb_private { +namespace platform_android { + +class PlatformAndroidRemoteGDBServerForTest + : public PlatformAndroidRemoteGDBServer { +public: + PlatformAndroidRemoteGDBServerForTest() = delete; + explicit PlatformAndroidRemoteGDBServerForTest( + const std::string &device_id, const std::string &adb_server_port, + const std::string &platform_local_port, const std::string &gdb_local_port) + : PlatformAndroidRemoteGDBServer(device_id, adb_server_port, + platform_local_port, gdb_local_port) {} + + void CheckPorts(uint16_t platform_local_port, uint16_t gdb_local_port) { + ASSERT_EQ(platform_local_port, GetPlatformLocalPort()); + ASSERT_EQ(gdb_local_port, GetGDBLocalPort()); + } +}; + +class PlatformAndroidRemoteGDBServerTest : public ::testing::Test { +public: + void SetUp() override { + set_env("ANDROID_PLATFORM_LOCAL_PORT", ""); + set_env("ANDROID_PLATFORM_LOCAL_GDB_PORT", ""); + } + + void TearDown() override { + set_env("ANDROID_PLATFORM_LOCAL_PORT", ""); + set_env("ANDROID_PLATFORM_LOCAL_GDB_PORT", ""); + } +}; + +TEST(PlatformAndroidRemoteGDBServerTest, GetPlatformLocalPort) { + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "", ""); + p.CheckPorts(0u, 0u); +} + +TEST(PlatformAndroidRemoteGDBServerTest, GetPlatformLocalPort_WithEnv) { + set_env("ANDROID_PLATFORM_LOCAL_PORT", "12346"); + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "", ""); + p.CheckPorts(12346u, 0u); +} + +TEST(PlatformAndroidRemoteGDBServerTest, GetPlatformLocalPort_WithOption) { + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "12345", ""); + p.CheckPorts(12345u, 0u); +} + +TEST(PlatformAndroidRemoteGDBServerTest, + GetPlatformLocalPort_WithEnvAndOption) { + set_env("ANDROID_PLATFORM_LOCAL_PORT", "12346"); + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "12345", ""); + p.CheckPorts(12345u, 0u); +} + +TEST(PlatformAndroidRemoteGDBServerTest, GetGDBLocalPort) { + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "", ""); + p.CheckPorts(0u, 0u); +} + +TEST(PlatformAndroidRemoteGDBServerTest, GetGDBLocalPort_WithEnv) { + set_env("ANDROID_PLATFORM_LOCAL_GDB_PORT", "12346"); + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "", ""); + p.CheckPorts(0u, 12346u); +} + +TEST(PlatformAndroidRemoteGDBServerTest, GetGDBLocalPort_WithOption) { + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "", "12345"); + p.CheckPorts(0u, 12345u); +} + +TEST(PlatformAndroidRemoteGDBServerTest, GetGDBLocalPort_WithEnvAndOption) { + set_env("ANDROID_PLATFORM_LOCAL_GDB_PORT", "12346"); + PlatformAndroidRemoteGDBServerForTest p("device1", "5037", "", "12345"); + p.CheckPorts(0u, 12345u); +} + +} // end namespace platform_android +} // end namespace lldb_private