Add lz4hc image compression format

Smaller than lz4 and decompresses at the same speed. Compression is
a bit slower.

Example saves on old FB APK:
Uncompressed: 44748800 bytes
LZ4: 12443648 bytes
LZ4HC: 11055104 bytes

Generating the image slows down by ~1s per 20MB of image due to
slower compression. Decompression is about the same speed but there
should be a slight speedup since less data needs to be read from
flash.

Added test.

Bug: 22858531

Change-Id: Ib2704305b9bec5b0ba3b1e871f59f4eedff330b7
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 992af29..5763cec 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -289,6 +289,11 @@
   TestWriteRead(ImageHeader::kStorageModeLZ4);
 }
 
+TEST_F(ImageTest, WriteReadLZ4HC) {
+  TestWriteRead(ImageHeader::kStorageModeLZ4HC);
+}
+
+
 TEST_F(ImageTest, ImageHeaderIsValid) {
     uint32_t image_begin = ART_BASE_ADDRESS;
     uint32_t image_size_ = 16 * KB;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 5eff8f3..871435b 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -18,6 +18,7 @@
 
 #include <sys/stat.h>
 #include <lz4.h>
+#include <lz4hc.h>
 
 #include <memory>
 #include <numeric>
@@ -224,18 +225,28 @@
     char* image_data = reinterpret_cast<char*>(image_info.image_->Begin()) + sizeof(ImageHeader);
     size_t data_size;
     const char* image_data_to_write;
+    const uint64_t compress_start_time = NanoTime();
 
     CHECK_EQ(image_header->storage_mode_, image_storage_mode_);
     switch (image_storage_mode_) {
       case ImageHeader::kStorageModeLZ4: {
-        size_t compressed_max_size = LZ4_compressBound(image_data_size);
+        const size_t compressed_max_size = LZ4_compressBound(image_data_size);
         compressed_data.reset(new char[compressed_max_size]);
         data_size = LZ4_compress(
             reinterpret_cast<char*>(image_info.image_->Begin()) + sizeof(ImageHeader),
             &compressed_data[0],
             image_data_size);
-        image_data_to_write = &compressed_data[0];
-        VLOG(compiler) << "Compressed from " << image_data_size << " to " << data_size;
+
+        break;
+      }
+      case ImageHeader::kStorageModeLZ4HC: {
+        // Bound is same as non HC.
+        const size_t compressed_max_size = LZ4_compressBound(image_data_size);
+        compressed_data.reset(new char[compressed_max_size]);
+        data_size = LZ4_compressHC(
+            reinterpret_cast<char*>(image_info.image_->Begin()) + sizeof(ImageHeader),
+            &compressed_data[0],
+            image_data_size);
         break;
       }
       case ImageHeader::kStorageModeUncompressed: {
@@ -249,6 +260,12 @@
       }
     }
 
+    if (compressed_data != nullptr) {
+      image_data_to_write = &compressed_data[0];
+      VLOG(compiler) << "Compressed from " << image_data_size << " to " << data_size << " in "
+                     << PrettyDuration(NanoTime() - compress_start_time);
+    }
+
     // Write header first, as uncompressed.
     image_header->data_size_ = data_size;
     if (!image_file->WriteFully(image_info.image_->Begin(), sizeof(ImageHeader))) {