Relanding 'update_engine: Add XZ compression for CrOS'

This patch implements XZ compression for Chrome OS. It is only activated
for only delta payload at this point. The XZ compression is typically
slower than Bzip2 to compress, but faster to decompress. However, it
uses slightly higher memory in decompression. It compresses about 5%-10%
better than the current Bzip2.

BUG=chromium:758792
TEST=unittests pass; brillo_update_paylod {generate|verify} passes;

Change-Id: I2fd8f6af30449c779cd2abb061e42ab389913d93
Reviewed-on: https://chromium-review.googlesource.com/872125
Commit-Ready: Amin Hassani <ahassani@chromium.org>
Tested-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Sen Jiang <senj@chromium.org>
diff --git a/payload_generator/xz_chromeos.cc b/payload_generator/xz_chromeos.cc
index a8cda4e..2ff9458 100644
--- a/payload_generator/xz_chromeos.cc
+++ b/payload_generator/xz_chromeos.cc
@@ -16,13 +16,39 @@
 
 #include "update_engine/payload_generator/xz.h"
 
+#include <base/logging.h>
+#include <lzma.h>
+
 namespace chromeos_update_engine {
 
 void XzCompressInit() {}
 
 bool XzCompress(const brillo::Blob& in, brillo::Blob* out) {
-  // No Xz compressor implementation in Chrome OS delta_generator builds.
-  return false;
+  out->clear();
+  if (in.empty())
+    return true;
+
+  // Resize the output buffer to get enough memory for writing the compressed
+  // data.
+  out->resize(lzma_stream_buffer_bound(in.size()));
+
+  const uint32_t kLzmaPreset = 6;
+  size_t out_pos = 0;
+  int rc = lzma_easy_buffer_encode(kLzmaPreset,
+                                   LZMA_CHECK_NONE,  // We do not need CRC.
+                                   nullptr,
+                                   in.data(),
+                                   in.size(),
+                                   out->data(),
+                                   &out_pos,
+                                   out->size());
+  if (rc != LZMA_OK) {
+    LOG(ERROR) << "Failed to compress data to LZMA stream with return code: "
+               << rc;
+    return false;
+  }
+  out->resize(out_pos);
+  return true;
 }
 
 }  // namespace chromeos_update_engine