sideload_main.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. //
  2. // Copyright (C) 2016 The Android Open Source Project
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. #include <xz.h>
  17. #include <string>
  18. #include <vector>
  19. #include <base/command_line.h>
  20. #include <base/logging.h>
  21. #include <base/strings/string_split.h>
  22. #include <base/strings/stringprintf.h>
  23. #include <brillo/asynchronous_signal_handler.h>
  24. #include <brillo/flag_helper.h>
  25. #include <brillo/message_loops/base_message_loop.h>
  26. #include <brillo/streams/file_stream.h>
  27. #include <brillo/streams/stream.h>
  28. #include "update_engine/common/boot_control.h"
  29. #include "update_engine/common/error_code_utils.h"
  30. #include "update_engine/common/hardware.h"
  31. #include "update_engine/common/prefs.h"
  32. #include "update_engine/common/subprocess.h"
  33. #include "update_engine/common/terminator.h"
  34. #include "update_engine/common/utils.h"
  35. #include "update_engine/update_attempter_android.h"
  36. using std::string;
  37. using std::vector;
  38. using update_engine::UpdateEngineStatus;
  39. using update_engine::UpdateStatus;
  40. namespace chromeos_update_engine {
  41. namespace {
  42. void SetupLogging() {
  43. string log_file;
  44. logging::LoggingSettings log_settings;
  45. log_settings.lock_log = logging::DONT_LOCK_LOG_FILE;
  46. log_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
  47. log_settings.log_file = nullptr;
  48. log_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
  49. logging::InitLogging(log_settings);
  50. }
  51. class SideloadDaemonState : public DaemonStateInterface,
  52. public ServiceObserverInterface {
  53. public:
  54. explicit SideloadDaemonState(brillo::StreamPtr status_stream)
  55. : status_stream_(std::move(status_stream)) {
  56. // Add this class as the only observer.
  57. observers_.insert(this);
  58. }
  59. ~SideloadDaemonState() override = default;
  60. // DaemonStateInterface overrides.
  61. bool StartUpdater() override { return true; }
  62. void AddObserver(ServiceObserverInterface* observer) override {}
  63. void RemoveObserver(ServiceObserverInterface* observer) override {}
  64. const std::set<ServiceObserverInterface*>& service_observers() override {
  65. return observers_;
  66. }
  67. // ServiceObserverInterface overrides.
  68. void SendStatusUpdate(
  69. const UpdateEngineStatus& update_engine_status) override {
  70. UpdateStatus status = update_engine_status.status;
  71. double progress = update_engine_status.progress;
  72. if (status_ != status && (status == UpdateStatus::DOWNLOADING ||
  73. status == UpdateStatus::FINALIZING)) {
  74. // Split the progress bar in two parts for the two stages DOWNLOADING and
  75. // FINALIZING.
  76. ReportStatus(base::StringPrintf(
  77. "ui_print Step %d/2", status == UpdateStatus::DOWNLOADING ? 1 : 2));
  78. ReportStatus(base::StringPrintf("progress 0.5 0"));
  79. }
  80. if (status_ != status || fabs(progress - progress_) > 0.005) {
  81. ReportStatus(base::StringPrintf("set_progress %.lf", progress));
  82. }
  83. progress_ = progress;
  84. status_ = status;
  85. }
  86. void SendPayloadApplicationComplete(ErrorCode error_code) override {
  87. if (error_code != ErrorCode::kSuccess) {
  88. ReportStatus(
  89. base::StringPrintf("ui_print Error applying update: %d (%s)",
  90. error_code,
  91. utils::ErrorCodeToString(error_code).c_str()));
  92. }
  93. error_code_ = error_code;
  94. brillo::MessageLoop::current()->BreakLoop();
  95. }
  96. // Getters.
  97. UpdateStatus status() { return status_; }
  98. ErrorCode error_code() { return error_code_; }
  99. private:
  100. // Report a status message in the status_stream_, if any. These messages
  101. // should conform to the specification defined in the Android recovery.
  102. void ReportStatus(const string& message) {
  103. if (!status_stream_)
  104. return;
  105. string status_line = message + "\n";
  106. status_stream_->WriteAllBlocking(
  107. status_line.data(), status_line.size(), nullptr);
  108. }
  109. std::set<ServiceObserverInterface*> observers_;
  110. brillo::StreamPtr status_stream_;
  111. // The last status and error code reported.
  112. UpdateStatus status_{UpdateStatus::IDLE};
  113. ErrorCode error_code_{ErrorCode::kSuccess};
  114. double progress_{-1.};
  115. };
  116. // Apply an update payload directly from the given payload URI.
  117. bool ApplyUpdatePayload(const string& payload,
  118. int64_t payload_offset,
  119. int64_t payload_size,
  120. const vector<string>& headers,
  121. int64_t status_fd) {
  122. brillo::BaseMessageLoop loop;
  123. loop.SetAsCurrent();
  124. // Setup the subprocess handler.
  125. brillo::AsynchronousSignalHandler handler;
  126. handler.Init();
  127. Subprocess subprocess;
  128. subprocess.Init(&handler);
  129. SideloadDaemonState sideload_daemon_state(
  130. brillo::FileStream::FromFileDescriptor(status_fd, true, nullptr));
  131. // During the sideload we don't access the prefs persisted on disk but instead
  132. // use a temporary memory storage.
  133. MemoryPrefs prefs;
  134. std::unique_ptr<BootControlInterface> boot_control =
  135. boot_control::CreateBootControl();
  136. if (!boot_control) {
  137. LOG(ERROR) << "Error initializing the BootControlInterface.";
  138. return false;
  139. }
  140. std::unique_ptr<HardwareInterface> hardware = hardware::CreateHardware();
  141. if (!hardware) {
  142. LOG(ERROR) << "Error initializing the HardwareInterface.";
  143. return false;
  144. }
  145. UpdateAttempterAndroid update_attempter(
  146. &sideload_daemon_state, &prefs, boot_control.get(), hardware.get());
  147. update_attempter.Init();
  148. TEST_AND_RETURN_FALSE(update_attempter.ApplyPayload(
  149. payload, payload_offset, payload_size, headers, nullptr));
  150. loop.Run();
  151. return sideload_daemon_state.status() == UpdateStatus::UPDATED_NEED_REBOOT;
  152. }
  153. } // namespace
  154. } // namespace chromeos_update_engine
  155. int main(int argc, char** argv) {
  156. DEFINE_string(payload,
  157. "file:///data/payload.bin",
  158. "The URI to the update payload to use.");
  159. DEFINE_int64(
  160. offset, 0, "The offset in the payload where the CrAU update starts. ");
  161. DEFINE_int64(size,
  162. 0,
  163. "The size of the CrAU part of the payload. If 0 is passed, it "
  164. "will be autodetected.");
  165. DEFINE_string(headers,
  166. "",
  167. "A list of key-value pairs, one element of the list per line.");
  168. DEFINE_int64(status_fd, -1, "A file descriptor to notify the update status.");
  169. chromeos_update_engine::Terminator::Init();
  170. chromeos_update_engine::SetupLogging();
  171. brillo::FlagHelper::Init(argc, argv, "Update Engine Sideload");
  172. LOG(INFO) << "Update Engine Sideloading starting";
  173. // xz-embedded requires to initialize its CRC-32 table once on startup.
  174. xz_crc32_init();
  175. vector<string> headers = base::SplitString(
  176. FLAGS_headers, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  177. if (!chromeos_update_engine::ApplyUpdatePayload(
  178. FLAGS_payload, FLAGS_offset, FLAGS_size, headers, FLAGS_status_fd))
  179. return 1;
  180. return 0;
  181. }