1 //===-- AdbClient.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/DataBuffer.h"
12 #include "lldb/Core/DataBufferHeap.h"
13 #include "lldb/Core/DataEncoder.h"
14 #include "lldb/Core/DataExtractor.h"
15 #include "lldb/Core/StreamString.h"
16 #include "lldb/Host/FileSpec.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/Support/FileUtilities.h"
21 
22 // Project includes
23 #include "AdbClient.h"
24 
25 #include <limits.h>
26 
27 #include <algorithm>
28 #include <fstream>
29 #include <sstream>
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 using namespace lldb_private::platform_android;
34 
35 namespace {
36 
37 const uint32_t kReadTimeout = 1000000; // 1 second
38 const char * kOKAY = "OKAY";
39 const char * kFAIL = "FAIL";
40 const char * kDATA = "DATA";
41 const char * kDONE = "DONE";
42 
43 const char * kSEND = "SEND";
44 const char * kRECV = "RECV";
45 const char * kSTAT = "STAT";
46 
47 const size_t kSyncPacketLen = 8;
48 // Maximum size of a filesync DATA packet.
49 const size_t kMaxPushData = 2*1024;
50 // Default mode for pushed files.
51 const uint32_t kDefaultMode = 0100770; // S_IFREG | S_IRWXU | S_IRWXG
52 
53 }  // namespace
54 
55 Error
56 AdbClient::CreateByDeviceID(const std::string &device_id, AdbClient &adb)
57 {
58     DeviceIDList connect_devices;
59     auto error = adb.GetDevices(connect_devices);
60     if (error.Fail())
61         return error;
62 
63     if (device_id.empty())
64     {
65         if (connect_devices.size() != 1)
66             return Error("Expected a single connected device, got instead %" PRIu64,
67                     static_cast<uint64_t>(connect_devices.size()));
68 
69         adb.SetDeviceID(connect_devices.front());
70     }
71     else
72     {
73         auto find_it = std::find(connect_devices.begin(), connect_devices.end(), device_id);
74         if (find_it == connect_devices.end())
75             return Error("Device \"%s\" not found", device_id.c_str());
76 
77         adb.SetDeviceID(*find_it);
78     }
79     return error;
80 }
81 
82 AdbClient::AdbClient (const std::string &device_id)
83     : m_device_id (device_id)
84 {
85 }
86 
87 void
88 AdbClient::SetDeviceID (const std::string &device_id)
89 {
90     m_device_id = device_id;
91 }
92 
93 const std::string&
94 AdbClient::GetDeviceID() const
95 {
96     return m_device_id;
97 }
98 
99 Error
100 AdbClient::Connect ()
101 {
102     Error error;
103     m_conn.Connect ("connect://localhost:5037", &error);
104 
105     return error;
106 }
107 
108 Error
109 AdbClient::GetDevices (DeviceIDList &device_list)
110 {
111     device_list.clear ();
112 
113     auto error = SendMessage ("host:devices");
114     if (error.Fail ())
115         return error;
116 
117     error = ReadResponseStatus ();
118     if (error.Fail ())
119         return error;
120 
121     std::vector<char> in_buffer;
122     error = ReadMessage (in_buffer);
123 
124     llvm::StringRef response (&in_buffer[0], in_buffer.size ());
125     llvm::SmallVector<llvm::StringRef, 4> devices;
126     response.split (devices, "\n", -1, false);
127 
128     for (const auto device: devices)
129         device_list.push_back (device.split ('\t').first);
130 
131     return error;
132 }
133 
134 Error
135 AdbClient::SetPortForwarding (const uint16_t local_port, const uint16_t remote_port)
136 {
137     char message[48];
138     snprintf (message, sizeof (message), "forward:tcp:%d;tcp:%d", local_port, remote_port);
139 
140     const auto error = SendDeviceMessage (message);
141     if (error.Fail ())
142         return error;
143 
144     return ReadResponseStatus ();
145 }
146 
147 Error
148 AdbClient::DeletePortForwarding (const uint16_t local_port)
149 {
150     char message[32];
151     snprintf (message, sizeof (message), "killforward:tcp:%d", local_port);
152 
153     const auto error = SendDeviceMessage (message);
154     if (error.Fail ())
155         return error;
156 
157     return ReadResponseStatus ();
158 }
159 
160 Error
161 AdbClient::SendMessage (const std::string &packet, const bool reconnect)
162 {
163     Error error;
164     if (reconnect)
165     {
166         error = Connect ();
167         if (error.Fail ())
168             return error;
169     }
170 
171     char length_buffer[5];
172     snprintf (length_buffer, sizeof (length_buffer), "%04x", static_cast<int>(packet.size ()));
173 
174     ConnectionStatus status;
175 
176     m_conn.Write (length_buffer, 4, status, &error);
177     if (error.Fail ())
178         return error;
179 
180     m_conn.Write (packet.c_str (), packet.size (), status, &error);
181     return error;
182 }
183 
184 Error
185 AdbClient::SendDeviceMessage (const std::string &packet)
186 {
187     std::ostringstream msg;
188     msg << "host-serial:" << m_device_id << ":" << packet;
189     return SendMessage (msg.str ());
190 }
191 
192 Error
193 AdbClient::ReadMessage (std::vector<char> &message)
194 {
195     message.clear ();
196 
197     char buffer[5];
198     buffer[4] = 0;
199 
200     auto error = ReadAllBytes (buffer, 4);
201     if (error.Fail ())
202         return error;
203 
204     unsigned int packet_len = 0;
205     sscanf (buffer, "%x", &packet_len);
206 
207     message.resize (packet_len, 0);
208     error = ReadAllBytes (&message[0], packet_len);
209     if (error.Fail ())
210         message.clear ();
211 
212     return error;
213 }
214 
215 Error
216 AdbClient::ReadMessageStream (std::vector<char>& message, uint32_t timeout_ms)
217 {
218     auto start = std::chrono::steady_clock::now();
219     message.clear();
220 
221     Error error;
222     lldb::ConnectionStatus status = lldb::eConnectionStatusSuccess;
223     char buffer[1024];
224     while (error.Success() && status == lldb::eConnectionStatusSuccess)
225     {
226         auto end = std::chrono::steady_clock::now();
227         uint32_t elapsed_time = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
228         if (elapsed_time >= timeout_ms)
229             return Error("Timed out");
230 
231         size_t n = m_conn.Read(buffer, sizeof(buffer), 1000 * (timeout_ms - elapsed_time), status, &error);
232         if (n > 0)
233             message.insert(message.end(), &buffer[0], &buffer[n]);
234     }
235     return error;
236 }
237 
238 Error
239 AdbClient::ReadResponseStatus()
240 {
241     char response_id[5];
242 
243     static const size_t packet_len = 4;
244     response_id[packet_len] = 0;
245 
246     auto error = ReadAllBytes (response_id, packet_len);
247     if (error.Fail ())
248         return error;
249 
250     if (strncmp (response_id, kOKAY, packet_len) != 0)
251         return GetResponseError (response_id);
252 
253     return error;
254 }
255 
256 Error
257 AdbClient::GetResponseError (const char *response_id)
258 {
259     if (strcmp (response_id, kFAIL) != 0)
260         return Error ("Got unexpected response id from adb: \"%s\"", response_id);
261 
262     std::vector<char> error_message;
263     auto error = ReadMessage (error_message);
264     if (error.Success ())
265         error.SetErrorString (std::string (&error_message[0], error_message.size ()).c_str ());
266 
267     return error;
268 }
269 
270 Error
271 AdbClient::SwitchDeviceTransport ()
272 {
273     std::ostringstream msg;
274     msg << "host:transport:" << m_device_id;
275 
276     auto error = SendMessage (msg.str ());
277     if (error.Fail ())
278         return error;
279 
280     return ReadResponseStatus ();
281 }
282 
283 Error
284 AdbClient::PullFile (const FileSpec &remote_file, const FileSpec &local_file)
285 {
286     auto error = StartSync ();
287     if (error.Fail ())
288         return error;
289 
290     const auto local_file_path = local_file.GetPath ();
291     llvm::FileRemover local_file_remover (local_file_path.c_str ());
292 
293     std::ofstream dst (local_file_path, std::ios::out | std::ios::binary);
294     if (!dst.is_open ())
295         return Error ("Unable to open local file %s", local_file_path.c_str());
296 
297     const auto remote_file_path = remote_file.GetPath (false);
298     error = SendSyncRequest (kRECV, remote_file_path.length (), remote_file_path.c_str ());
299     if (error.Fail ())
300         return error;
301 
302     std::vector<char> chunk;
303     bool eof = false;
304     while (!eof)
305     {
306         error = PullFileChunk (chunk, eof);
307         if (error.Fail ())
308             return error;
309         if (!eof)
310             dst.write (&chunk[0], chunk.size ());
311     }
312 
313     local_file_remover.releaseFile ();
314     return error;
315 }
316 
317 Error
318 AdbClient::PushFile (const FileSpec &local_file, const FileSpec &remote_file)
319 {
320     auto error = StartSync ();
321     if (error.Fail ())
322         return error;
323 
324     const auto local_file_path (local_file.GetPath ());
325     std::ifstream src (local_file_path.c_str(), std::ios::in | std::ios::binary);
326     if (!src.is_open ())
327         return Error ("Unable to open local file %s", local_file_path.c_str());
328 
329     std::stringstream file_description;
330     file_description << remote_file.GetPath(false).c_str() << "," << kDefaultMode;
331     std::string file_description_str = file_description.str();
332     error = SendSyncRequest (kSEND, file_description_str.length(), file_description_str.c_str());
333     if (error.Fail ())
334         return error;
335 
336     char chunk[kMaxPushData];
337     while (!src.eof() && !src.read(chunk, kMaxPushData).bad())
338     {
339         size_t chunk_size = src.gcount();
340         error = SendSyncRequest(kDATA, chunk_size, chunk);
341         if (error.Fail ())
342             return Error ("Failed to send file chunk: %s", error.AsCString ());
343     }
344     error = SendSyncRequest(kDONE, local_file.GetModificationTime().seconds(), nullptr);
345     if (error.Fail ())
346         return error;
347 
348     std::string response_id;
349     uint32_t data_len;
350     error = ReadSyncHeader (response_id, data_len);
351     if (error.Fail ())
352         return Error ("Failed to read DONE response: %s", error.AsCString ());
353     if (response_id == kFAIL)
354     {
355         std::string error_message (data_len, 0);
356         error = ReadAllBytes (&error_message[0], data_len);
357         if (error.Fail ())
358             return Error ("Failed to read DONE error message: %s", error.AsCString ());
359         return Error ("Failed to push file: %s", error_message.c_str ());
360     }
361     else if (response_id != kOKAY)
362         return Error ("Got unexpected DONE response: %s", response_id.c_str ());
363 
364     // If there was an error reading the source file, finish the adb file
365     // transfer first so that adb isn't expecting any more data.
366     if (src.bad())
367         return Error ("Failed read on %s", local_file_path.c_str());
368     return error;
369 }
370 
371 Error
372 AdbClient::StartSync ()
373 {
374     auto error = SwitchDeviceTransport ();
375     if (error.Fail ())
376         return Error ("Failed to switch to device transport: %s", error.AsCString ());
377 
378     error = Sync ();
379     if (error.Fail ())
380         return Error ("Sync failed: %s", error.AsCString ());
381 
382     return error;
383 }
384 
385 Error
386 AdbClient::Sync ()
387 {
388     auto error = SendMessage ("sync:", false);
389     if (error.Fail ())
390         return error;
391 
392     return ReadResponseStatus ();
393 }
394 
395 Error
396 AdbClient::PullFileChunk (std::vector<char> &buffer, bool &eof)
397 {
398     buffer.clear ();
399 
400     std::string response_id;
401     uint32_t data_len;
402     auto error = ReadSyncHeader (response_id, data_len);
403     if (error.Fail ())
404         return error;
405 
406     if (response_id == kDATA)
407     {
408         buffer.resize (data_len, 0);
409         error = ReadAllBytes (&buffer[0], data_len);
410         if (error.Fail ())
411             buffer.clear ();
412     }
413     else if (response_id == kDONE)
414     {
415         eof = true;
416     }
417     else if (response_id == kFAIL)
418     {
419         std::string error_message (data_len, 0);
420         error = ReadAllBytes (&error_message[0], data_len);
421         if (error.Fail ())
422             return Error ("Failed to read pull error message: %s", error.AsCString ());
423         return Error ("Failed to pull file: %s", error_message.c_str ());
424     }
425     else
426         return Error ("Pull failed with unknown response: %s", response_id.c_str ());
427 
428     return Error ();
429 }
430 
431 Error
432 AdbClient::SendSyncRequest (const char *request_id, const uint32_t data_len, const void *data)
433 {
434     const DataBufferSP data_sp (new DataBufferHeap (kSyncPacketLen, 0));
435     DataEncoder encoder (data_sp, eByteOrderLittle, sizeof (void*));
436     auto offset = encoder.PutData (0, request_id, strlen(request_id));
437     encoder.PutU32 (offset, data_len);
438 
439     Error error;
440     ConnectionStatus status;
441     m_conn.Write (data_sp->GetBytes (), kSyncPacketLen, status, &error);
442     if (error.Fail ())
443         return error;
444 
445     if (data)
446         m_conn.Write (data, data_len, status, &error);
447     return error;
448 }
449 
450 Error
451 AdbClient::ReadSyncHeader (std::string &response_id, uint32_t &data_len)
452 {
453     char buffer[kSyncPacketLen];
454 
455     auto error = ReadAllBytes (buffer, kSyncPacketLen);
456     if (error.Success ())
457     {
458         response_id.assign (&buffer[0], 4);
459         DataExtractor extractor (&buffer[4], 4, eByteOrderLittle, sizeof (void*));
460         offset_t offset = 0;
461         data_len = extractor.GetU32 (&offset);
462     }
463 
464     return error;
465 }
466 
467 Error
468 AdbClient::ReadAllBytes (void *buffer, size_t size)
469 {
470     Error error;
471     ConnectionStatus status;
472     char *read_buffer = static_cast<char*>(buffer);
473 
474     size_t tota_read_bytes = 0;
475     while (tota_read_bytes < size)
476     {
477         auto read_bytes = m_conn.Read (read_buffer + tota_read_bytes, size - tota_read_bytes, kReadTimeout, status, &error);
478         if (error.Fail ())
479             return error;
480         tota_read_bytes += read_bytes;
481     }
482     return error;
483 }
484 
485 Error
486 AdbClient::Stat (const FileSpec &remote_file, uint32_t &mode, uint32_t &size, uint32_t &mtime)
487 {
488     auto error = StartSync ();
489     if (error.Fail ())
490         return error;
491 
492     const std::string remote_file_path (remote_file.GetPath (false));
493     error = SendSyncRequest (kSTAT, remote_file_path.length (), remote_file_path.c_str ());
494     if (error.Fail ())
495         return Error ("Failed to send request: %s", error.AsCString ());
496 
497     static const size_t stat_len = strlen (kSTAT);
498     static const size_t response_len = stat_len + (sizeof (uint32_t) * 3);
499 
500     std::vector<char> buffer (response_len);
501     error = ReadAllBytes (&buffer[0], buffer.size ());
502     if (error.Fail ())
503         return Error ("Failed to read response: %s", error.AsCString ());
504 
505     DataExtractor extractor (&buffer[0], buffer.size (), eByteOrderLittle, sizeof (void*));
506     offset_t offset = 0;
507 
508     const void* command = extractor.GetData (&offset, stat_len);
509     if (!command)
510         return Error ("Failed to get response command");
511     const char* command_str = static_cast<const char*> (command);
512     if (strncmp (command_str, kSTAT, stat_len))
513         return Error ("Got invalid stat command: %s", command_str);
514 
515     mode = extractor.GetU32 (&offset);
516     size = extractor.GetU32 (&offset);
517     mtime = extractor.GetU32 (&offset);
518     return Error ();
519 }
520 
521 Error
522 AdbClient::Shell (const char* command, uint32_t timeout_ms, std::string* output)
523 {
524     auto error = SwitchDeviceTransport ();
525     if (error.Fail ())
526         return Error ("Failed to switch to device transport: %s", error.AsCString ());
527 
528     StreamString adb_command;
529     adb_command.Printf("shell:%s", command);
530     error = SendMessage (adb_command.GetData(), false);
531     if (error.Fail ())
532         return error;
533 
534     error = ReadResponseStatus ();
535     if (error.Fail ())
536         return error;
537 
538     std::vector<char> in_buffer;
539     error = ReadMessageStream (in_buffer, timeout_ms);
540     if (error.Fail())
541         return error;
542 
543     if (output)
544         output->assign(in_buffer.begin(), in_buffer.end());
545     return error;
546 }
547