Report the progress of the update when sideloading.
am: 5462f45087
Change-Id: I9acdd6121cae5f3c995d1bbea48d3ecd29ae6178
diff --git a/sideload_main.cc b/sideload_main.cc
index eae9539..46e8f35 100644
--- a/sideload_main.cc
+++ b/sideload_main.cc
@@ -22,18 +22,26 @@
#include <base/command_line.h>
#include <base/logging.h>
#include <base/strings/string_split.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/asynchronous_signal_handler.h>
#include <brillo/flag_helper.h>
+#include <brillo/make_unique_ptr.h>
#include <brillo/message_loops/base_message_loop.h>
+#include <brillo/streams/file_stream.h>
+#include <brillo/streams/stream.h>
#include "update_engine/common/boot_control.h"
+#include "update_engine/common/error_code_utils.h"
#include "update_engine/common/hardware.h"
#include "update_engine/common/prefs.h"
+#include "update_engine/common/subprocess.h"
#include "update_engine/common/terminator.h"
#include "update_engine/common/utils.h"
#include "update_engine/update_attempter_android.h"
using std::string;
using std::vector;
+using update_engine::UpdateStatus;
namespace chromeos_update_engine {
namespace {
@@ -52,7 +60,8 @@
class SideloadDaemonState : public DaemonStateInterface,
public ServiceObserverInterface {
public:
- SideloadDaemonState() {
+ explicit SideloadDaemonState(brillo::StreamPtr status_stream)
+ : status_stream_(std::move(status_stream)) {
// Add this class as the only observer.
observers_.insert(this);
}
@@ -69,13 +78,31 @@
// ServiceObserverInterface overrides.
void SendStatusUpdate(int64_t last_checked_time,
double progress,
- update_engine::UpdateStatus status,
+ UpdateStatus status,
const string& new_version,
int64_t new_size) override {
+ if (status_ != status && (status == UpdateStatus::DOWNLOADING ||
+ status == UpdateStatus::FINALIZING)) {
+ // Split the progress bar in two parts for the two stages DOWNLOADING and
+ // FINALIZING.
+ ReportStatus(base::StringPrintf(
+ "ui_print Step %d/2", status == UpdateStatus::DOWNLOADING ? 1 : 2));
+ ReportStatus(base::StringPrintf("progress 0.5 0"));
+ }
+ if (status_ != status || fabs(progress - progress_) > 0.005) {
+ ReportStatus(base::StringPrintf("set_progress %.lf", progress));
+ }
+ progress_ = progress;
status_ = status;
}
void SendPayloadApplicationComplete(ErrorCode error_code) override {
+ if (error_code != ErrorCode::kSuccess) {
+ ReportStatus(
+ base::StringPrintf("ui_print Error applying update: %d (%s)",
+ error_code,
+ utils::ErrorCodeToString(error_code).c_str()));
+ }
error_code_ = error_code;
brillo::MessageLoop::current()->BreakLoop();
}
@@ -83,26 +110,46 @@
void SendChannelChangeUpdate(const string& tracking_channel) override {}
// Getters.
- update_engine::UpdateStatus status() { return status_; }
+ UpdateStatus status() { return status_; }
ErrorCode error_code() { return error_code_; }
private:
+ // Report a status message in the status_stream_, if any. These messages
+ // should conform to the specification defined in the Android recovery.
+ void ReportStatus(const string& message) {
+ if (!status_stream_)
+ return;
+ string status_line = message + "\n";
+ status_stream_->WriteAllBlocking(
+ status_line.data(), status_line.size(), nullptr);
+ }
+
std::set<ServiceObserverInterface*> observers_;
+ brillo::StreamPtr status_stream_;
// The last status and error code reported.
- update_engine::UpdateStatus status_{update_engine::UpdateStatus::IDLE};
+ UpdateStatus status_{UpdateStatus::IDLE};
ErrorCode error_code_{ErrorCode::kSuccess};
+ double progress_{-1.};
};
// Apply an update payload directly from the given payload URI.
bool ApplyUpdatePayload(const string& payload,
int64_t payload_offset,
int64_t payload_size,
- const vector<string>& headers) {
+ const vector<string>& headers,
+ int64_t status_fd) {
brillo::BaseMessageLoop loop;
loop.SetAsCurrent();
- SideloadDaemonState sideload_daemon_state;
+ // Setup the subprocess handler.
+ brillo::AsynchronousSignalHandler handler;
+ handler.Init();
+ Subprocess subprocess;
+ subprocess.Init(&handler);
+
+ SideloadDaemonState sideload_daemon_state(
+ brillo::FileStream::FromFileDescriptor(status_fd, true, nullptr));
// During the sideload we don't access the prefs persisted on disk but instead
// use a temporary memory storage.
@@ -129,8 +176,7 @@
payload, payload_offset, payload_size, headers, nullptr));
loop.Run();
- return sideload_daemon_state.status() ==
- update_engine::UpdateStatus::UPDATED_NEED_REBOOT;
+ return sideload_daemon_state.status() == UpdateStatus::UPDATED_NEED_REBOOT;
}
} // namespace
@@ -149,6 +195,7 @@
DEFINE_string(headers,
"",
"A list of key-value pairs, one element of the list per line.");
+ DEFINE_int64(status_fd, -1, "A file descriptor to notify the update status.");
chromeos_update_engine::Terminator::Init();
chromeos_update_engine::SetupLogging();
@@ -163,7 +210,7 @@
FLAGS_headers, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
if (!chromeos_update_engine::ApplyUpdatePayload(
- FLAGS_payload, FLAGS_offset, FLAGS_size, headers))
+ FLAGS_payload, FLAGS_offset, FLAGS_size, headers, FLAGS_status_fd))
return 1;
return 0;