Home | History | Annotate | Download | only in update_engine
      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