diff options
Diffstat (limited to 'aosp/sideload_main.cc')
-rw-r--r-- | aosp/sideload_main.cc | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/aosp/sideload_main.cc b/aosp/sideload_main.cc new file mode 100644 index 00000000..bf015c94 --- /dev/null +++ b/aosp/sideload_main.cc @@ -0,0 +1,206 @@ +// +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#include <xz.h> + +#include <string> +#include <vector> + +#include <base/command_line.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/message_loops/base_message_loop.h> +#include <brillo/streams/file_stream.h> +#include <brillo/streams/stream.h> + +#include "update_engine/aosp/update_attempter_android.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/logging.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" + +using std::string; +using std::vector; +using update_engine::UpdateEngineStatus; +using update_engine::UpdateStatus; + +namespace chromeos_update_engine { +namespace { + +class SideloadDaemonState : public DaemonStateInterface, + public ServiceObserverInterface { + public: + explicit SideloadDaemonState(brillo::StreamPtr status_stream) + : status_stream_(std::move(status_stream)) { + // Add this class as the only observer. + observers_.insert(this); + } + ~SideloadDaemonState() override = default; + + // DaemonStateInterface overrides. + bool StartUpdater() override { return true; } + void AddObserver(ServiceObserverInterface* observer) override {} + void RemoveObserver(ServiceObserverInterface* observer) override {} + const std::set<ServiceObserverInterface*>& service_observers() override { + return observers_; + } + + // ServiceObserverInterface overrides. + void SendStatusUpdate( + const UpdateEngineStatus& update_engine_status) override { + UpdateStatus status = update_engine_status.status; + double progress = update_engine_status.progress; + 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(); + } + + // Getters. + 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. + 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, + int64_t status_fd) { + brillo::BaseMessageLoop loop; + loop.SetAsCurrent(); + + // 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. + MemoryPrefs prefs; + + std::unique_ptr<BootControlInterface> boot_control = + boot_control::CreateBootControl(); + if (!boot_control) { + LOG(ERROR) << "Error initializing the BootControlInterface."; + return false; + } + + std::unique_ptr<HardwareInterface> hardware = hardware::CreateHardware(); + if (!hardware) { + LOG(ERROR) << "Error initializing the HardwareInterface."; + return false; + } + + UpdateAttempterAndroid update_attempter(&sideload_daemon_state, + &prefs, + boot_control.get(), + hardware.get(), + nullptr); + update_attempter.Init(); + + TEST_AND_RETURN_FALSE(update_attempter.ApplyPayload( + payload, payload_offset, payload_size, headers, nullptr)); + + loop.Run(); + return sideload_daemon_state.status() == UpdateStatus::UPDATED_NEED_REBOOT; +} + +} // namespace +} // namespace chromeos_update_engine + +int main(int argc, char** argv) { + DEFINE_string(payload, + "file:///data/payload.bin", + "The URI to the update payload to use."); + DEFINE_int64( + offset, 0, "The offset in the payload where the CrAU update starts. "); + DEFINE_int64(size, + 0, + "The size of the CrAU part of the payload. If 0 is passed, it " + "will be autodetected."); + 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(true /* stderr */, false /* file */); + brillo::FlagHelper::Init(argc, argv, "Update Engine Sideload"); + + LOG(INFO) << "Update Engine Sideloading starting"; + + // xz-embedded requires to initialize its CRC-32 table once on startup. + xz_crc32_init(); + + vector<string> headers = base::SplitString( + FLAGS_headers, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + + if (!chromeos_update_engine::ApplyUpdatePayload( + FLAGS_payload, FLAGS_offset, FLAGS_size, headers, FLAGS_status_fd)) + return 1; + + return 0; +} |