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 17 #include <xz.h> 18 19 #include <string> 20 #include <vector> 21 22 #include <base/command_line.h> 23 #include <base/logging.h> 24 #include <base/strings/string_split.h> 25 #include <base/strings/stringprintf.h> 26 #include <brillo/asynchronous_signal_handler.h> 27 #include <brillo/flag_helper.h> 28 #include <brillo/make_unique_ptr.h> 29 #include <brillo/message_loops/base_message_loop.h> 30 #include <brillo/streams/file_stream.h> 31 #include <brillo/streams/stream.h> 32 33 #include "update_engine/common/boot_control.h" 34 #include "update_engine/common/error_code_utils.h" 35 #include "update_engine/common/hardware.h" 36 #include "update_engine/common/prefs.h" 37 #include "update_engine/common/subprocess.h" 38 #include "update_engine/common/terminator.h" 39 #include "update_engine/common/utils.h" 40 #include "update_engine/update_attempter_android.h" 41 42 using std::string; 43 using std::vector; 44 using update_engine::UpdateStatus; 45 46 namespace { 47 // The root directory used for temporary files in update_engine_sideload. 48 const char kSideloadRootTempDir[] = "/tmp/update_engine_sideload"; 49 } // namespace 50 51 namespace chromeos_update_engine { 52 namespace { 53 54 void SetupLogging() { 55 string log_file; 56 logging::LoggingSettings log_settings; 57 log_settings.lock_log = logging::DONT_LOCK_LOG_FILE; 58 log_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE; 59 log_settings.log_file = nullptr; 60 log_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; 61 62 logging::InitLogging(log_settings); 63 } 64 65 class SideloadDaemonState : public DaemonStateInterface, 66 public ServiceObserverInterface { 67 public: 68 explicit SideloadDaemonState(brillo::StreamPtr status_stream) 69 : status_stream_(std::move(status_stream)) { 70 // Add this class as the only observer. 71 observers_.insert(this); 72 } 73 ~SideloadDaemonState() override = default; 74 75 // DaemonStateInterface overrides. 76 bool StartUpdater() override { return true; } 77 void AddObserver(ServiceObserverInterface* observer) override {} 78 void RemoveObserver(ServiceObserverInterface* observer) override {} 79 const std::set<ServiceObserverInterface*>& service_observers() override { 80 return observers_; 81 } 82 83 // ServiceObserverInterface overrides. 84 void SendStatusUpdate(int64_t last_checked_time, 85 double progress, 86 UpdateStatus status, 87 const string& new_version, 88 int64_t new_size) override { 89 if (status_ != status && (status == UpdateStatus::DOWNLOADING || 90 status == UpdateStatus::FINALIZING)) { 91 // Split the progress bar in two parts for the two stages DOWNLOADING and 92 // FINALIZING. 93 ReportStatus(base::StringPrintf( 94 "ui_print Step %d/2", status == UpdateStatus::DOWNLOADING ? 1 : 2)); 95 ReportStatus(base::StringPrintf("progress 0.5 0")); 96 } 97 if (status_ != status || fabs(progress - progress_) > 0.005) { 98 ReportStatus(base::StringPrintf("set_progress %.lf", progress)); 99 } 100 progress_ = progress; 101 status_ = status; 102 } 103 104 void SendPayloadApplicationComplete(ErrorCode error_code) override { 105 if (error_code != ErrorCode::kSuccess) { 106 ReportStatus( 107 base::StringPrintf("ui_print Error applying update: %d (%s)", 108 error_code, 109 utils::ErrorCodeToString(error_code).c_str())); 110 } 111 error_code_ = error_code; 112 brillo::MessageLoop::current()->BreakLoop(); 113 } 114 115 void SendChannelChangeUpdate(const string& tracking_channel) override {} 116 117 // Getters. 118 UpdateStatus status() { return status_; } 119 ErrorCode error_code() { return error_code_; } 120 121 private: 122 // Report a status message in the status_stream_, if any. These messages 123 // should conform to the specification defined in the Android recovery. 124 void ReportStatus(const string& message) { 125 if (!status_stream_) 126 return; 127 string status_line = message + "\n"; 128 status_stream_->WriteAllBlocking( 129 status_line.data(), status_line.size(), nullptr); 130 } 131 132 std::set<ServiceObserverInterface*> observers_; 133 brillo::StreamPtr status_stream_; 134 135 // The last status and error code reported. 136 UpdateStatus status_{UpdateStatus::IDLE}; 137 ErrorCode error_code_{ErrorCode::kSuccess}; 138 double progress_{-1.}; 139 }; 140 141 // Apply an update payload directly from the given payload URI. 142 bool ApplyUpdatePayload(const string& payload, 143 int64_t payload_offset, 144 int64_t payload_size, 145 const vector<string>& headers, 146 int64_t status_fd) { 147 base::MessageLoopForIO base_loop; 148 brillo::BaseMessageLoop loop(&base_loop); 149 loop.SetAsCurrent(); 150 151 // Setup the subprocess handler. 152 brillo::AsynchronousSignalHandler handler; 153 handler.Init(); 154 Subprocess subprocess; 155 subprocess.Init(&handler); 156 157 SideloadDaemonState sideload_daemon_state( 158 brillo::FileStream::FromFileDescriptor(status_fd, true, nullptr)); 159 160 // During the sideload we don't access the prefs persisted on disk but instead 161 // use a temporary memory storage. 162 MemoryPrefs prefs; 163 164 std::unique_ptr<BootControlInterface> boot_control = 165 boot_control::CreateBootControl(); 166 if (!boot_control) { 167 LOG(ERROR) << "Error initializing the BootControlInterface."; 168 return false; 169 } 170 171 std::unique_ptr<HardwareInterface> hardware = hardware::CreateHardware(); 172 if (!hardware) { 173 LOG(ERROR) << "Error initializing the HardwareInterface."; 174 return false; 175 } 176 177 UpdateAttempterAndroid update_attempter( 178 &sideload_daemon_state, &prefs, boot_control.get(), hardware.get()); 179 update_attempter.Init(); 180 181 TEST_AND_RETURN_FALSE(update_attempter.ApplyPayload( 182 payload, payload_offset, payload_size, headers, nullptr)); 183 184 loop.Run(); 185 return sideload_daemon_state.status() == UpdateStatus::UPDATED_NEED_REBOOT; 186 } 187 188 } // namespace 189 } // namespace chromeos_update_engine 190 191 int main(int argc, char** argv) { 192 DEFINE_string(payload, 193 "file:///data/payload.bin", 194 "The URI to the update payload to use."); 195 DEFINE_int64( 196 offset, 0, "The offset in the payload where the CrAU update starts. "); 197 DEFINE_int64(size, 198 0, 199 "The size of the CrAU part of the payload. If 0 is passed, it " 200 "will be autodetected."); 201 DEFINE_string(headers, 202 "", 203 "A list of key-value pairs, one element of the list per line."); 204 DEFINE_int64(status_fd, -1, "A file descriptor to notify the update status."); 205 206 chromeos_update_engine::Terminator::Init(); 207 chromeos_update_engine::SetupLogging(); 208 brillo::FlagHelper::Init(argc, argv, "Update Engine Sideload"); 209 210 LOG(INFO) << "Update Engine Sideloading starting"; 211 212 // xz-embedded requires to initialize its CRC-32 table once on startup. 213 xz_crc32_init(); 214 215 // When called from recovery, /data is not accessible, so we need to use 216 // /tmp for temporary files. 217 chromeos_update_engine::utils::SetRootTempDir(kSideloadRootTempDir); 218 219 vector<string> headers = base::SplitString( 220 FLAGS_headers, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); 221 222 if (!chromeos_update_engine::ApplyUpdatePayload( 223 FLAGS_payload, FLAGS_offset, FLAGS_size, headers, FLAGS_status_fd)) 224 return 1; 225 226 return 0; 227 } 228