Home | History | Annotate | Download | only in payload_consumer
      1 //
      2 // Copyright (C) 2011 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 "update_engine/payload_consumer/download_action.h"
     18 
     19 #include <errno.h>
     20 
     21 #include <algorithm>
     22 #include <string>
     23 
     24 #include <base/files/file_path.h>
     25 #include <base/metrics/statistics_recorder.h>
     26 #include <base/strings/stringprintf.h>
     27 
     28 #include "update_engine/common/action_pipe.h"
     29 #include "update_engine/common/boot_control_interface.h"
     30 #include "update_engine/common/error_code_utils.h"
     31 #include "update_engine/common/multi_range_http_fetcher.h"
     32 #include "update_engine/common/utils.h"
     33 #include "update_engine/omaha_request_params.h"
     34 #include "update_engine/p2p_manager.h"
     35 #include "update_engine/payload_state_interface.h"
     36 
     37 using base::FilePath;
     38 using std::string;
     39 
     40 namespace chromeos_update_engine {
     41 
     42 DownloadAction::DownloadAction(PrefsInterface* prefs,
     43                                BootControlInterface* boot_control,
     44                                HardwareInterface* hardware,
     45                                SystemState* system_state,
     46                                HttpFetcher* http_fetcher,
     47                                bool is_interactive)
     48     : prefs_(prefs),
     49       boot_control_(boot_control),
     50       hardware_(hardware),
     51       system_state_(system_state),
     52       http_fetcher_(new MultiRangeHttpFetcher(http_fetcher)),
     53       is_interactive_(is_interactive),
     54       writer_(nullptr),
     55       code_(ErrorCode::kSuccess),
     56       delegate_(nullptr),
     57       p2p_sharing_fd_(-1),
     58       p2p_visible_(true) {
     59   base::StatisticsRecorder::Initialize();
     60 }
     61 
     62 DownloadAction::~DownloadAction() {}
     63 
     64 void DownloadAction::CloseP2PSharingFd(bool delete_p2p_file) {
     65   if (p2p_sharing_fd_ != -1) {
     66     if (close(p2p_sharing_fd_) != 0) {
     67       PLOG(ERROR) << "Error closing p2p sharing fd";
     68     }
     69     p2p_sharing_fd_ = -1;
     70   }
     71 
     72   if (delete_p2p_file) {
     73     FilePath path =
     74       system_state_->p2p_manager()->FileGetPath(p2p_file_id_);
     75     if (unlink(path.value().c_str()) != 0) {
     76       PLOG(ERROR) << "Error deleting p2p file " << path.value();
     77     } else {
     78       LOG(INFO) << "Deleted p2p file " << path.value();
     79     }
     80   }
     81 
     82   // Don't use p2p from this point onwards.
     83   p2p_file_id_.clear();
     84 }
     85 
     86 bool DownloadAction::SetupP2PSharingFd() {
     87   P2PManager *p2p_manager = system_state_->p2p_manager();
     88 
     89   if (!p2p_manager->FileShare(p2p_file_id_, payload_->size)) {
     90     LOG(ERROR) << "Unable to share file via p2p";
     91     CloseP2PSharingFd(true);  // delete p2p file
     92     return false;
     93   }
     94 
     95   // File has already been created (and allocated, xattrs been
     96   // populated etc.) by FileShare() so just open it for writing.
     97   FilePath path = p2p_manager->FileGetPath(p2p_file_id_);
     98   p2p_sharing_fd_ = open(path.value().c_str(), O_WRONLY);
     99   if (p2p_sharing_fd_ == -1) {
    100     PLOG(ERROR) << "Error opening file " << path.value();
    101     CloseP2PSharingFd(true);  // Delete p2p file.
    102     return false;
    103   }
    104 
    105   // Ensure file to share is world-readable, otherwise
    106   // p2p-server and p2p-http-server can't access it.
    107   //
    108   // (Q: Why doesn't the file have mode 0644 already? A: Because
    109   // the process-wide umask is set to 0700 in main.cc.)
    110   if (fchmod(p2p_sharing_fd_, 0644) != 0) {
    111     PLOG(ERROR) << "Error setting mode 0644 on " << path.value();
    112     CloseP2PSharingFd(true);  // Delete p2p file.
    113     return false;
    114   }
    115 
    116   // All good.
    117   LOG(INFO) << "Writing payload contents to " << path.value();
    118   p2p_manager->FileGetVisible(p2p_file_id_, &p2p_visible_);
    119   return true;
    120 }
    121 
    122 void DownloadAction::WriteToP2PFile(const void* data,
    123                                     size_t length,
    124                                     off_t file_offset) {
    125   if (p2p_sharing_fd_ == -1) {
    126     if (!SetupP2PSharingFd())
    127       return;
    128   }
    129 
    130   // Check that the file is at least |file_offset| bytes long - if
    131   // it's not something is wrong and we must immediately delete the
    132   // file to avoid propagating this problem to other peers.
    133   //
    134   // How can this happen? It could be that we're resuming an update
    135   // after a system crash... in this case, it could be that
    136   //
    137   //  1. the p2p file didn't get properly synced to stable storage; or
    138   //  2. the file was deleted at bootup (it's in /var/cache after all); or
    139   //  3. other reasons
    140   off_t p2p_size = utils::FileSize(p2p_sharing_fd_);
    141   if (p2p_size < 0) {
    142     PLOG(ERROR) << "Error getting file status for p2p file";
    143     CloseP2PSharingFd(true);  // Delete p2p file.
    144     return;
    145   }
    146   if (p2p_size < file_offset) {
    147     LOG(ERROR) << "Wanting to write to file offset " << file_offset
    148                << " but existing p2p file is only " << p2p_size
    149                << " bytes.";
    150     CloseP2PSharingFd(true);  // Delete p2p file.
    151     return;
    152   }
    153 
    154   off_t cur_file_offset = lseek(p2p_sharing_fd_, file_offset, SEEK_SET);
    155   if (cur_file_offset != static_cast<off_t>(file_offset)) {
    156     PLOG(ERROR) << "Error seeking to position "
    157                 << file_offset << " in p2p file";
    158     CloseP2PSharingFd(true);  // Delete p2p file.
    159   } else {
    160     // OK, seeking worked, now write the data
    161     ssize_t bytes_written = write(p2p_sharing_fd_, data, length);
    162     if (bytes_written != static_cast<ssize_t>(length)) {
    163       PLOG(ERROR) << "Error writing "
    164                   << length << " bytes at file offset "
    165                   << file_offset << " in p2p file";
    166       CloseP2PSharingFd(true);  // Delete p2p file.
    167     }
    168   }
    169 }
    170 
    171 void DownloadAction::PerformAction() {
    172   http_fetcher_->set_delegate(this);
    173 
    174   // Get the InstallPlan and read it
    175   CHECK(HasInputObject());
    176   install_plan_ = GetInputObject();
    177   install_plan_.Dump();
    178 
    179   bytes_received_ = 0;
    180   bytes_received_previous_payloads_ = 0;
    181   bytes_total_ = 0;
    182   for (const auto& payload : install_plan_.payloads)
    183     bytes_total_ += payload.size;
    184 
    185   if (install_plan_.is_resume) {
    186     int64_t payload_index = 0;
    187     if (prefs_->GetInt64(kPrefsUpdateStatePayloadIndex, &payload_index) &&
    188         static_cast<size_t>(payload_index) < install_plan_.payloads.size()) {
    189       // Save the index for the resume payload before downloading any previous
    190       // payload, otherwise it will be overwritten.
    191       resume_payload_index_ = payload_index;
    192       for (int i = 0; i < payload_index; i++)
    193         install_plan_.payloads[i].already_applied = true;
    194     }
    195   }
    196   // TODO(senj): check that install plan has at least one payload.
    197   if (!payload_)
    198     payload_ = &install_plan_.payloads[0];
    199 
    200   LOG(INFO) << "Marking new slot as unbootable";
    201   if (!boot_control_->MarkSlotUnbootable(install_plan_.target_slot)) {
    202     LOG(WARNING) << "Unable to mark new slot "
    203                  << BootControlInterface::SlotName(install_plan_.target_slot)
    204                  << ". Proceeding with the update anyway.";
    205   }
    206 
    207   StartDownloading();
    208 }
    209 
    210 void DownloadAction::StartDownloading() {
    211   download_active_ = true;
    212   http_fetcher_->ClearRanges();
    213   if (install_plan_.is_resume &&
    214       payload_ == &install_plan_.payloads[resume_payload_index_]) {
    215     // Resuming an update so fetch the update manifest metadata first.
    216     int64_t manifest_metadata_size = 0;
    217     int64_t manifest_signature_size = 0;
    218     prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
    219     prefs_->GetInt64(kPrefsManifestSignatureSize, &manifest_signature_size);
    220     http_fetcher_->AddRange(base_offset_,
    221                             manifest_metadata_size + manifest_signature_size);
    222     // If there're remaining unprocessed data blobs, fetch them. Be careful not
    223     // to request data beyond the end of the payload to avoid 416 HTTP response
    224     // error codes.
    225     int64_t next_data_offset = 0;
    226     prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
    227     uint64_t resume_offset =
    228         manifest_metadata_size + manifest_signature_size + next_data_offset;
    229     if (!payload_->size) {
    230       http_fetcher_->AddRange(base_offset_ + resume_offset);
    231     } else if (resume_offset < payload_->size) {
    232       http_fetcher_->AddRange(base_offset_ + resume_offset,
    233                               payload_->size - resume_offset);
    234     }
    235   } else {
    236     if (payload_->size) {
    237       http_fetcher_->AddRange(base_offset_, payload_->size);
    238     } else {
    239       // If no payload size is passed we assume we read until the end of the
    240       // stream.
    241       http_fetcher_->AddRange(base_offset_);
    242     }
    243   }
    244 
    245   if (writer_ && writer_ != delta_performer_.get()) {
    246     LOG(INFO) << "Using writer for test.";
    247   } else {
    248     delta_performer_.reset(new DeltaPerformer(prefs_,
    249                                               boot_control_,
    250                                               hardware_,
    251                                               delegate_,
    252                                               &install_plan_,
    253                                               payload_,
    254                                               is_interactive_));
    255     writer_ = delta_performer_.get();
    256   }
    257   if (system_state_ != nullptr) {
    258     const PayloadStateInterface* payload_state = system_state_->payload_state();
    259     string file_id = utils::CalculateP2PFileId(payload_->hash, payload_->size);
    260     if (payload_state->GetUsingP2PForSharing()) {
    261       // If we're sharing the update, store the file_id to convey
    262       // that we should write to the file.
    263       p2p_file_id_ = file_id;
    264       LOG(INFO) << "p2p file id: " << p2p_file_id_;
    265     } else {
    266       // Even if we're not sharing the update, it could be that
    267       // there's a partial file from a previous attempt with the same
    268       // hash. If this is the case, we NEED to clean it up otherwise
    269       // we're essentially timing out other peers downloading from us
    270       // (since we're never going to complete the file).
    271       FilePath path = system_state_->p2p_manager()->FileGetPath(file_id);
    272       if (!path.empty()) {
    273         if (unlink(path.value().c_str()) != 0) {
    274           PLOG(ERROR) << "Error deleting p2p file " << path.value();
    275         } else {
    276           LOG(INFO) << "Deleting partial p2p file " << path.value()
    277                     << " since we're not using p2p to share.";
    278         }
    279       }
    280     }
    281 
    282     // Tweak timeouts on the HTTP fetcher if we're downloading from a
    283     // local peer.
    284     if (payload_state->GetUsingP2PForDownloading() &&
    285         payload_state->GetP2PUrl() == install_plan_.download_url) {
    286       LOG(INFO) << "Tweaking HTTP fetcher since we're downloading via p2p";
    287       http_fetcher_->set_low_speed_limit(kDownloadP2PLowSpeedLimitBps,
    288                                          kDownloadP2PLowSpeedTimeSeconds);
    289       http_fetcher_->set_max_retry_count(kDownloadP2PMaxRetryCount);
    290       http_fetcher_->set_connect_timeout(kDownloadP2PConnectTimeoutSeconds);
    291     }
    292   }
    293 
    294   http_fetcher_->BeginTransfer(install_plan_.download_url);
    295 }
    296 
    297 void DownloadAction::SuspendAction() {
    298   http_fetcher_->Pause();
    299 }
    300 
    301 void DownloadAction::ResumeAction() {
    302   http_fetcher_->Unpause();
    303 }
    304 
    305 void DownloadAction::TerminateProcessing() {
    306   if (writer_) {
    307     writer_->Close();
    308     writer_ = nullptr;
    309   }
    310   download_active_ = false;
    311   CloseP2PSharingFd(false);  // Keep p2p file.
    312   // Terminates the transfer. The action is terminated, if necessary, when the
    313   // TransferTerminated callback is received.
    314   http_fetcher_->TerminateTransfer();
    315 }
    316 
    317 void DownloadAction::SeekToOffset(off_t offset) {
    318   bytes_received_ = offset;
    319 }
    320 
    321 void DownloadAction::ReceivedBytes(HttpFetcher* fetcher,
    322                                    const void* bytes,
    323                                    size_t length) {
    324   // Note that bytes_received_ is the current offset.
    325   if (!p2p_file_id_.empty()) {
    326     WriteToP2PFile(bytes, length, bytes_received_);
    327   }
    328 
    329   bytes_received_ += length;
    330   uint64_t bytes_downloaded_total =
    331       bytes_received_previous_payloads_ + bytes_received_;
    332   if (delegate_ && download_active_) {
    333     delegate_->BytesReceived(length, bytes_downloaded_total, bytes_total_);
    334   }
    335   if (writer_ && !writer_->Write(bytes, length, &code_)) {
    336     if (code_ != ErrorCode::kSuccess) {
    337       LOG(ERROR) << "Error " << utils::ErrorCodeToString(code_) << " (" << code_
    338                  << ") in DeltaPerformer's Write method when "
    339                  << "processing the received payload -- Terminating processing";
    340     }
    341     // Delete p2p file, if applicable.
    342     if (!p2p_file_id_.empty())
    343       CloseP2PSharingFd(true);
    344     // Don't tell the action processor that the action is complete until we get
    345     // the TransferTerminated callback. Otherwise, this and the HTTP fetcher
    346     // objects may get destroyed before all callbacks are complete.
    347     TerminateProcessing();
    348     return;
    349   }
    350 
    351   // Call p2p_manager_->FileMakeVisible() when we've successfully
    352   // verified the manifest!
    353   if (!p2p_visible_ && system_state_ && delta_performer_.get() &&
    354       delta_performer_->IsManifestValid()) {
    355     LOG(INFO) << "Manifest has been validated. Making p2p file visible.";
    356     system_state_->p2p_manager()->FileMakeVisible(p2p_file_id_);
    357     p2p_visible_ = true;
    358   }
    359 }
    360 
    361 void DownloadAction::TransferComplete(HttpFetcher* fetcher, bool successful) {
    362   if (writer_) {
    363     LOG_IF(WARNING, writer_->Close() != 0) << "Error closing the writer.";
    364     if (delta_performer_.get() == writer_) {
    365       // no delta_performer_ in tests, so leave the test writer in place
    366       writer_ = nullptr;
    367     }
    368   }
    369   download_active_ = false;
    370   ErrorCode code =
    371       successful ? ErrorCode::kSuccess : ErrorCode::kDownloadTransferError;
    372   if (code == ErrorCode::kSuccess) {
    373     if (delta_performer_ && !payload_->already_applied)
    374       code = delta_performer_->VerifyPayload(payload_->hash, payload_->size);
    375     if (code == ErrorCode::kSuccess) {
    376       if (payload_ < &install_plan_.payloads.back() &&
    377                  system_state_->payload_state()->NextPayload()) {
    378         LOG(INFO) << "Incrementing to next payload";
    379         // No need to reset if this payload was already applied.
    380         if (delta_performer_ && !payload_->already_applied)
    381           DeltaPerformer::ResetUpdateProgress(prefs_, false);
    382         // Start downloading next payload.
    383         bytes_received_previous_payloads_ += payload_->size;
    384         payload_++;
    385         install_plan_.download_url =
    386             system_state_->payload_state()->GetCurrentUrl();
    387         StartDownloading();
    388         return;
    389       }
    390       // Log UpdateEngine.DownloadAction.* histograms to help diagnose
    391       // long-blocking oeprations.
    392       std::string histogram_output;
    393       base::StatisticsRecorder::WriteGraph(
    394           "UpdateEngine.DownloadAction.", &histogram_output);
    395       LOG(INFO) << histogram_output;
    396     } else {
    397       LOG(ERROR) << "Download of " << install_plan_.download_url
    398                  << " failed due to payload verification error.";
    399       // Delete p2p file, if applicable.
    400       if (!p2p_file_id_.empty())
    401         CloseP2PSharingFd(true);
    402     }
    403   }
    404 
    405   // Write the path to the output pipe if we're successful.
    406   if (code == ErrorCode::kSuccess && HasOutputPipe())
    407     SetOutputObject(install_plan_);
    408   processor_->ActionComplete(this, code);
    409 }
    410 
    411 void DownloadAction::TransferTerminated(HttpFetcher* fetcher) {
    412   if (code_ != ErrorCode::kSuccess) {
    413     processor_->ActionComplete(this, code_);
    414   } else if (payload_->already_applied) {
    415     LOG(INFO) << "TransferTerminated with ErrorCode::kSuccess when the current "
    416                  "payload has already applied, treating as TransferComplete.";
    417     TransferComplete(fetcher, true);
    418   }
    419 }
    420 
    421 }  // namespace chromeos_update_engine
    422