• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "transport_sniffer.h"
2 #include <android-base/stringprintf.h>
3 #include <sys/select.h>
4 #include <sys/time.h>
5 #include <sys/types.h>
6 #include <algorithm>
7 #include <iomanip>
8 #include <sstream>
9 
10 namespace fastboot {
11 
TransportSniffer(std::unique_ptr<Transport> transport,const int serial_fd)12 TransportSniffer::TransportSniffer(std::unique_ptr<Transport> transport,
13                                          const int serial_fd)
14     : transport_(std::move(transport)), serial_fd_(serial_fd) {}
15 
~TransportSniffer()16 TransportSniffer::~TransportSniffer() {
17     Close();
18 }
19 
Read(void * data,size_t len)20 ssize_t TransportSniffer::Read(void* data, size_t len) {
21     ProcessSerial();
22 
23     ssize_t ret = transport_->Read(data, len);
24     if (ret < 0) {
25         const char* err = strerror(errno);
26         std::vector<char> buf(err, err + strlen(err));
27         Event e(READ_ERROR, std::move(buf));
28         transfers_.push_back(e);
29         return ret;
30     }
31 
32     char* cdata = static_cast<char*>(data);
33     std::vector<char> buf(cdata, cdata + ret);
34     Event e(READ, std::move(buf));
35     transfers_.push_back(e);
36 
37     ProcessSerial();
38     return ret;
39 }
40 
Write(const void * data,size_t len)41 ssize_t TransportSniffer::Write(const void* data, size_t len) {
42     ProcessSerial();
43 
44     size_t ret = transport_->Write(data, len);
45     if (ret != len) {
46         const char* err = strerror(errno);
47         std::vector<char> buf(err, err + strlen(err));
48         Event e(WRITE_ERROR, std::move(buf));
49         transfers_.push_back(e);
50         return ret;
51     }
52 
53     const char* cdata = static_cast<const char*>(data);
54     std::vector<char> buf(cdata, cdata + len);
55     Event e(WRITE, std::move(buf));
56     transfers_.push_back(e);
57 
58     ProcessSerial();
59     return ret;
60 }
61 
Close()62 int TransportSniffer::Close() {
63     return transport_->Close();
64 }
65 
Reset()66 int TransportSniffer::Reset() {
67     ProcessSerial();
68     int ret = transport_->Reset();
69     std::vector<char> buf;
70     Event e(RESET, std::move(buf));
71     transfers_.push_back(e);
72     ProcessSerial();
73     return ret;
74 }
75 
Transfers()76 const std::vector<TransportSniffer::Event> TransportSniffer::Transfers() {
77     return transfers_;
78 }
79 
80 /*
81  * When a test fails, we want a human readable log of everything going on up until
82  * the failure. This method will look through its log of captured events, and
83  * create a clean printable string of everything that happened.
84  */
CreateTrace()85 std::string TransportSniffer::CreateTrace() {
86     std::string ret;
87 
88     const auto no_print = [](char c) -> bool { return !isprint(c); };
89     // This lambda creates a humand readable representation of a byte buffer
90     // It first attempts to figure out whether it should be interpreted as an ASCII buffer,
91     // and be printed as a string, or just a raw byte-buffer
92     const auto msg = [&ret, no_print](const std::vector<char>& buf) {
93         ret += android::base::StringPrintf("(%lu bytes): ", buf.size());
94         std::vector<char>::const_iterator iter = buf.end();
95         const unsigned max_chars = 50;
96         if (buf.size() > max_chars) {
97             iter = buf.begin() + max_chars;
98         }
99         ret += '"';
100         if (std::count_if(buf.begin(), iter, no_print) == 0) {  // print as ascii
101             ret.insert(ret.end(), buf.begin(), iter);
102         } else {  // print as hex
103             std::stringstream ss;
104             for (auto c = buf.begin(); c < iter; c++) {
105                 ss << std::hex << std::setw(2) << std::setfill('0')
106                    << static_cast<uint16_t>(static_cast<uint8_t>(*c));
107                 ss << ',';
108             }
109             ret += ss.str();
110         }
111         if (buf.size() > max_chars) {
112             ret += android::base::StringPrintf("...\"(+%lu bytes)\n", buf.size() - max_chars);
113         } else {
114             ret += "\"\n";
115         }
116     };
117 
118     // Now we just scan through the log of everything that happened and create a
119     // printable string for each one
120     for (const auto& event : transfers_) {
121         const std::vector<char>& cbuf = event.buf;
122         const std::string tmp(cbuf.begin(), cbuf.end());
123         auto start = transfers_.front().start;
124         auto durr = event.start - start;
125         auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(durr).count();
126 
127         switch (event.type) {
128             case READ:
129                 ret += android::base::StringPrintf("[READ %lldms]", millis);
130                 msg(cbuf);
131                 break;
132 
133             case WRITE:
134                 ret += android::base::StringPrintf("[WRITE %lldms]", millis);
135                 msg(cbuf);
136                 break;
137 
138             case RESET:
139                 ret += android::base::StringPrintf("[RESET %lldms]\n", millis);
140                 break;
141 
142             case READ_ERROR:
143                 ret += android::base::StringPrintf("[READ_ERROR %lldms] %s\n", millis, tmp.c_str());
144                 break;
145 
146             case WRITE_ERROR:
147                 ret += android::base::StringPrintf("[WRITE_ERROR %lldms] %s\n", millis,
148                                                    tmp.c_str());
149                 break;
150 
151             case SERIAL:
152                 ret += android::base::StringPrintf("[SERIAL %lldms] %s", millis, tmp.c_str());
153                 if (ret.back() != '\n') ret += '\n';
154                 break;
155         }
156     }
157     return ret;
158 }
159 
160 // This is a quick call to flush any UART logs the device might have sent
161 // to our internal event log. It will wait up to 10ms for data to appear
ProcessSerial()162 void TransportSniffer::ProcessSerial() {
163     if (serial_fd_ <= 0) return;
164 
165     fd_set set;
166     struct timeval timeout;
167 
168     FD_ZERO(&set);
169     FD_SET(serial_fd_, &set);
170     timeout.tv_sec = 0;
171     timeout.tv_usec = 10000;  // 10ms
172 
173     int count = 0;
174     int n = 0;
175     std::vector<char> buf;
176     buf.resize(1000);
177     while (select(serial_fd_ + 1, &set, NULL, NULL, &timeout) > 0) {
178         n = read(serial_fd_, buf.data() + count, buf.size() - count);
179         if (n > 0) {
180             count += n;
181         } else {
182             break;
183         }
184     }
185 
186     buf.resize(count);
187 
188     if (count > 0) {
189         Event e(SERIAL, std::move(buf));
190         transfers_.push_back(e);
191     }
192 }
193 
194 }  // namespace fastboot
195