Changed EncodeFEC to compute in incremental steps allowing OTA to be
paused during verity writes.

Test: tested incremental OTA on cuttelfish devices.

Bug: 243594791
Change-Id: I55179ab06fd22f10b246449e841d9b40204c6aaf
diff --git a/payload_consumer/verity_writer_android.h b/payload_consumer/verity_writer_android.h
index a6a4920..0d48803 100644
--- a/payload_consumer/verity_writer_android.h
+++ b/payload_consumer/verity_writer_android.h
@@ -21,11 +21,62 @@
 #include <string>
 
 #include <verity/hash_tree_builder.h>
+#include <base/logging.h>
+#include <base/posix/eintr_wrapper.h>
+#include <fec/ecc.h>
+extern "C" {
+#include <fec.h>
+}
 
 #include "payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/cached_file_descriptor.h"
 #include "update_engine/payload_consumer/verity_writer_interface.h"
 
 namespace chromeos_update_engine {
+enum class EncodeFECStep {
+  kInitFDStep,
+  kEncodeRoundStep,
+  kWriteStep,
+  kComplete
+};
+class IncrementalEncodeFEC {
+ public:
+  IncrementalEncodeFEC()
+      : rs_char_(nullptr, &free_rs_char), cache_fd_(nullptr, 1 * (1 << 20)) {}
+  // Initialize all member variables needed to performe FEC Computation
+  bool Init(const uint64_t _data_offset,
+            const uint64_t _data_size,
+            const uint64_t _fec_offset,
+            const uint64_t _fec_size,
+            const uint64_t _fec_roots,
+            const uint64_t _block_size,
+            const bool _verify_mode);
+  bool Compute(FileDescriptor* _read_fd, FileDescriptor* _write_fd);
+  void UpdateState();
+  bool Finished() const;
+  void Reset();
+
+ private:
+  brillo::Blob rs_blocks_;
+  brillo::Blob buffer_;
+  brillo::Blob fec_;
+  brillo::Blob fec_read_;
+  EncodeFECStep current_step_;
+  size_t current_round_;
+  size_t num_rounds_;
+  FileDescriptor* read_fd_;
+  FileDescriptor* write_fd_;
+  uint64_t data_offset_;
+  uint64_t data_size_;
+  uint64_t fec_offset_;
+  uint64_t fec_size_;
+  uint64_t fec_roots_;
+  uint64_t block_size_;
+  size_t rs_n_;
+  bool verify_mode_;
+  std::unique_ptr<void, decltype(&free_rs_char)> rs_char_;
+  UnownedCachedFileDescriptor cache_fd_;
+};
 
 class VerityWriterAndroid : public VerityWriterInterface {
  public:
@@ -35,7 +86,10 @@
   bool Init(const InstallPlan::Partition& partition);
   bool Update(uint64_t offset, const uint8_t* buffer, size_t size) override;
   bool Finalize(FileDescriptor* read_fd, FileDescriptor* write_fd) override;
+  bool IncrementalFinalize(FileDescriptor* read_fd,
+                           FileDescriptor* write_fd) override;
 
+  bool FECFinished() const override;
   // Read [data_offset : data_offset + data_size) from |path| and encode FEC
   // data, if |verify_mode|, then compare the encoded FEC with the one in
   // |path|, otherwise write the encoded FEC to |path|. We can't encode as we go
@@ -61,6 +115,9 @@
                         bool verify_mode);
 
  private:
+  // stores the state of EncodeFEC
+  IncrementalEncodeFEC encodeFEC_;
+  bool hash_tree_written_ = false;
   const InstallPlan::Partition* partition_ = nullptr;
 
   std::unique_ptr<HashTreeBuilder> hash_tree_builder_;