system/corennnnn
Révision | aed7048ce0c8ff20a2ed7ce46a848d8af1d3142d (tree) |
---|---|
l'heure | 2016-08-04 23:44:35 |
Auteur | TreeHugger Robot <treehugger-gerrit@goog...> |
Commiter | Android (Google) Code Review |
Merge changes from topic 'bug_30451114' into nyc-mr1-dev
* changes:
@@ -14,28 +14,38 @@ | ||
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 | |
17 | +#include "bugreport.h" | |
18 | + | |
17 | 19 | #include <string> |
20 | +#include <vector> | |
18 | 21 | |
19 | 22 | #include <android-base/strings.h> |
20 | 23 | |
21 | -#include "bugreport.h" | |
24 | +#include "sysdeps.h" | |
25 | +#include "adb_utils.h" | |
22 | 26 | #include "file_sync_service.h" |
23 | 27 | |
24 | -static constexpr char BUGZ_OK_PREFIX[] = "OK:"; | |
25 | -static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:"; | |
28 | +static constexpr char BUGZ_BEGIN_PREFIX[] = "BEGIN:"; | |
26 | 29 | static constexpr char BUGZ_PROGRESS_PREFIX[] = "PROGRESS:"; |
27 | 30 | static constexpr char BUGZ_PROGRESS_SEPARATOR[] = "/"; |
31 | +static constexpr char BUGZ_OK_PREFIX[] = "OK:"; | |
32 | +static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:"; | |
28 | 33 | |
29 | 34 | // Custom callback used to handle the output of zipped bugreports. |
30 | 35 | class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface { |
31 | 36 | public: |
32 | - BugreportStandardStreamsCallback(const std::string& dest_file, bool show_progress, Bugreport* br) | |
37 | + BugreportStandardStreamsCallback(const std::string& dest_dir, const std::string& dest_file, | |
38 | + bool show_progress, Bugreport* br) | |
33 | 39 | : br_(br), |
40 | + src_file_(), | |
41 | + dest_dir_(dest_dir), | |
34 | 42 | dest_file_(dest_file), |
35 | - line_message_(android::base::StringPrintf("generating %s", dest_file_.c_str())), | |
43 | + line_message_(), | |
44 | + invalid_lines_(), | |
36 | 45 | show_progress_(show_progress), |
37 | - status_(-1), | |
46 | + status_(0), | |
38 | 47 | line_() { |
48 | + SetLineMessage(); | |
39 | 49 | } |
40 | 50 | |
41 | 51 | void OnStdout(const char* buffer, int length) { |
@@ -54,28 +64,72 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface | ||
54 | 64 | OnStream(nullptr, stderr, buffer, length); |
55 | 65 | } |
56 | 66 | int Done(int unused_) { |
57 | - // Process remaining line, if any... | |
67 | + // Process remaining line, if any. | |
58 | 68 | ProcessLine(line_); |
59 | - // ..then return. | |
69 | + | |
70 | + // Warn about invalid lines, if any. | |
71 | + if (!invalid_lines_.empty()) { | |
72 | + fprintf(stderr, | |
73 | + "WARNING: bugreportz generated %zu line(s) with unknown commands, " | |
74 | + "device might not support zipped bugreports:\n", | |
75 | + invalid_lines_.size()); | |
76 | + for (const auto& line : invalid_lines_) { | |
77 | + fprintf(stderr, "\t%s\n", line.c_str()); | |
78 | + } | |
79 | + fprintf(stderr, | |
80 | + "If the zipped bugreport was not generated, try 'adb bugreport' instead.\n"); | |
81 | + } | |
82 | + | |
83 | + // Pull the generated bug report. | |
84 | + if (status_ == 0) { | |
85 | + if (src_file_.empty()) { | |
86 | + fprintf(stderr, "bugreportz did not return a '%s' or '%s' line\n", BUGZ_OK_PREFIX, | |
87 | + BUGZ_FAIL_PREFIX); | |
88 | + return -1; | |
89 | + } | |
90 | + std::string destination; | |
91 | + if (dest_dir_.empty()) { | |
92 | + destination = dest_file_; | |
93 | + } else { | |
94 | + destination = android::base::StringPrintf("%s%c%s", dest_dir_.c_str(), | |
95 | + OS_PATH_SEPARATOR, dest_file_.c_str()); | |
96 | + } | |
97 | + std::vector<const char*> srcs{src_file_.c_str()}; | |
98 | + status_ = | |
99 | + br_->DoSyncPull(srcs, destination.c_str(), true, line_message_.c_str()) ? 0 : 1; | |
100 | + if (status_ != 0) { | |
101 | + fprintf(stderr, | |
102 | + "Bug report finished but could not be copied to '%s'.\n" | |
103 | + "Try to run 'adb pull %s <directory>'\n" | |
104 | + "to copy it to a directory that can be written.\n", | |
105 | + destination.c_str(), src_file_.c_str()); | |
106 | + } | |
107 | + } | |
60 | 108 | return status_; |
61 | 109 | } |
62 | 110 | |
63 | 111 | private: |
112 | + void SetLineMessage() { | |
113 | + line_message_ = | |
114 | + android::base::StringPrintf("generating %s", adb_basename(dest_file_).c_str()); | |
115 | + } | |
116 | + | |
117 | + void SetSrcFile(const std::string path) { | |
118 | + src_file_ = path; | |
119 | + if (!dest_dir_.empty()) { | |
120 | + // Only uses device-provided name when user passed a directory. | |
121 | + dest_file_ = adb_basename(path); | |
122 | + SetLineMessage(); | |
123 | + } | |
124 | + } | |
125 | + | |
64 | 126 | void ProcessLine(const std::string& line) { |
65 | 127 | if (line.empty()) return; |
66 | 128 | |
67 | - if (android::base::StartsWith(line, BUGZ_OK_PREFIX)) { | |
68 | - if (show_progress_) { | |
69 | - // Make sure pull message doesn't conflict with generation message. | |
70 | - br_->UpdateProgress(line_message_, 100, 100); | |
71 | - } | |
72 | - | |
73 | - const char* zip_file = &line[strlen(BUGZ_OK_PREFIX)]; | |
74 | - std::vector<const char*> srcs{zip_file}; | |
75 | - status_ = br_->DoSyncPull(srcs, dest_file_.c_str(), true, line_message_.c_str()) ? 0 : 1; | |
76 | - if (status_ != 0) { | |
77 | - fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file_.c_str()); | |
78 | - } | |
129 | + if (android::base::StartsWith(line, BUGZ_BEGIN_PREFIX)) { | |
130 | + SetSrcFile(&line[strlen(BUGZ_BEGIN_PREFIX)]); | |
131 | + } else if (android::base::StartsWith(line, BUGZ_OK_PREFIX)) { | |
132 | + SetSrcFile(&line[strlen(BUGZ_OK_PREFIX)]); | |
79 | 133 | } else if (android::base::StartsWith(line, BUGZ_FAIL_PREFIX)) { |
80 | 134 | const char* error_message = &line[strlen(BUGZ_FAIL_PREFIX)]; |
81 | 135 | fprintf(stderr, "Device failed to take a zipped bugreport: %s\n", error_message); |
@@ -89,24 +143,38 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface | ||
89 | 143 | size_t idx2 = line.rfind(BUGZ_PROGRESS_SEPARATOR); |
90 | 144 | int progress = std::stoi(line.substr(idx1, (idx2 - idx1))); |
91 | 145 | int total = std::stoi(line.substr(idx2 + 1)); |
92 | - br_->UpdateProgress(dest_file_, progress, total); | |
146 | + br_->UpdateProgress(line_message_, progress, total); | |
93 | 147 | } else { |
94 | - fprintf(stderr, | |
95 | - "WARNING: unexpected line (%s) returned by bugreportz, " | |
96 | - "device probably does not support zipped bugreports.\n" | |
97 | - "Try 'adb bugreport' instead.", | |
98 | - line.c_str()); | |
148 | + invalid_lines_.push_back(line); | |
99 | 149 | } |
100 | 150 | } |
101 | 151 | |
102 | 152 | Bugreport* br_; |
103 | - const std::string dest_file_; | |
104 | - const std::string line_message_; | |
153 | + | |
154 | + // Path of bugreport on device. | |
155 | + std::string src_file_; | |
156 | + | |
157 | + // Bugreport destination on host, depending on argument passed on constructor: | |
158 | + // - if argument is a directory, dest_dir_ is set with it and dest_file_ will be the name | |
159 | + // of the bugreport reported by the device. | |
160 | + // - if argument is empty, dest_dir is set as the current directory and dest_file_ will be the | |
161 | + // name of the bugreport reported by the device. | |
162 | + // - otherwise, dest_dir_ is not set and dest_file_ is set with the value passed on constructor. | |
163 | + std::string dest_dir_, dest_file_; | |
164 | + | |
165 | + // Message displayed on LinePrinter, it's updated every time the destination above change. | |
166 | + std::string line_message_; | |
167 | + | |
168 | + // Lines sent by bugreportz that contain invalid commands; will be displayed at the end. | |
169 | + std::vector<std::string> invalid_lines_; | |
170 | + | |
171 | + // Whether PROGRESS_LINES should be interpreted as progress. | |
105 | 172 | bool show_progress_; |
173 | + | |
174 | + // Overall process of the operation, as returned by Done(). | |
106 | 175 | int status_; |
107 | 176 | |
108 | - // Temporary buffer containing the characters read since the last newline | |
109 | - // (\n). | |
177 | + // Temporary buffer containing the characters read since the last newline (\n). | |
110 | 178 | std::string line_; |
111 | 179 | |
112 | 180 | DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback); |
@@ -116,34 +184,54 @@ class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface | ||
116 | 184 | int usage(); |
117 | 185 | |
118 | 186 | int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) { |
119 | - if (argc == 1) return SendShellCommand(transport_type, serial, "bugreport", false); | |
120 | - if (argc != 2) return usage(); | |
121 | - | |
122 | - // Zipped bugreport option - will call 'bugreportz', which prints the location | |
123 | - // of the generated | |
124 | - // file, then pull it to the destination file provided by the user. | |
125 | - std::string dest_file = argv[1]; | |
126 | - if (!android::base::EndsWith(argv[1], ".zip")) { | |
127 | - // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase | |
128 | - dest_file += ".zip"; | |
129 | - } | |
187 | + if (argc > 2) return usage(); | |
130 | 188 | |
131 | 189 | // Gets bugreportz version. |
132 | 190 | std::string bugz_stderr; |
133 | 191 | DefaultStandardStreamsCallback version_callback(nullptr, &bugz_stderr); |
134 | 192 | int status = SendShellCommand(transport_type, serial, "bugreportz -v", false, &version_callback); |
193 | + std::string bugz_version = android::base::Trim(bugz_stderr); | |
194 | + | |
195 | + if (status != 0 || bugz_version.empty()) { | |
196 | + // Device does not support bugreportz: if called as 'adb bugreport', just falls out to the | |
197 | + // flat-file version | |
198 | + if (argc == 1) return SendShellCommand(transport_type, serial, "bugreport", false); | |
135 | 199 | |
136 | - if (status != 0) { | |
200 | + // But if user explicitly asked for a zipped bug report, fails instead (otherwise calling | |
201 | + // 'bugreport' would generate a lot of output the user might not be prepared to handle) | |
137 | 202 | fprintf(stderr, |
138 | - "Failed to get bugreportz version: 'bugreport -v' returned '%s' " | |
139 | - "(code %d)." | |
140 | - "\nIf the device does not support it, try running 'adb bugreport' " | |
141 | - "to get a " | |
142 | - "flat-file bugreport.", | |
203 | + "Failed to get bugreportz version: 'bugreportz -v' returned '%s' (code %d).\n" | |
204 | + "If the device runs Android M or below, try 'adb bugreport' instead.\n", | |
143 | 205 | bugz_stderr.c_str(), status); |
144 | - return status; | |
206 | + return status != 0 ? status : -1; | |
207 | + } | |
208 | + | |
209 | + std::string dest_file, dest_dir; | |
210 | + | |
211 | + if (argc == 1) { | |
212 | + // No args - use current directory | |
213 | + if (!getcwd(&dest_dir)) { | |
214 | + perror("adb: getcwd failed"); | |
215 | + return 1; | |
216 | + } | |
217 | + } else { | |
218 | + // Check whether argument is a directory or file | |
219 | + if (directory_exists(argv[1])) { | |
220 | + dest_dir = argv[1]; | |
221 | + } else { | |
222 | + dest_file = argv[1]; | |
223 | + } | |
224 | + } | |
225 | + | |
226 | + if (dest_file.empty()) { | |
227 | + // Uses a default value until device provides the proper name | |
228 | + dest_file = "bugreport.zip"; | |
229 | + } else { | |
230 | + if (!android::base::EndsWith(dest_file, ".zip")) { | |
231 | + // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase | |
232 | + dest_file += ".zip"; | |
233 | + } | |
145 | 234 | } |
146 | - std::string bugz_version = android::base::Trim(bugz_stderr); | |
147 | 235 | |
148 | 236 | bool show_progress = true; |
149 | 237 | std::string bugz_command = "bugreportz -p"; |
@@ -153,12 +241,11 @@ int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, | ||
153 | 241 | fprintf(stderr, |
154 | 242 | "Bugreport is in progress and it could take minutes to complete.\n" |
155 | 243 | "Please be patient and do not cancel or disconnect your device " |
156 | - "until it completes." | |
157 | - "\n"); | |
244 | + "until it completes.\n"); | |
158 | 245 | show_progress = false; |
159 | 246 | bugz_command = "bugreportz"; |
160 | 247 | } |
161 | - BugreportStandardStreamsCallback bugz_callback(dest_file, show_progress, this); | |
248 | + BugreportStandardStreamsCallback bugz_callback(dest_dir, dest_file, show_progress, this); | |
162 | 249 | return SendShellCommand(transport_type, serial, bugz_command, false, &bugz_callback); |
163 | 250 | } |
164 | 251 |
@@ -19,6 +19,12 @@ | ||
19 | 19 | #include <gmock/gmock.h> |
20 | 20 | #include <gtest/gtest.h> |
21 | 21 | |
22 | +#include <android-base/strings.h> | |
23 | +#include <android-base/test_utils.h> | |
24 | + | |
25 | +#include "sysdeps.h" | |
26 | +#include "adb_utils.h" | |
27 | + | |
22 | 28 | using ::testing::_; |
23 | 29 | using ::testing::Action; |
24 | 30 | using ::testing::ActionInterface; |
@@ -122,28 +128,38 @@ class BugreportMock : public Bugreport { | ||
122 | 128 | |
123 | 129 | class BugreportTest : public ::testing::Test { |
124 | 130 | public: |
125 | - void SetBugreportzVersion(const std::string& version) { | |
131 | + void SetUp() { | |
132 | + if (!getcwd(&cwd_)) { | |
133 | + ADD_FAILURE() << "getcwd failed: " << strerror(errno); | |
134 | + return; | |
135 | + } | |
136 | + } | |
137 | + | |
138 | + void ExpectBugreportzVersion(const std::string& version) { | |
126 | 139 | EXPECT_CALL(br_, |
127 | 140 | SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -v", false, _)) |
128 | 141 | .WillOnce(DoAll(WithArg<4>(WriteOnStderr(version.c_str())), |
129 | 142 | WithArg<4>(ReturnCallbackDone(0)))); |
130 | 143 | } |
131 | 144 | |
132 | - void ExpectProgress(int progress, int total) { | |
133 | - EXPECT_CALL(br_, UpdateProgress(HasSubstr("file.zip"), progress, total)); | |
145 | + void ExpectProgress(int progress, int total, const std::string& file = "file.zip") { | |
146 | + EXPECT_CALL(br_, UpdateProgress(StrEq("generating " + file), progress, total)); | |
134 | 147 | } |
135 | 148 | |
136 | 149 | BugreportMock br_; |
150 | + std::string cwd_; // TODO: make it static | |
137 | 151 | }; |
138 | 152 | |
139 | -// Tests when called with invalid number of argumnts | |
153 | +// Tests when called with invalid number of arguments | |
140 | 154 | TEST_F(BugreportTest, InvalidNumberArgs) { |
141 | 155 | const char* args[1024] = {"bugreport", "to", "principal"}; |
142 | 156 | ASSERT_EQ(-42, br_.DoIt(kTransportLocal, "HannibalLecter", 3, args)); |
143 | 157 | } |
144 | 158 | |
145 | -// Tests the legacy 'adb bugreport' option | |
146 | -TEST_F(BugreportTest, FlatFileFormat) { | |
159 | +// Tests the 'adb bugreport' option when the device does not support 'bugreportz' - it falls back | |
160 | +// to the flat-file format ('bugreport' binary on device) | |
161 | +TEST_F(BugreportTest, NoArgumentsPreNDevice) { | |
162 | + ExpectBugreportzVersion(""); | |
147 | 163 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreport", false, _)) |
148 | 164 | .WillOnce(Return(0)); |
149 | 165 |
@@ -151,15 +167,52 @@ TEST_F(BugreportTest, FlatFileFormat) { | ||
151 | 167 | ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args)); |
152 | 168 | } |
153 | 169 | |
154 | -// Tests 'adb bugreport file.zip' when it succeeds and device does not support | |
155 | -// progress. | |
156 | -TEST_F(BugreportTest, OkLegacy) { | |
157 | - SetBugreportzVersion("1.0"); | |
170 | +// Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.0 - it will | |
171 | +// save the bugreport in the current directory with the name provided by the device. | |
172 | +TEST_F(BugreportTest, NoArgumentsNDevice) { | |
173 | + ExpectBugreportzVersion("1.0"); | |
174 | + | |
175 | + std::string dest_file = | |
176 | + android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR); | |
177 | + EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) | |
178 | + .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")), | |
179 | + WithArg<4>(ReturnCallbackDone()))); | |
180 | + EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), | |
181 | + true, StrEq("generating da_bugreport.zip"))) | |
182 | + .WillOnce(Return(true)); | |
183 | + | |
184 | + const char* args[1024] = {"bugreport"}; | |
185 | + ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args)); | |
186 | +} | |
187 | + | |
188 | +// Tests the 'adb bugreport' option when the device supports 'bugreportz' version 1.1 - it will | |
189 | +// save the bugreport in the current directory with the name provided by the device. | |
190 | +TEST_F(BugreportTest, NoArgumentsPostNDevice) { | |
191 | + ExpectBugreportzVersion("1.1"); | |
192 | + std::string dest_file = | |
193 | + android::base::StringPrintf("%s%cda_bugreport.zip", cwd_.c_str(), OS_PATH_SEPARATOR); | |
194 | + ExpectProgress(50, 100, "da_bugreport.zip"); | |
195 | + EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) | |
196 | + .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), | |
197 | + WithArg<4>(WriteOnStdout("PROGRESS:50/100\n")), | |
198 | + WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip\n")), | |
199 | + WithArg<4>(ReturnCallbackDone()))); | |
200 | + EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), | |
201 | + true, StrEq("generating da_bugreport.zip"))) | |
202 | + .WillOnce(Return(true)); | |
203 | + | |
204 | + const char* args[1024] = {"bugreport"}; | |
205 | + ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 1, args)); | |
206 | +} | |
207 | + | |
208 | +// Tests 'adb bugreport file.zip' when it succeeds and device does not support progress. | |
209 | +TEST_F(BugreportTest, OkNDevice) { | |
210 | + ExpectBugreportzVersion("1.0"); | |
158 | 211 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) |
159 | 212 | .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")), |
160 | 213 | WithArg<4>(ReturnCallbackDone()))); |
161 | 214 | EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), |
162 | - true, HasSubstr("file.zip"))) | |
215 | + true, StrEq("generating file.zip"))) | |
163 | 216 | .WillOnce(Return(true)); |
164 | 217 | |
165 | 218 | const char* args[1024] = {"bugreport", "file.zip"}; |
@@ -168,14 +221,14 @@ TEST_F(BugreportTest, OkLegacy) { | ||
168 | 221 | |
169 | 222 | // Tests 'adb bugreport file.zip' when it succeeds but response was sent in |
170 | 223 | // multiple buffer writers and without progress updates. |
171 | -TEST_F(BugreportTest, OkLegacySplitBuffer) { | |
172 | - SetBugreportzVersion("1.0"); | |
224 | +TEST_F(BugreportTest, OkNDeviceSplitBuffer) { | |
225 | + ExpectBugreportzVersion("1.0"); | |
173 | 226 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) |
174 | 227 | .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device")), |
175 | 228 | WithArg<4>(WriteOnStdout("/bugreport.zip")), |
176 | 229 | WithArg<4>(ReturnCallbackDone()))); |
177 | 230 | EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), |
178 | - true, HasSubstr("file.zip"))) | |
231 | + true, StrEq("generating file.zip"))) | |
179 | 232 | .WillOnce(Return(true)); |
180 | 233 | |
181 | 234 | const char* args[1024] = {"bugreport", "file.zip"}; |
@@ -183,20 +236,22 @@ TEST_F(BugreportTest, OkLegacySplitBuffer) { | ||
183 | 236 | } |
184 | 237 | |
185 | 238 | // Tests 'adb bugreport file.zip' when it succeeds and displays progress. |
186 | -TEST_F(BugreportTest, Ok) { | |
187 | - SetBugreportzVersion("1.1"); | |
239 | +TEST_F(BugreportTest, OkProgress) { | |
240 | + ExpectBugreportzVersion("1.1"); | |
188 | 241 | ExpectProgress(1, 100); |
189 | 242 | ExpectProgress(10, 100); |
190 | 243 | ExpectProgress(50, 100); |
191 | 244 | ExpectProgress(99, 100); |
192 | - ExpectProgress(100, 100); | |
193 | 245 | // clang-format off |
194 | 246 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) |
247 | + // NOTE: DoAll accepts at most 10 arguments, and we're almost reached that limit... | |
195 | 248 | .WillOnce(DoAll( |
249 | + // Name might change on OK, so make sure the right one is picked. | |
250 | + WithArg<4>(WriteOnStdout("BEGIN:/device/bugreport___NOT.zip\n")), | |
196 | 251 | // Progress line in one write |
197 | 252 | WithArg<4>(WriteOnStdout("PROGRESS:1/100\n")), |
198 | 253 | // Add some bogus lines |
199 | - WithArg<4>(WriteOnStdout("\nDUDE:SWEET\n\n")), | |
254 | + WithArg<4>(WriteOnStdout("\nDUDE:SWEET\n\nBLA\n\nBLA\nBLA\n\n")), | |
200 | 255 | // Multiple progress lines in one write |
201 | 256 | WithArg<4>(WriteOnStdout("PROGRESS:10/100\nPROGRESS:50/100\n")), |
202 | 257 | // Progress line in multiple writes |
@@ -207,32 +262,70 @@ TEST_F(BugreportTest, Ok) { | ||
207 | 262 | WithArg<4>(WriteOnStdout("OK:/device/bugreport")), |
208 | 263 | WithArg<4>(WriteOnStdout(".zip")), |
209 | 264 | WithArg<4>(ReturnCallbackDone()))); |
265 | + // clang-format on | |
210 | 266 | EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), |
211 | - true, HasSubstr("file.zip"))) | |
267 | + true, StrEq("generating file.zip"))) | |
212 | 268 | .WillOnce(Return(true)); |
213 | 269 | |
214 | 270 | const char* args[1024] = {"bugreport", "file.zip"}; |
215 | 271 | ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); |
216 | 272 | } |
217 | 273 | |
274 | +// Tests 'adb bugreport dir' when it succeeds and destination is a directory. | |
275 | +TEST_F(BugreportTest, OkDirectory) { | |
276 | + ExpectBugreportzVersion("1.1"); | |
277 | + TemporaryDir td; | |
278 | + std::string dest_file = | |
279 | + android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR); | |
280 | + | |
281 | + EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) | |
282 | + .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), | |
283 | + WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")), | |
284 | + WithArg<4>(ReturnCallbackDone()))); | |
285 | + EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), | |
286 | + true, StrEq("generating da_bugreport.zip"))) | |
287 | + .WillOnce(Return(true)); | |
288 | + | |
289 | + const char* args[1024] = {"bugreport", td.path}; | |
290 | + ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); | |
291 | +} | |
292 | + | |
218 | 293 | // Tests 'adb bugreport file' when it succeeds |
219 | 294 | TEST_F(BugreportTest, OkNoExtension) { |
220 | - SetBugreportzVersion("1.1"); | |
221 | - ExpectProgress(100, 100); | |
295 | + ExpectBugreportzVersion("1.1"); | |
222 | 296 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) |
223 | 297 | .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip\n")), |
224 | 298 | WithArg<4>(ReturnCallbackDone()))); |
225 | 299 | EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/bugreport.zip")), StrEq("file.zip"), |
226 | - true, HasSubstr("file.zip"))) | |
300 | + true, StrEq("generating file.zip"))) | |
227 | 301 | .WillOnce(Return(true)); |
228 | 302 | |
229 | 303 | const char* args[1024] = {"bugreport", "file"}; |
230 | 304 | ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); |
231 | 305 | } |
232 | 306 | |
307 | +// Tests 'adb bugreport dir' when it succeeds and destination is a directory and device runs N. | |
308 | +TEST_F(BugreportTest, OkNDeviceDirectory) { | |
309 | + ExpectBugreportzVersion("1.0"); | |
310 | + TemporaryDir td; | |
311 | + std::string dest_file = | |
312 | + android::base::StringPrintf("%s%cda_bugreport.zip", td.path, OS_PATH_SEPARATOR); | |
313 | + | |
314 | + EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz", false, _)) | |
315 | + .WillOnce(DoAll(WithArg<4>(WriteOnStdout("BEGIN:/device/da_bugreport.zip\n")), | |
316 | + WithArg<4>(WriteOnStdout("OK:/device/da_bugreport.zip")), | |
317 | + WithArg<4>(ReturnCallbackDone()))); | |
318 | + EXPECT_CALL(br_, DoSyncPull(ElementsAre(StrEq("/device/da_bugreport.zip")), StrEq(dest_file), | |
319 | + true, StrEq("generating da_bugreport.zip"))) | |
320 | + .WillOnce(Return(true)); | |
321 | + | |
322 | + const char* args[1024] = {"bugreport", td.path}; | |
323 | + ASSERT_EQ(0, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); | |
324 | +} | |
325 | + | |
233 | 326 | // Tests 'adb bugreport file.zip' when the bugreport itself failed |
234 | 327 | TEST_F(BugreportTest, BugreportzReturnedFail) { |
235 | - SetBugreportzVersion("1.1"); | |
328 | + ExpectBugreportzVersion("1.1"); | |
236 | 329 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) |
237 | 330 | .WillOnce( |
238 | 331 | DoAll(WithArg<4>(WriteOnStdout("FAIL:D'OH!\n")), WithArg<4>(ReturnCallbackDone()))); |
@@ -247,7 +340,7 @@ TEST_F(BugreportTest, BugreportzReturnedFail) { | ||
247 | 340 | // was sent in |
248 | 341 | // multiple buffer writes |
249 | 342 | TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) { |
250 | - SetBugreportzVersion("1.1"); | |
343 | + ExpectBugreportzVersion("1.1"); | |
251 | 344 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) |
252 | 345 | .WillOnce(DoAll(WithArg<4>(WriteOnStdout("FAIL")), WithArg<4>(WriteOnStdout(":D'OH!\n")), |
253 | 346 | WithArg<4>(ReturnCallbackDone()))); |
@@ -261,7 +354,7 @@ TEST_F(BugreportTest, BugreportzReturnedFailSplitBuffer) { | ||
261 | 354 | // Tests 'adb bugreport file.zip' when the bugreportz returned an unsupported |
262 | 355 | // response. |
263 | 356 | TEST_F(BugreportTest, BugreportzReturnedUnsupported) { |
264 | - SetBugreportzVersion("1.1"); | |
357 | + ExpectBugreportzVersion("1.1"); | |
265 | 358 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) |
266 | 359 | .WillOnce(DoAll(WithArg<4>(WriteOnStdout("bugreportz? What am I, a zombie?")), |
267 | 360 | WithArg<4>(ReturnCallbackDone()))); |
@@ -281,9 +374,17 @@ TEST_F(BugreportTest, BugreportzVersionFailed) { | ||
281 | 374 | ASSERT_EQ(666, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); |
282 | 375 | } |
283 | 376 | |
377 | +// Tests 'adb bugreport file.zip' when the bugreportz -v returns status 0 but with no output. | |
378 | +TEST_F(BugreportTest, BugreportzVersionEmpty) { | |
379 | + ExpectBugreportzVersion(""); | |
380 | + | |
381 | + const char* args[1024] = {"bugreport", "file.zip"}; | |
382 | + ASSERT_EQ(-1, br_.DoIt(kTransportLocal, "HannibalLecter", 2, args)); | |
383 | +} | |
384 | + | |
284 | 385 | // Tests 'adb bugreport file.zip' when the main bugreportz command failed |
285 | 386 | TEST_F(BugreportTest, BugreportzFailed) { |
286 | - SetBugreportzVersion("1.1"); | |
387 | + ExpectBugreportzVersion("1.1"); | |
287 | 388 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) |
288 | 389 | .WillOnce(Return(666)); |
289 | 390 |
@@ -293,8 +394,7 @@ TEST_F(BugreportTest, BugreportzFailed) { | ||
293 | 394 | |
294 | 395 | // Tests 'adb bugreport file.zip' when the bugreport could not be pulled |
295 | 396 | TEST_F(BugreportTest, PullFails) { |
296 | - SetBugreportzVersion("1.1"); | |
297 | - ExpectProgress(100, 100); | |
397 | + ExpectBugreportzVersion("1.1"); | |
298 | 398 | EXPECT_CALL(br_, SendShellCommand(kTransportLocal, "HannibalLecter", "bugreportz -p", false, _)) |
299 | 399 | .WillOnce(DoAll(WithArg<4>(WriteOnStdout("OK:/device/bugreport.zip")), |
300 | 400 | WithArg<4>(ReturnCallbackDone()))); |
@@ -81,6 +81,7 @@ static std::string product_file(const char *extra) { | ||
81 | 81 | |
82 | 82 | static void help() { |
83 | 83 | fprintf(stderr, "%s\n", adb_version().c_str()); |
84 | + // clang-format off | |
84 | 85 | fprintf(stderr, |
85 | 86 | " -a - directs adb to listen on all interfaces for a connection\n" |
86 | 87 | " -d - directs command to the only connected USB device\n" |
@@ -173,9 +174,11 @@ static void help() { | ||
173 | 174 | " (-g: grant all runtime permissions)\n" |
174 | 175 | " adb uninstall [-k] <package> - remove this app package from the device\n" |
175 | 176 | " ('-k' means keep the data and cache directories)\n" |
176 | - " adb bugreport [<zip_file>] - return all information from the device\n" | |
177 | - " that should be included in a bug report.\n" | |
178 | - "\n" | |
177 | + " adb bugreport [<path>] - return all information from the device that should be included in a zipped bug report.\n" | |
178 | + " If <path> is a file, the bug report will be saved as that file.\n" | |
179 | + " If <path> is a directory, the bug report will be saved in that directory with the name provided by the device.\n" | |
180 | + " If <path> is omitted, the bug report will be saved in the current directory with the name provided by the device.\n" | |
181 | + " NOTE: if the device does not support zipped bug reports, the bug report will be output on stdout.\n" | |
179 | 182 | " adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]\n" |
180 | 183 | " - write an archive of the device's data to <file>.\n" |
181 | 184 | " If no -f option is supplied then the data is written\n" |
@@ -249,8 +252,8 @@ static void help() { | ||
249 | 252 | " ADB_TRACE - Print debug information. A comma separated list of the following values\n" |
250 | 253 | " 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp\n" |
251 | 254 | " ANDROID_SERIAL - The serial number to connect to. -s takes priority over this if given.\n" |
252 | - " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n" | |
253 | - ); | |
255 | + " ANDROID_LOG_TAGS - When used with the logcat option, only these debug tags are printed.\n"); | |
256 | + // clang-format on | |
254 | 257 | } |
255 | 258 | |
256 | 259 | int usage() { |
@@ -1327,7 +1330,7 @@ static std::string find_product_out_path(const std::string& hint) { | ||
1327 | 1330 | if (hint.find_first_of(OS_PATH_SEPARATORS) != std::string::npos) { |
1328 | 1331 | std::string cwd; |
1329 | 1332 | if (!getcwd(&cwd)) { |
1330 | - fprintf(stderr, "adb: getcwd failed: %s\n", strerror(errno)); | |
1333 | + perror("adb: getcwd failed"); | |
1331 | 1334 | return ""; |
1332 | 1335 | } |
1333 | 1336 | return android::base::StringPrintf("%s%c%s", cwd.c_str(), OS_PATH_SEPARATOR, hint.c_str()); |