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