Copy a version of download action for ChromeOS

DownloadAction contains many cros specific stuff, such as p2p, system
state. Many of these cros bits are used in a fragile way in aosp. It's
better if we maintain two independent download actions.

Test: treehugger
Bug: 175042161
Change-Id: Iaaed269b3886a068bfcb4bcac12aca99b9cf6970
diff --git a/cros/download_action_chromeos.h b/cros/download_action_chromeos.h
new file mode 100644
index 0000000..068946a
--- /dev/null
+++ b/cros/download_action_chromeos.h
@@ -0,0 +1,174 @@
+//
+// Copyright (C) 2020 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.
+//
+
+#ifndef UPDATE_ENGINE_COMMON_DOWNLOAD_ACTION_CHROMEOS_H_
+#define UPDATE_ENGINE_COMMON_DOWNLOAD_ACTION_CHROMEOS_H_
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+
+#include "update_engine/common/action.h"
+#include "update_engine/common/boot_control_interface.h"
+#include "update_engine/common/download_action.h"
+#include "update_engine/common/http_fetcher.h"
+#include "update_engine/common/multi_range_http_fetcher.h"
+#include "update_engine/payload_consumer/delta_performer.h"
+#include "update_engine/payload_consumer/install_plan.h"
+
+// The Download Action downloads a specified url to disk. The url should point
+// to an update in a delta payload format. The payload will be piped into a
+// DeltaPerformer that will apply the delta to the disk.
+
+namespace chromeos_update_engine {
+
+class PrefsInterface;
+
+class DownloadActionChromeos : public InstallPlanAction,
+                               public HttpFetcherDelegate {
+ public:
+  static std::string StaticType() { return "DownloadActionChromeos"; }
+
+  // Takes ownership of the passed in HttpFetcher. Useful for testing.
+  // A good calling pattern is:
+  // DownloadActionChromeos(prefs, boot_contol, hardware, system_state,
+  //                new WhateverHttpFetcher, false);
+  DownloadActionChromeos(PrefsInterface* prefs,
+                         BootControlInterface* boot_control,
+                         HardwareInterface* hardware,
+                         HttpFetcher* http_fetcher,
+                         bool interactive);
+  ~DownloadActionChromeos() override;
+
+  // InstallPlanAction overrides.
+  void PerformAction() override;
+  void SuspendAction() override;
+  void ResumeAction() override;
+  void TerminateProcessing() override;
+  std::string Type() const override { return StaticType(); }
+
+  // Testing
+  void SetTestFileWriter(FileWriter* writer) { writer_ = writer; }
+
+  int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); }
+
+  // HttpFetcherDelegate methods (see http_fetcher.h)
+  bool ReceivedBytes(HttpFetcher* fetcher,
+                     const void* bytes,
+                     size_t length) override;
+  void SeekToOffset(off_t offset) override;
+  void TransferComplete(HttpFetcher* fetcher, bool successful) override;
+  void TransferTerminated(HttpFetcher* fetcher) override;
+
+  DownloadActionDelegate* delegate() const { return delegate_; }
+  void set_delegate(DownloadActionDelegate* delegate) { delegate_ = delegate; }
+
+  void set_base_offset(int64_t base_offset) { base_offset_ = base_offset; }
+
+  HttpFetcher* http_fetcher() { return http_fetcher_.get(); }
+
+  // Returns the p2p file id for the file being written or the empty
+  // string if we're not writing to a p2p file.
+  std::string p2p_file_id() { return p2p_file_id_; }
+
+ private:
+  // Closes the file descriptor for the p2p file being written and
+  // clears |p2p_file_id_| to indicate that we're no longer sharing
+  // the file. If |delete_p2p_file| is True, also deletes the file.
+  // If there is no p2p file descriptor, this method does nothing.
+  void CloseP2PSharingFd(bool delete_p2p_file);
+
+  // Starts sharing the p2p file. Must be called before
+  // WriteToP2PFile(). Returns True if this worked.
+  bool SetupP2PSharingFd();
+
+  // Writes |length| bytes of payload from |data| into |file_offset|
+  // of the p2p file. Also does validation checks; for example ensures we
+  // don't end up with a file with holes in it.
+  //
+  // This method does nothing if SetupP2PSharingFd() hasn't been
+  // called or if CloseP2PSharingFd() has been called.
+  void WriteToP2PFile(const void* data, size_t length, off_t file_offset);
+
+  // Attempt to load cached manifest data from prefs
+  // return true on success, false otherwise.
+  bool LoadCachedManifest(int64_t manifest_size);
+
+  // Start downloading the current payload using delta_performer.
+  void StartDownloading();
+
+  // Pointer to the current payload in install_plan_.payloads.
+  InstallPlan::Payload* payload_{nullptr};
+
+  PrefsInterface* prefs_;
+  BootControlInterface* boot_control_;
+  HardwareInterface* hardware_;
+
+  // Pointer to the MultiRangeHttpFetcher that does the http work.
+  std::unique_ptr<MultiRangeHttpFetcher> http_fetcher_;
+
+  // If |true|, the update is user initiated (vs. periodic update checks). Hence
+  // the |delta_performer_| can decide not to use O_DSYNC flag for faster
+  // update.
+  bool interactive_;
+
+  // The FileWriter that downloaded data should be written to. It will
+  // either point to *decompressing_file_writer_ or *delta_performer_.
+  FileWriter* writer_;
+
+  std::unique_ptr<DeltaPerformer> delta_performer_;
+
+  // Used by TransferTerminated to figure if this action terminated itself or
+  // was terminated by the action processor.
+  ErrorCode code_;
+
+  // For reporting status to outsiders
+  DownloadActionDelegate* delegate_;
+  uint64_t bytes_received_{0};  // per file/range
+  uint64_t bytes_received_previous_payloads_{0};
+  uint64_t bytes_total_{0};
+  bool download_active_{false};
+
+  // The file-id for the file we're sharing or the empty string
+  // if we're not using p2p to share.
+  std::string p2p_file_id_;
+
+  // The file descriptor for the p2p file used for caching the payload or -1
+  // if we're not using p2p to share.
+  int p2p_sharing_fd_;
+
+  // Set to |false| if p2p file is not visible.
+  bool p2p_visible_;
+
+  // Loaded from prefs before downloading any payload.
+  size_t resume_payload_index_{0};
+
+  // Offset of the payload in the download URL, used by UpdateAttempterAndroid.
+  int64_t base_offset_{0};
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadActionChromeos);
+};
+
+// We want to be sure that we're compiled with large file support on linux,
+// just in case we find ourselves downloading large images.
+static_assert(8 == sizeof(off_t), "off_t not 64 bit");
+
+}  // namespace chromeos_update_engine
+
+#endif  // UPDATE_ENGINE_COMMON_DOWNLOAD_ACTION_CHROMEOS_H_