1 //===-- PlatformAndroidRemoteGDBServer.cpp ----------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // Other libraries and framework includes
11 #include "lldb/Core/Error.h"
12 #include "lldb/Core/Log.h"
13 
14 // Project includes
15 #include "AdbClient.h"
16 #include "PlatformAndroidRemoteGDBServer.h"
17 #include "Utility/UriParser.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 using namespace platform_android;
22 
23 static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
24 
25 static Error
26 ForwardPortWithAdb (uint16_t port, std::string& device_id)
27 {
28     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
29 
30     // Fetch the device list from ADB and if only 1 device found then use that device
31     // TODO: Handle the case when more device is available
32     AdbClient adb;
33     auto error = AdbClient::CreateByDeviceID (nullptr, adb);
34     if (error.Fail ())
35         return error;
36 
37     device_id = adb.GetDeviceID ();
38     if (log)
39         log->Printf("Connected to Android device \"%s\"", device_id.c_str ());
40 
41     return adb.SetPortForwarding (port);
42 }
43 
44 static Error
45 DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id)
46 {
47     AdbClient adb (device_id);
48     return adb.DeletePortForwarding (port);
49 }
50 
51 PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
52 {
53 }
54 
55 PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
56 {
57     for (const auto& it : m_port_forwards)
58     {
59         DeleteForwardPortWithAdb (it.second.first, it.second.second);
60     }
61 }
62 
63 uint16_t
64 PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
65 {
66     uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
67     if (port == 0)
68         return port;
69 
70     std::string device_id;
71     Error error = ForwardPortWithAdb (port, device_id);
72     if (error.Fail ())
73         return 0;
74 
75     m_port_forwards[pid] = std::make_pair (port, device_id);
76 
77     return port;
78 }
79 
80 bool
81 PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
82 {
83     DeleteForwardPort (pid);
84     return m_gdb_client.KillSpawnedProcess (pid);
85 }
86 
87 Error
88 PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
89 {
90     if (args.GetArgumentCount () != 1)
91         return Error ("\"platform connect\" takes a single argument: <connect-url>");
92 
93     int port;
94     std::string scheme, host, path;
95     const char *url = args.GetArgumentAtIndex (0);
96     if (!UriParser::Parse (url, scheme, host, port, path))
97         return Error ("invalid uri");
98 
99     std::string device_id;
100     Error error = ForwardPortWithAdb (port, device_id);
101     if (error.Fail ())
102         return error;
103 
104     m_port_forwards[g_remote_platform_pid] = std::make_pair (port, device_id);
105 
106     error = PlatformRemoteGDBServer::ConnectRemote (args);
107     if (error.Fail ())
108         DeleteForwardPort (g_remote_platform_pid);
109 
110     return error;
111 }
112 
113 Error
114 PlatformAndroidRemoteGDBServer::DisconnectRemote ()
115 {
116     DeleteForwardPort (g_remote_platform_pid);
117     return PlatformRemoteGDBServer::DisconnectRemote ();
118 }
119 
120 void
121 PlatformAndroidRemoteGDBServer::DeleteForwardPort (lldb::pid_t pid)
122 {
123     Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
124 
125     auto it = m_port_forwards.find (pid);
126     if (it == m_port_forwards.end ())
127         return;
128 
129     const auto& forward_val = it->second;
130     const auto error = DeleteForwardPortWithAdb (forward_val.first, forward_val.second);
131     if (error.Fail ()) {
132         if (log)
133             log->Printf ("Failed to delete port forwarding (pid=%" PRIu64 ", port=%d, device=%s): %s",
134                          pid, forward_val.first, forward_val.second.c_str (), error.AsCString ());
135     }
136     m_port_forwards.erase (it);
137 }
138