Add --compilation-reason option to dex2oat

The compilation reason is an optional metadata specifying the reason for
compiling the apk. If specified, the string will be embedded verbatim in
the key value store of the oat file.

This will allow a more precise performance monitoring based on the actual
reason for compilation (e.g. install time vs background dexopt time).

Test: dex2oat_test
Bug: 73102540
Change-Id: I73c7fcc73e37a695f1684d9e282c7cc5be3030f8
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 7948bca..4ac8e6a 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1731,4 +1731,54 @@
   EXPECT_NE(std::string::npos, output_.find("dex2oat took"));
 }
 
+TEST_F(Dex2oatTest, VerifyCompilationReason) {
+  std::string dex_location = GetScratchDir() + "/Dex2OatCompilationReason.jar";
+  std::string odex_location = GetOdexDir() + "/Dex2OatCompilationReason.odex";
+
+  // Test file doesn't matter.
+  Copy(GetDexSrc1(), dex_location);
+
+  GenerateOdexForTest(dex_location,
+                      odex_location,
+                      CompilerFilter::kVerify,
+                      { "--compilation-reason=install" },
+                      true);
+  std::string error_msg;
+  std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                   odex_location.c_str(),
+                                                   nullptr,
+                                                   nullptr,
+                                                   false,
+                                                   /*low_4gb*/false,
+                                                   dex_location.c_str(),
+                                                   &error_msg));
+  ASSERT_TRUE(odex_file != nullptr);
+  ASSERT_STREQ("install", odex_file->GetCompilationReason());
+}
+
+TEST_F(Dex2oatTest, VerifyNoCompilationReason) {
+  std::string dex_location = GetScratchDir() + "/Dex2OatNoCompilationReason.jar";
+  std::string odex_location = GetOdexDir() + "/Dex2OatNoCompilationReason.odex";
+
+  // Test file doesn't matter.
+  Copy(GetDexSrc1(), dex_location);
+
+  GenerateOdexForTest(dex_location,
+                      odex_location,
+                      CompilerFilter::kVerify,
+                      {},
+                      true);
+  std::string error_msg;
+  std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+                                                   odex_location.c_str(),
+                                                   nullptr,
+                                                   nullptr,
+                                                   false,
+                                                   /*low_4gb*/false,
+                                                   dex_location.c_str(),
+                                                   &error_msg));
+  ASSERT_TRUE(odex_file != nullptr);
+  ASSERT_EQ(nullptr, odex_file->GetCompilationReason());
+}
+
 }  // namespace art