Generate SHA-1 build ID for host-generated *.oat files (1/2).

For host-generated *.oat files, generate a SHA-1 build ID based on the
file content and write it to .note.gnu.build-id ELF section.  This
should allow various developer tools like profilers correlate the data
captured for files like boot.oat on the device with the corresponding
known version of the file during an offline analysis.

Test: Verified that boot.oat contains the build ID section now (with
      this change and https://android-review.googlesource.com/#/c/275630
      applied)
Test: Added ElfWriterTest::CheckBuildIdPresent test.
Test: make test-art-host
Bug: 31292208
Change-Id: Ie5e89da2ef87e34c27c0237ab34ddc7d2dc0aa3b
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 36cd232..0d6575c 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -16,6 +16,7 @@
 
 #include "elf_writer_quick.h"
 
+#include <openssl/sha.h>
 #include <unordered_map>
 #include <unordered_set>
 
@@ -126,6 +127,8 @@
   std::unique_ptr<DebugInfoTask> debug_info_task_;
   std::unique_ptr<ThreadPool> debug_info_thread_pool_;
 
+  void ComputeFileBuildId(uint8_t (*build_id)[ElfBuilder<ElfTypes>::kBuildIdLen]);
+
   DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
 };
 
@@ -167,6 +170,9 @@
 template <typename ElfTypes>
 void ElfWriterQuick<ElfTypes>::Start() {
   builder_->Start();
+  if (compiler_options_->GetGenerateBuildId()) {
+    builder_->WriteBuildIdSection();
+  }
 }
 
 template <typename ElfTypes>
@@ -275,11 +281,36 @@
 template <typename ElfTypes>
 bool ElfWriterQuick<ElfTypes>::End() {
   builder_->End();
-
+  if (compiler_options_->GetGenerateBuildId()) {
+    uint8_t build_id[ElfBuilder<ElfTypes>::kBuildIdLen];
+    ComputeFileBuildId(&build_id);
+    builder_->WriteBuildId(build_id);
+  }
   return builder_->Good();
 }
 
 template <typename ElfTypes>
+void ElfWriterQuick<ElfTypes>::ComputeFileBuildId(
+    uint8_t (*build_id)[ElfBuilder<ElfTypes>::kBuildIdLen]) {
+  constexpr int kBufSize = 8192;
+  std::vector<char> buffer(kBufSize);
+  int64_t offset = 0;
+  SHA_CTX ctx;
+  SHA1_Init(&ctx);
+  while (true) {
+    int64_t bytes_read = elf_file_->Read(buffer.data(), kBufSize, offset);
+    CHECK_GE(bytes_read, 0);
+    if (bytes_read == 0) {
+      // End of file.
+      break;
+    }
+    SHA1_Update(&ctx, buffer.data(), bytes_read);
+    offset += bytes_read;
+  }
+  SHA1_Final(*build_id, &ctx);
+}
+
+template <typename ElfTypes>
 OutputStream* ElfWriterQuick<ElfTypes>::GetStream() {
   return builder_->GetStream();
 }