splhack created this revision.
Herald added a subscriber: danielkiss.
Herald added a project: All.
splhack added a reviewer: clayborg.
splhack updated this revision to Diff 480112.
splhack added a comment.
splhack published this revision for review.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

.


This is an alternative approach to 'Fix Android serial number handling' 
https://reviews.llvm.org/D138164 .

As I pointed out in https://reviews.llvm.org/D138164, the platform connect URL 
does not work to specify TCP/IP-connected Android device.

This diff allows users to use `platform connect` options in order to specify 
Android device serial, ADB server port, platform local TCP port, and/or GDB 
local TCP port.

This is the example to use a TCP/IP-connected Android device with serial 
`[::1]:5556`.

  (lldb) platform select remote-android
  (lldb) platform connect --android-serial [::1]:5556 
unix-abstract-connect:///data/local/tmp/debug.sock

help

  (lldb) platform select remote-android
    Platform: remote-android
   Connected: no
  (lldb) help platform connect
  Select the current platform by providing a connection URL.
  
  Syntax: platform connect <connect-url>
  
  Command Options Usage:
    platform connect [-s <cmd-name>] [-p <cmd-name>] [-l <cmd-name>] [-g 
<cmd-name>] <process-connect-url>
  
         -g <cmd-name> ( --gdb-local-port <cmd-name> )
              Local TCP port for GDB port forwarding (overrides 
$ANDROID_PLATFORM_LOCAL_GDB_PORT.)
  
         -l <cmd-name> ( --platform-local-port <cmd-name> )
              Local TCP port for the platform port forwarding (overrides
              $ANDROID_PLATFORM_LOCAL_PORT.)
  
         -p <cmd-name> ( --adb-server-port <cmd-name> )
              Local server port to connect ADB (overrides 
$ANDROID_ADB_SERVER_PORT.)
  
         -s <cmd-name> ( --android-serial <cmd-name> )
              Android device serial for ADB to use (overrides $ANDROID_SERIAL.)
  
       This command takes options and free-form arguments.  If your arguments 
resemble option
       specifiers (i.e., they start with a - or --), you must use ' -- ' 
between the end of the
       command options and the beginning of the arguments.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D139332

Files:
  lldb/include/lldb/Target/Platform.h
  lldb/source/Plugins/Platform/Android/AdbClient.cpp
  lldb/source/Plugins/Platform/Android/AdbClient.h
  lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
  lldb/source/Plugins/Platform/Android/PlatformAndroid.h
  lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
  lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
  lldb/source/Target/Platform.cpp
  lldb/unittests/Platform/Android/AdbClientTest.cpp
  lldb/unittests/Platform/Android/CMakeLists.txt
  lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp

Index: lldb/unittests/Platform/Android/PlatformAndroidRemoteGDBServerTest.cpp
===================================================================
--- /dev/null
+++ 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 <cstdlib>
+
+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
Index: lldb/unittests/Platform/Android/CMakeLists.txt
===================================================================
--- lldb/unittests/Platform/Android/CMakeLists.txt
+++ 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
Index: lldb/unittests/Platform/Android/AdbClientTest.cpp
===================================================================
--- lldb/unittests/Platform/Android/AdbClientTest.cpp
+++ 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
Index: lldb/source/Target/Platform.cpp
===================================================================
--- lldb/source/Target/Platform.cpp
+++ 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<OptionDefinition> 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<OptionDefinition> OptionGroupPlatformCaching::GetDefinitions() {
   return llvm::makeArrayRef(g_caching_option_table);
 }
Index: lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
===================================================================
--- lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.h
+++ 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<lldb::pid_t, uint16_t> m_port_forwards;
   llvm::Optional<AdbClient::UnixSocketNamespace> 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);
Index: lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
===================================================================
--- lldb/source/Plugins/Platform/Android/PlatformAndroidRemoteGDBServer.cpp
+++ 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<AdbClient::UnixSocketNamespace> &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: <connect-url>");
@@ -122,7 +131,7 @@
   llvm::Optional<URI> 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;
Index: lldb/source/Plugins/Platform/Android/PlatformAndroid.h
===================================================================
--- lldb/source/Plugins/Platform/Android/PlatformAndroid.h
+++ lldb/source/Plugins/Platform/Android/PlatformAndroid.h
@@ -13,6 +13,7 @@
 #include <string>
 
 #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<lldb_private::OptionGroupPlatformAndroid>
+      m_option_group_platform_android;
+
   AdbClient::SyncService *GetSyncService(Status &error);
 
   std::unique_ptr<AdbClient::SyncService> 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
Index: lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
===================================================================
--- lldb/source/Plugins/Platform/Android/PlatformAndroid.cpp
+++ 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<lldb_private::OptionGroupOptions> 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;
 }
Index: lldb/source/Plugins/Platform/Android/AdbClient.h
===================================================================
--- lldb/source/Plugins/Platform/Android/AdbClient.h
+++ lldb/source/Plugins/Platform/Android/AdbClient.h
@@ -73,17 +73,24 @@
     std::unique_ptr<Connection> 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<Connection> m_conn;
 };
 
Index: lldb/source/Plugins/Platform/Android/AdbClient.cpp
===================================================================
--- lldb/source/Plugins/Platform/Android/AdbClient.cpp
+++ 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<ConnectionFileDescriptor>();
-  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<char> 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];
Index: lldb/include/lldb/Target/Platform.h
===================================================================
--- lldb/include/lldb/Target/Platform.h
+++ 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<OptionDefinition> 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;
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to