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/Host/ConnectionFileDescriptor.h"
13 #include "llvm/ADT/StringRef.h"
14 
15 // Project includes
16 #include "PlatformAndroidRemoteGDBServer.h"
17 #include "Utility/UriParser.h"
18 
19 using namespace lldb;
20 using namespace lldb_private;
21 
22 static const lldb::pid_t g_remote_platform_pid = 0; // Alias for the process id of lldb-platform
23 static const uint32_t g_adb_timeout = 10000; // 10 ms
24 
25 static void
26 SendMessageToAdb (Connection& conn, const std::string& packet, Error& error)
27 {
28     ConnectionStatus status;
29 
30     char length_buffer[5];
31     snprintf (length_buffer, sizeof (length_buffer), "%04zx", packet.size());
32 
33     conn.Write (length_buffer, 4, status, &error);
34     if (error.Fail ())
35         return;
36 
37     conn.Write (packet.c_str(), packet.size(), status, &error);
38 }
39 
40 static std::string
41 ReadMessageFromAdb (Connection& conn, bool has_okay, Error& error)
42 {
43     ConnectionStatus status;
44 
45     char buffer[5];
46     buffer[4] = 0;
47 
48     if (has_okay)
49     {
50         conn.Read (buffer, 4, g_adb_timeout, status, &error);
51         if (error.Fail ())
52             return "";
53 
54         if (strncmp (buffer, "OKAY", 4) != 0)
55         {
56             error.SetErrorStringWithFormat ("\"OKAY\" expected from adb, received: \"%s\"", buffer);
57             return "";
58         }
59     }
60 
61     conn.Read (buffer, 4, g_adb_timeout, status, &error);
62     if (error.Fail())
63         return "";
64 
65     size_t packet_len = 0;
66     sscanf(buffer, "%zx", &packet_len);
67     std::string result(packet_len, 0);
68     conn.Read (&result[0], packet_len, g_adb_timeout, status, &error);
69     if (error.Fail ())
70         return "";
71 
72     return result;
73 }
74 
75 static Error
76 ForwardPortWithAdb (uint16_t port, std::string& device_id)
77 {
78     Error error;
79 
80     {
81         // Fetch the device list from ADB and if only 1 device found then use that device
82         // TODO: Handle the case when more device is available
83         std::unique_ptr<ConnectionFileDescriptor> conn (new ConnectionFileDescriptor ());
84         if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess)
85             return error;
86 
87         SendMessageToAdb (*conn, "host:devices", error);
88         if (error.Fail ())
89             return error;
90         std::string in_buffer = ReadMessageFromAdb (*conn, true, error);
91 
92         llvm::StringRef deviceList(in_buffer);
93         std::pair<llvm::StringRef, llvm::StringRef> devices = deviceList.split ('\n');
94         if (devices.first.size () == 0 || devices.second.size () > 0)
95         {
96             error.SetErrorString ("Wrong number of devices returned from ADB");
97             return error;
98         }
99 
100         device_id = devices.first.split ('\t').first;
101     }
102 
103     {
104         // Forward the port to the (only) connected device
105         std::unique_ptr<ConnectionFileDescriptor> conn (new ConnectionFileDescriptor ());
106         if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess)
107             return error;
108 
109         char port_buffer[32];
110         snprintf (port_buffer, sizeof (port_buffer), "tcp:%d;tcp:%d", port, port);
111 
112         std::string out_buffer = "host-serial:" + device_id + ":forward:" + port_buffer;
113         SendMessageToAdb (*conn, out_buffer, error);
114         if (error.Fail ())
115             return error;
116 
117         std::string in_buffer = ReadMessageFromAdb (*conn, false, error);
118         if (in_buffer != "OKAY")
119             error.SetErrorString (in_buffer.c_str ());
120     }
121 
122     return error;
123 }
124 
125 static Error
126 DeleteForwardPortWithAdb (uint16_t port, const std::string& device_id)
127 {
128     Error error;
129 
130     std::unique_ptr<ConnectionFileDescriptor> conn (new ConnectionFileDescriptor ());
131     if (conn->Connect ("connect://localhost:5037", &error) != eConnectionStatusSuccess)
132         return error;
133 
134     char port_buffer[16];
135     snprintf (port_buffer, sizeof (port_buffer), "tcp:%d", port);
136 
137     std::string out_buffer = "host-serial:" + device_id + ":killforward:" + port_buffer;
138     SendMessageToAdb (*conn, out_buffer, error);
139     if (error.Fail ())
140         return error;
141 
142     std::string in_buffer = ReadMessageFromAdb (*conn, true, error);
143     if (in_buffer != "OKAY")
144         error.SetErrorString (in_buffer.c_str ());
145 
146     return error;
147 }
148 
149 PlatformAndroidRemoteGDBServer::PlatformAndroidRemoteGDBServer ()
150 {
151 }
152 
153 PlatformAndroidRemoteGDBServer::~PlatformAndroidRemoteGDBServer ()
154 {
155     for (const auto& it : m_port_forwards)
156     {
157         DeleteForwardPortWithAdb (it.second.first, it.second.second);
158     }
159 }
160 
161 uint16_t
162 PlatformAndroidRemoteGDBServer::LaunchGDBserverAndGetPort (lldb::pid_t &pid)
163 {
164     uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort (pid, "127.0.0.1");
165     if (port == 0)
166         return port;
167 
168     std::string device_id;
169     Error error = ForwardPortWithAdb (port, device_id);
170     if (error.Fail ())
171         return 0;
172 
173     m_port_forwards[pid] = std::make_pair (port, device_id);
174 
175     return port;
176 }
177 
178 bool
179 PlatformAndroidRemoteGDBServer::KillSpawnedProcess (lldb::pid_t pid)
180 {
181     auto it = m_port_forwards.find (pid);
182     if (it != m_port_forwards.end ())
183     {
184         DeleteForwardPortWithAdb (it->second.first, it->second.second);
185         m_port_forwards.erase (it);
186     }
187 
188     return m_gdb_client.KillSpawnedProcess (pid);
189 }
190 
191 Error
192 PlatformAndroidRemoteGDBServer::ConnectRemote (Args& args)
193 {
194     if (args.GetArgumentCount () != 1)
195         return Error ("\"platform connect\" takes a single argument: <connect-url>");
196 
197     int port;
198     std::string scheme, host, path;
199     const char *url = args.GetArgumentAtIndex (0);
200     if (!UriParser::Parse (url, scheme, host, port, path))
201         return Error ("invalid uri");
202 
203     std::string device_id;
204     Error error = ForwardPortWithAdb (port, device_id);
205     if (error.Fail ())
206         return error;
207 
208     m_port_forwards[g_remote_platform_pid] = std::make_pair (port, device_id);
209 
210     return PlatformRemoteGDBServer::ConnectRemote (args);
211 }
212 
213 Error
214 PlatformAndroidRemoteGDBServer::DisconnectRemote ()
215 {
216     auto it = m_port_forwards.find (g_remote_platform_pid);
217     if (it != m_port_forwards.end ())
218     {
219         DeleteForwardPortWithAdb (it->second.first, it->second.second);
220         m_port_forwards.erase (it);
221     }
222 
223     return PlatformRemoteGDBServer::DisconnectRemote ();
224 }
225