diff options
author | Felipe Leme <felipeal@google.com> | 2016-07-26 12:23:40 -0700 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2016-08-30 13:06:28 -0700 |
commit | 6f5080faa5c95ba7fc9d4c73eaecf4684a79d00c (patch) | |
tree | d00f771767a8a56832dc9352743583cae9d8f339 /adb/bugreport.cpp | |
parent | 0d4f0508c0c20847c8f44353ce00d36fcc3d0788 (diff) | |
download | core-6f5080faa5c95ba7fc9d4c73eaecf4684a79d00c.tar.gz core-6f5080faa5c95ba7fc9d4c73eaecf4684a79d00c.tar.bz2 core-6f5080faa5c95ba7fc9d4c73eaecf4684a79d00c.zip |
DO NOT MERGE: Show bugreport progress.
adb calls bugreportz to generate a bugreport; initially, bugreportz
would only report the final status of the operation (OK or FAIL), but
now it sends intermediate PROGRESS lines reporting its progress (in the
form of current/max).
Similarly, the initial implementation of 'adb bugreport <zip_file>'
would print an initial 'please wait' message and wait for the full
stdout before parsing the result, but now it uses a new callback class
to handle the stdout as it is generated by bugreportz.
BUG: 28609499
Change-Id: I6644fc39a686279e1635f946a47f3847b547d1c1
(cherry picked from commit cd42d658b2d08ace81b5ae3b108acbaca1a1d439)
(cherry picked from commit 97b73a0daf74081a6324bb41cc34d9f0598cfe29)
Diffstat (limited to 'adb/bugreport.cpp')
-rw-r--r-- | adb/bugreport.cpp | 129 |
1 files changed, 102 insertions, 27 deletions
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp index e267f0f87..8a3eb0825 100644 --- a/adb/bugreport.cpp +++ b/adb/bugreport.cpp @@ -23,55 +23,92 @@ static constexpr char BUGZ_OK_PREFIX[] = "OK:"; static constexpr char BUGZ_FAIL_PREFIX[] = "FAIL:"; +static constexpr char BUGZ_PROGRESS_PREFIX[] = "PROGRESS:"; +static constexpr char BUGZ_PROGRESS_SEPARATOR[] = "/"; // Custom callback used to handle the output of zipped bugreports. class BugreportStandardStreamsCallback : public StandardStreamsCallbackInterface { public: - BugreportStandardStreamsCallback(const std::string& dest_file, Bugreport* br) - : br_(br), dest_file_(dest_file), stdout_str_() { + BugreportStandardStreamsCallback(const std::string& dest_file, bool show_progress, Bugreport* br) + : br_(br), dest_file_(dest_file), show_progress_(show_progress), status_(-1), line_() { } void OnStdout(const char* buffer, int length) { - std::string output; - OnStream(&output, stdout, buffer, length); - stdout_str_.append(output); + for (int i = 0; i < length; i++) { + char c = buffer[i]; + if (c == '\n') { + ProcessLine(line_); + line_.clear(); + } else { + line_.append(1, c); + } + } } void OnStderr(const char* buffer, int length) { OnStream(nullptr, stderr, buffer, length); } - int Done(int unused_) { - int status = -1; - std::string output = android::base::Trim(stdout_str_); - if (android::base::StartsWith(output, BUGZ_OK_PREFIX)) { - const char* zip_file = &output[strlen(BUGZ_OK_PREFIX)]; + // Process remaining line, if any... + ProcessLine(line_); + // ..then return. + return status_; + } + + private: + void ProcessLine(const std::string& line) { + if (line.empty()) return; + + if (android::base::StartsWith(line, BUGZ_OK_PREFIX)) { + if (show_progress_) { + // Make sure pull message doesn't conflict with generation message. + br_->UpdateProgress(dest_file_, 100, 100, true); + } + + const char* zip_file = &line[strlen(BUGZ_OK_PREFIX)]; std::vector<const char*> srcs{zip_file}; - status = br_->DoSyncPull(srcs, dest_file_.c_str(), true, dest_file_.c_str()) ? 0 : 1; - if (status != 0) { + status_ = br_->DoSyncPull(srcs, dest_file_.c_str(), true, dest_file_.c_str()) ? 0 : 1; + if (status_ != 0) { fprintf(stderr, "Could not copy file '%s' to '%s'\n", zip_file, dest_file_.c_str()); } - } else if (android::base::StartsWith(output, BUGZ_FAIL_PREFIX)) { - const char* error_message = &output[strlen(BUGZ_FAIL_PREFIX)]; + } else if (android::base::StartsWith(line, BUGZ_FAIL_PREFIX)) { + const char* error_message = &line[strlen(BUGZ_FAIL_PREFIX)]; fprintf(stderr, "Device failed to take a zipped bugreport: %s\n", error_message); + status_ = -1; + } else if (show_progress_ && android::base::StartsWith(line, BUGZ_PROGRESS_PREFIX)) { + // progress_line should have the following format: + // + // BUGZ_PROGRESS_PREFIX:PROGRESS/TOTAL + // + size_t idx1 = line.rfind(BUGZ_PROGRESS_PREFIX) + strlen(BUGZ_PROGRESS_PREFIX); + size_t idx2 = line.rfind(BUGZ_PROGRESS_SEPARATOR); + int progress = std::stoi(line.substr(idx1, (idx2 - idx1))); + int total = std::stoi(line.substr(idx2 + 1)); + br_->UpdateProgress(dest_file_, progress, total); } else { fprintf(stderr, - "Unexpected string (%s) returned by bugreportz, " - "device probably does not support it\n", - output.c_str()); + "WARNING: unexpected line (%s) returned by bugreportz, " + "device probably does not support zipped bugreports.\n" + "Try 'adb bugreport' instead.", + line.c_str()); } - - return status; } - private: Bugreport* br_; const std::string dest_file_; - std::string stdout_str_; + bool show_progress_; + int status_; + + // Temporary buffer containing the characters read since the last newline + // (\n). + std::string line_; DISALLOW_COPY_AND_ASSIGN(BugreportStandardStreamsCallback); }; +// Implemented in commandline.cpp +int usage(); + int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, const char** argv) { if (argc == 1) return SendShellCommand(transport_type, serial, "bugreport", false); if (argc != 2) return usage(); @@ -84,12 +121,50 @@ int Bugreport::DoIt(TransportType transport_type, const char* serial, int argc, // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase dest_file += ".zip"; } - fprintf(stderr, - "Bugreport is in progress and it could take minutes to complete.\n" - "Please be patient and do not cancel or disconnect your device until " - "it completes.\n"); - BugreportStandardStreamsCallback bugz_callback(dest_file, this); - return SendShellCommand(transport_type, serial, "bugreportz", false, &bugz_callback); + + // Gets bugreportz version. + std::string bugz_stderr; + DefaultStandardStreamsCallback version_callback(nullptr, &bugz_stderr); + int status = SendShellCommand(transport_type, serial, "bugreportz -v", false, &version_callback); + + if (status != 0) { + fprintf(stderr, + "Failed to get bugreportz version: 'bugreport -v' returned '%s' " + "(code %d)." + "\nIf the device does not support it, try running 'adb bugreport' " + "to get a " + "flat-file bugreport.", + bugz_stderr.c_str(), status); + return status; + } + std::string bugz_version = android::base::Trim(bugz_stderr); + + bool show_progress = true; + std::string bugz_command = "bugreportz -p"; + if (bugz_version == "1.0") { + // 1.0 does not support progress notifications, so print a disclaimer + // message instead. + fprintf(stderr, + "Bugreport is in progress and it could take minutes to complete.\n" + "Please be patient and do not cancel or disconnect your device " + "until it completes." + "\n"); + show_progress = false; + bugz_command = "bugreportz"; + } + BugreportStandardStreamsCallback bugz_callback(dest_file, show_progress, this); + return SendShellCommand(transport_type, serial, bugz_command, false, &bugz_callback); +} + +void Bugreport::UpdateProgress(const std::string& file_name, int progress, int total, + bool keep_info_line) { + int progress_percentage = (progress * 100 / total); + line_printer_.Print(android::base::StringPrintf("[%3d%%] generating %s", progress_percentage, + file_name.c_str()), + LinePrinter::INFO); + if (keep_info_line) { + line_printer_.KeepInfoLine(); + } } int Bugreport::SendShellCommand(TransportType transport_type, const char* serial, |