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