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