diff options
author | 2021-07-07 08:28:31 +0100 | |
---|---|---|
committer | 2021-07-08 14:37:36 +0000 | |
commit | 79f874d287cb314dcf3fb8a78122d4296e91bd42 (patch) | |
tree | 7f2c9bd81b107e4acda51dcd7a133153980961de | |
parent | 4f623272bdf76d0308af4e45a71fb5a728d4f0f1 (diff) |
odrefresh: add support for lastUpdateMillis as part of version check
This is to support samegrade updates for module evaluation.
Bug: 192647837
Test: atest art_standalone_odrefresh_tests
Test: atest odsign_e2e_tests
Change-Id: Ied43ebdcc4b2ec57e337e709970fab948cf5f992
-rw-r--r-- | odrefresh/CacheInfo.xsd | 2 | ||||
-rw-r--r-- | odrefresh/odr_compilation_log.cc | 33 | ||||
-rw-r--r-- | odrefresh/odr_compilation_log.h | 13 | ||||
-rw-r--r-- | odrefresh/odr_compilation_log_test.cc | 231 | ||||
-rw-r--r-- | odrefresh/odr_metrics.h | 13 | ||||
-rw-r--r-- | odrefresh/odrefresh.cc | 33 | ||||
-rw-r--r-- | odrefresh/schema/current.txt | 2 |
7 files changed, 271 insertions, 56 deletions
diff --git a/odrefresh/CacheInfo.xsd b/odrefresh/CacheInfo.xsd index a0c00af00f..b58453a9d8 100644 --- a/odrefresh/CacheInfo.xsd +++ b/odrefresh/CacheInfo.xsd @@ -38,6 +38,8 @@ <xs:attribute name="versionCode" type="xs:long" use="required" /> <!-- Module versionName for the active ART APEX from `/apex/apex-info-list.xml`. --> <xs:attribute name="versionName" type="xs:string" use="required" /> + <!-- Module lastUpdateMillis for the active ART APEX from `/apex/apex-info-list.xml`. --> + <xs:attribute name="lastUpdateMillis" type="xs:long" use="required" /> </xs:complexType> <!-- Components of the `DEX2OATBOOTCLASSPATH`. --> diff --git a/odrefresh/odr_compilation_log.cc b/odrefresh/odr_compilation_log.cc index 55432f4357..37804a2385 100644 --- a/odrefresh/odr_compilation_log.cc +++ b/odrefresh/odr_compilation_log.cc @@ -41,7 +41,9 @@ std::istream& operator>>(std::istream& is, OdrCompilationLogEntry& entry) { auto saved_exceptions = is.exceptions(); is.exceptions(std::ios_base::iostate {}); + // Write log entry. NB update OdrCompilationLog::kLogVersion if changing the format here. is >> entry.apex_version >> std::ws; + is >> entry.last_update_millis >> std::ws; is >> entry.trigger >> std::ws; is >> entry.when >> std::ws; is >> entry.exit_code >> std::ws; @@ -59,6 +61,7 @@ std::ostream& operator<<(std::ostream& os, const OdrCompilationLogEntry& entry) os.exceptions(std::ios_base::iostate {}); os << entry.apex_version << kSpace; + os << entry.last_update_millis << kSpace; os << entry.trigger << kSpace; os << entry.when << kSpace; os << entry.exit_code << std::endl; @@ -69,8 +72,8 @@ std::ostream& operator<<(std::ostream& os, const OdrCompilationLogEntry& entry) } bool operator==(const OdrCompilationLogEntry& lhs, const OdrCompilationLogEntry& rhs) { - return lhs.apex_version == rhs.apex_version && lhs.trigger == rhs.trigger && - lhs.when == rhs.when && lhs.exit_code == rhs.exit_code; + return lhs.apex_version == rhs.apex_version && lhs.last_update_millis == rhs.last_update_millis && + lhs.trigger == rhs.trigger && lhs.when == rhs.when && lhs.exit_code == rhs.exit_code; } bool operator!=(const OdrCompilationLogEntry& lhs, const OdrCompilationLogEntry& rhs) { @@ -98,6 +101,12 @@ bool OdrCompilationLog::Read() { return false; } + std::string log_version; + ifs >> log_version >> std::ws; + if (log_version != kLogVersion) { + return false; + } + while (!ifs.eof()) { OdrCompilationLogEntry entry; ifs >> entry; @@ -117,6 +126,7 @@ bool OdrCompilationLog::Write() const { return false; } + ofs << kLogVersion << std::endl; for (const auto& entry : entries_) { ofs << entry; if (ofs.fail()) { @@ -148,23 +158,29 @@ const OdrCompilationLogEntry* OdrCompilationLog::Peek(size_t index) const { } void OdrCompilationLog::Log(int64_t apex_version, + int64_t last_update_millis, OdrMetrics::Trigger trigger, ExitCode compilation_result) { time_t now; time(&now); - Log(apex_version, trigger, now, compilation_result); + Log(apex_version, last_update_millis, trigger, now, compilation_result); } void OdrCompilationLog::Log(int64_t apex_version, + int64_t last_update_millis, OdrMetrics::Trigger trigger, time_t when, ExitCode compilation_result) { - entries_.push_back(OdrCompilationLogEntry{ - apex_version, static_cast<int32_t>(trigger), when, static_cast<int32_t>(compilation_result)}); + entries_.push_back(OdrCompilationLogEntry{apex_version, + last_update_millis, + static_cast<int32_t>(trigger), + when, + static_cast<int32_t>(compilation_result)}); Truncate(); } bool OdrCompilationLog::ShouldAttemptCompile(int64_t apex_version, + int64_t last_update_millis, OdrMetrics::Trigger trigger, time_t now) const { if (entries_.size() == 0) { @@ -173,7 +189,12 @@ bool OdrCompilationLog::ShouldAttemptCompile(int64_t apex_version, } if (apex_version != entries_.back().apex_version) { - // There is a new ART APEX, we should use compile right away. + // There is a new ART APEX, we should compile right away. + return true; + } + + if (last_update_millis != entries_.back().last_update_millis) { + // There is a samegrade ART APEX update, we should compile right away. return true; } diff --git a/odrefresh/odr_compilation_log.h b/odrefresh/odr_compilation_log.h index 6f13c97db1..894079c3f9 100644 --- a/odrefresh/odr_compilation_log.h +++ b/odrefresh/odr_compilation_log.h @@ -32,6 +32,7 @@ namespace odrefresh { // OdrCompilationLogEntry represents the result of a compilation attempt by odrefresh. struct OdrCompilationLogEntry { int64_t apex_version; + int64_t last_update_millis; int32_t trigger; time_t when; int32_t exit_code; @@ -53,6 +54,11 @@ class OdrCompilationLog { // directory is only used by odrefresh whereas the ART apexdata directory is also used by odsign // and others which may lead to the deletion (or rollback) of the log file. static constexpr const char* kCompilationLogFile = "/data/misc/odrefresh/compilation-log.txt"; + + // Version string that appears on the first line of the compilation log. + static constexpr const char kLogVersion[] = "CompilationLog/1.0"; + + // Number of log entries in the compilation log. static constexpr const size_t kMaxLoggedEntries = 4; explicit OdrCompilationLog(const char* compilation_log_path = kCompilationLogFile); @@ -60,6 +66,7 @@ class OdrCompilationLog { // Applies policy to compilation log to determine whether to recompile. bool ShouldAttemptCompile(int64_t apex_version, + int64_t last_update_millis, OdrMetrics::Trigger trigger, time_t now = 0) const; @@ -69,9 +76,13 @@ class OdrCompilationLog { // Returns the entry at position `index` or nullptr if `index` is out of bounds. const OdrCompilationLogEntry* Peek(size_t index) const; - void Log(int64_t apex_version, OdrMetrics::Trigger trigger, ExitCode compilation_result); + void Log(int64_t apex_version, + int64_t last_update_millis, + OdrMetrics::Trigger trigger, + ExitCode compilation_result); void Log(int64_t apex_version, + int64_t last_update_millis, OdrMetrics::Trigger trigger, time_t when, ExitCode compilation_result); diff --git a/odrefresh/odr_compilation_log_test.cc b/odrefresh/odr_compilation_log_test.cc index c5c95559c4..d99b4d9eaf 100644 --- a/odrefresh/odr_compilation_log_test.cc +++ b/odrefresh/odr_compilation_log_test.cc @@ -28,8 +28,8 @@ #include <string> #include <vector> +#include "android-base/file.h" #include "base/common_art_test.h" - #include "odrefresh/odrefresh.h" #include "odr_metrics.h" @@ -41,28 +41,31 @@ const time_t kSecondsPerDay = 86'400; class OdrCompilationLogTest : public CommonArtTest {}; TEST(OdrCompilationLogEntry, Equality) { - OdrCompilationLogEntry a{1, 2, 3, 4}; - - ASSERT_EQ(a, (OdrCompilationLogEntry{1, 2, 3, 4})); - ASSERT_NE(a, (OdrCompilationLogEntry{9, 2, 3, 4})); - ASSERT_NE(a, (OdrCompilationLogEntry{1, 9, 3, 4})); - ASSERT_NE(a, (OdrCompilationLogEntry{1, 2, 9, 4})); - ASSERT_NE(a, (OdrCompilationLogEntry{2, 2, 3, 9})); + OdrCompilationLogEntry a{1, 2, 3, 4, 5}; + + ASSERT_EQ(a, (OdrCompilationLogEntry{1, 2, 3, 4, 5})); + ASSERT_NE(a, (OdrCompilationLogEntry{9, 2, 3, 4, 5})); + ASSERT_NE(a, (OdrCompilationLogEntry{1, 9, 3, 4, 5})); + ASSERT_NE(a, (OdrCompilationLogEntry{1, 2, 9, 4, 5})); + ASSERT_NE(a, (OdrCompilationLogEntry{2, 2, 3, 9, 5})); + ASSERT_NE(a, (OdrCompilationLogEntry{2, 2, 3, 5, 9})); } TEST(OdrCompilationLogEntry, InputOutput) { const OdrCompilationLogEntry entries[] = { - {1, 2, 3, 4}, + {1, 2, 3, 4, 5}, {std::numeric_limits<int64_t>::min(), + std::numeric_limits<int64_t>::min(), std::numeric_limits<int32_t>::min(), std::numeric_limits<time_t>::min(), std::numeric_limits<int32_t>::min()}, {std::numeric_limits<int64_t>::max(), + std::numeric_limits<int64_t>::max(), std::numeric_limits<int32_t>::max(), std::numeric_limits<time_t>::max(), std::numeric_limits<int32_t>::max()}, - {0, 0, 0, 0}, - {0x7fedcba9'87654321, 0x12345678, 0x2346789, 0x76543210} + {0, 0, 0, 0, 0}, + {0x7fedcba9'87654321, 0x5a5a5a5a'5a5a5a5a, 0x12345678, 0x2346789, 0x76543210} }; for (const auto& entry : entries) { std::stringstream ss; @@ -86,12 +89,12 @@ TEST(OdrCompilationLogEntry, TruncatedInput) { TEST(OdrCompilationLogEntry, ReadMultiple) { std::stringstream ss; - ss << "1 2 3 4\n5 6 7 8\n"; + ss << "0 1 2 3 4\n5 6 7 8 9\n"; OdrCompilationLogEntry entry0, entry1; ss >> entry0 >> entry1; - ASSERT_EQ(entry0, (OdrCompilationLogEntry{1, 2, 3, 4})); - ASSERT_EQ(entry1, (OdrCompilationLogEntry{5, 6, 7, 8})); + ASSERT_EQ(entry0, (OdrCompilationLogEntry{0, 1, 2, 3, 4})); + ASSERT_EQ(entry1, (OdrCompilationLogEntry{5, 6, 7, 8, 9})); ASSERT_FALSE(ss.fail()); ASSERT_FALSE(ss.bad()); @@ -100,14 +103,24 @@ TEST(OdrCompilationLogEntry, ReadMultiple) { TEST(OdrCompilationLog, ShouldAttemptCompile) { OdrCompilationLog ocl(/*compilation_log_path=*/nullptr); - ASSERT_TRUE(ocl.ShouldAttemptCompile(1, OdrMetrics::Trigger::kMissingArtifacts, 0)); + ASSERT_TRUE(ocl.ShouldAttemptCompile( + /*apex_version=*/1, /*last_update_millis=*/762, OdrMetrics::Trigger::kMissingArtifacts, 0)); ocl.Log( - /*apex_version=*/1, OdrMetrics::Trigger::kApexVersionMismatch, ExitCode::kCompilationSuccess); - ASSERT_TRUE(ocl.ShouldAttemptCompile(2, OdrMetrics::Trigger::kApexVersionMismatch)); - ASSERT_FALSE(ocl.ShouldAttemptCompile(1, OdrMetrics::Trigger::kApexVersionMismatch)); - ASSERT_TRUE(ocl.ShouldAttemptCompile(1, OdrMetrics::Trigger::kDexFilesChanged)); - ASSERT_FALSE(ocl.ShouldAttemptCompile(1, OdrMetrics::Trigger::kUnknown)); + /*apex_version=*/1, + /*last_update_millis=*/762, + OdrMetrics::Trigger::kApexVersionMismatch, + ExitCode::kCompilationSuccess); + ASSERT_TRUE(ocl.ShouldAttemptCompile( + /*apex_version=*/2, /*last_update_millis=*/762, OdrMetrics::Trigger::kApexVersionMismatch)); + ASSERT_TRUE(ocl.ShouldAttemptCompile( + /*apex_version=*/1, /*last_update_millis=*/10000, OdrMetrics::Trigger::kApexVersionMismatch)); + ASSERT_FALSE(ocl.ShouldAttemptCompile( + /*apex_version=*/1, /*last_update_millis=*/762, OdrMetrics::Trigger::kApexVersionMismatch)); + ASSERT_TRUE(ocl.ShouldAttemptCompile( + /*apex_version=*/1, /*last_update_millis=*/762, OdrMetrics::Trigger::kDexFilesChanged)); + ASSERT_FALSE(ocl.ShouldAttemptCompile( + /*apex_version=*/1, /*last_update_millis=*/762, OdrMetrics::Trigger::kUnknown)); } TEST(OdrCompilationLog, BackOffNoHistory) { @@ -117,63 +130,81 @@ TEST(OdrCompilationLog, BackOffNoHistory) { OdrCompilationLog ocl(/*compilation_log_path=*/nullptr); ASSERT_TRUE(ocl.ShouldAttemptCompile( - /*apex_version=*/1, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + /*apex_version=*/1, + /*last_update_millis=*/0, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time)); // Start log ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); ASSERT_FALSE(ocl.ShouldAttemptCompile( - /*apex_version=*/1, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + /*apex_version=*/1, + /*last_update_millis=*/0, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time)); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay / 2)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay)); // Add one more log entry ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 2 * kSecondsPerDay)); // One more. ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 3 * kSecondsPerDay)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 4 * kSecondsPerDay)); // And one for the road. ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 7 * kSecondsPerDay)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 8 * kSecondsPerDay)); } @@ -186,31 +217,40 @@ TEST(OdrCompilationLog, BackOffHappyHistory) { // Start log with a successful entry. ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationSuccess); ASSERT_FALSE(ocl.ShouldAttemptCompile( - /*apex_version=*/1, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + /*apex_version=*/1, + /*last_update_millis=*/0, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time)); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay / 4)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay / 2)); - // Add a log entry for a failed compilation. + // Add a log entry for a failed compilation. ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay / 2)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay)); } @@ -219,18 +259,19 @@ TEST_F(OdrCompilationLogTest, LogNumberOfEntriesAndPeek) { OdrCompilationLog ocl(/*compilation_log_path=*/nullptr); std::vector<OdrCompilationLogEntry> entries = { - { 0, 1, 2, 3 }, - { 1, 2, 3, 4 }, - { 2, 3, 4, 5 }, - { 3, 4, 5, 6 }, - { 4, 5, 6, 7 }, - { 5, 6, 7, 8 }, - { 6, 7, 8, 9 } + { 0, 1, 2, 3, 4 }, + { 1, 2, 3, 4, 5 }, + { 2, 3, 4, 5, 6 }, + { 3, 4, 5, 6, 7 }, + { 4, 5, 6, 7, 8 }, + { 5, 6, 7, 8, 9 }, + { 6, 7, 8, 9, 10 } }; for (size_t i = 0; i < entries.size(); ++i) { OdrCompilationLogEntry& e = entries[i]; ocl.Log(e.apex_version, + e.last_update_millis, static_cast<OdrMetrics::Trigger>(e.trigger), e.when, static_cast<ExitCode>(e.exit_code)); @@ -251,13 +292,13 @@ TEST_F(OdrCompilationLogTest, LogNumberOfEntriesAndPeek) { TEST_F(OdrCompilationLogTest, LogReadWrite) { std::vector<OdrCompilationLogEntry> entries = { - { 0, 1, 2, 3 }, - { 1, 2, 3, 4 }, - { 2, 3, 4, 5 }, - { 3, 4, 5, 6 }, - { 4, 5, 6, 7 }, - { 5, 6, 7, 8 }, - { 6, 7, 8, 9 } + { 0, 1, 2, 3, 4 }, + { 1, 2, 3, 4, 5 }, + { 2, 3, 4, 5, 6 }, + { 3, 4, 5, 6, 7 }, + { 4, 5, 6, 7, 8 }, + { 5, 6, 7, 8, 9 }, + { 6, 7, 8, 9, 10 } }; ScratchFile scratch_file; @@ -268,6 +309,7 @@ TEST_F(OdrCompilationLogTest, LogReadWrite) { OdrCompilationLog ocl(scratch_file.GetFilename().c_str()); OdrCompilationLogEntry& e = entries[i]; ocl.Log(e.apex_version, + e.last_update_millis, static_cast<OdrMetrics::Trigger>(e.trigger), e.when, static_cast<ExitCode>(e.exit_code)); @@ -303,7 +345,10 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { OdrCompilationLog ocl(log_path); ASSERT_TRUE(ocl.ShouldAttemptCompile( - /*apex_version=*/1, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + /*apex_version=*/1, + /*last_update_millis=*/0, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time)); } { @@ -311,6 +356,7 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { // Start log ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); @@ -319,13 +365,18 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { { OdrCompilationLog ocl(log_path); ASSERT_FALSE(ocl.ShouldAttemptCompile( - /*apex_version=*/1, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + /*apex_version=*/1, + /*last_update_millis=*/0, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time)); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay / 2)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay)); } @@ -334,6 +385,7 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { // Add one more log entry OdrCompilationLog ocl(log_path); ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); @@ -344,10 +396,12 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + kSecondsPerDay)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 2 * kSecondsPerDay)); } @@ -356,19 +410,22 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { // One more log entry. OdrCompilationLog ocl(log_path); ocl.Log(/*apex_version=*/1, - OdrMetrics::Trigger::kApexVersionMismatch, - start_time, - ExitCode::kCompilationFailed); + /*last_update_millis=*/0, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time, + ExitCode::kCompilationFailed); } { OdrCompilationLog ocl(log_path); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 3 * kSecondsPerDay)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 4 * kSecondsPerDay)); } @@ -377,6 +434,7 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { // And one for the road. OdrCompilationLog ocl(log_path); ocl.Log(/*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time, ExitCode::kCompilationFailed); @@ -386,14 +444,101 @@ TEST_F(OdrCompilationLogTest, BackoffBasedOnLog) { OdrCompilationLog ocl(log_path); ASSERT_FALSE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 7 * kSecondsPerDay)); ASSERT_TRUE(ocl.ShouldAttemptCompile( /*apex_version=*/1, + /*last_update_millis=*/0, OdrMetrics::Trigger::kApexVersionMismatch, start_time + 8 * kSecondsPerDay)); } } +TEST(OdrCompilationLog, LastUpdateMillisChangeTriggersCompilation) { + time_t start_time; + time(&start_time); + + OdrCompilationLog ocl(/*compilation_log_path=*/nullptr); + + for (int64_t last_update_millis = 0; last_update_millis < 10000; last_update_millis += 1000) { + static const int64_t kApexVersion = 19999; + ASSERT_TRUE(ocl.ShouldAttemptCompile( + kApexVersion, last_update_millis, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + ocl.Log(kApexVersion, + last_update_millis, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time, + ExitCode::kCompilationSuccess); + ASSERT_FALSE(ocl.ShouldAttemptCompile(kApexVersion, + last_update_millis, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time + 1)); + } +} + +TEST(OdrCompilationLog, ApexVersionChangeTriggersCompilation) { + time_t start_time; + time(&start_time); + + OdrCompilationLog ocl(/*compilation_log_path=*/nullptr); + + for (int64_t apex_version = 0; apex_version < 10000; apex_version += 1000) { + static const int64_t kLastUpdateMillis = 777; + ASSERT_TRUE(ocl.ShouldAttemptCompile(apex_version, + kLastUpdateMillis, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time + 8 * kSecondsPerDay)); + ocl.Log(apex_version, + kLastUpdateMillis, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time, + ExitCode::kCompilationSuccess); + ASSERT_FALSE(ocl.ShouldAttemptCompile(apex_version, + kLastUpdateMillis, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time + 1)); + } +} + +TEST_F(OdrCompilationLogTest, NewLogVersionTriggersCompilation) { + static const int64_t kApexVersion = 1066; + static const int64_t kLastUpdateMillis = 777; + time_t start_time; + time(&start_time); + + ScratchFile scratch_file; + scratch_file.Close(); + + // Generate a compilation log. + { + OdrCompilationLog ocl(scratch_file.GetFilename().c_str()); + for (size_t i = 0; i < OdrCompilationLog::kMaxLoggedEntries; ++i) { + ocl.Log(kApexVersion, + kLastUpdateMillis, + OdrMetrics::Trigger::kApexVersionMismatch, + start_time, + ExitCode::kCompilationSuccess); + ASSERT_FALSE(ocl.ShouldAttemptCompile( + kApexVersion, kLastUpdateMillis, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + } + } + + // Replace version string in the compilation log. + std::string log_text; + ASSERT_TRUE(android::base::ReadFileToString(scratch_file.GetFilename(), &log_text)); + std::string new_log_version = std::string(OdrCompilationLog::kLogVersion) + "a"; + log_text.replace(0, new_log_version.size() - 1, new_log_version); + ASSERT_TRUE(android::base::WriteStringToFile(log_text, scratch_file.GetFilename())); + + // Read log with updated version entry, check it is treated as out-of-date. + { + OdrCompilationLog ocl(scratch_file.GetFilename().c_str()); + ASSERT_TRUE(ocl.ShouldAttemptCompile( + kApexVersion, kLastUpdateMillis, OdrMetrics::Trigger::kApexVersionMismatch, start_time)); + ASSERT_EQ(0u, ocl.NumberOfEntries()); + } +} + } // namespace odrefresh } // namespace art diff --git a/odrefresh/odr_metrics.h b/odrefresh/odr_metrics.h index 5ff9df2fcf..cd80beffc5 100644 --- a/odrefresh/odr_metrics.h +++ b/odrefresh/odr_metrics.h @@ -75,7 +75,7 @@ class OdrMetrics final { ~OdrMetrics(); // Gets the ART APEX that metrics are being collected on behalf of. - int64_t GetApexVersion() const { + int64_t GetArtApexVersion() const { return art_apex_version_; } @@ -84,6 +84,16 @@ class OdrMetrics final { art_apex_version_ = version; } + // Gets the ART APEX last update time in milliseconds. + int64_t GetArtApexLastUpdateMillis() const { + return art_apex_last_update_millis_; + } + + // Sets the ART APEX last update time in milliseconds. + void SetArtApexLastUpdateMillis(int64_t last_update_millis) { + art_apex_last_update_millis_ = last_update_millis; + } + // Gets the trigger for metrics collection. The trigger is the reason why odrefresh considers // compilation necessary. Trigger GetTrigger() const { @@ -122,6 +132,7 @@ class OdrMetrics final { const std::string metrics_file_; int64_t art_apex_version_ = 0; + int64_t art_apex_last_update_millis_ = 0; std::optional<Trigger> trigger_ = {}; // metrics are only logged if compilation is triggered. Stage stage_ = Stage::kUnknown; Status status_ = Status::kUnknown; diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc index 4cb15b94ae..7ecbe061bb 100644 --- a/odrefresh/odrefresh.cc +++ b/odrefresh/odrefresh.cc @@ -360,7 +360,10 @@ class OnDeviceRefresh final { LOG(ERROR) << "Could not update " << QuotePath(cache_info_filename_) << " : no ART Apex info"; return {}; } - return art_apex::ArtModuleInfo{info->getVersionCode(), info->getVersionName()}; + // The lastUpdateMillis is an addition to ApexInfoList.xsd to support samegrade installs. + int64_t last_update_millis = info->hasLastUpdateMillis() ? info->getLastUpdateMillis() : 0; + return art_apex::ArtModuleInfo{ + info->getVersionCode(), info->getVersionName(), last_update_millis}; } bool CheckComponents(const std::vector<art_apex::Component>& expected_components, @@ -530,9 +533,12 @@ class OnDeviceRefresh final { return cleanup_return(ExitCode::kCompilationRequired); } - // Record ART Apex version for metrics reporting. + // Record ART APEX version for metrics reporting. metrics.SetArtApexVersion(current_info->getVersionCode()); + // Record ART APEX last update milliseconds (used in compilation log). + metrics.SetArtApexLastUpdateMillis(current_info->getLastUpdateMillis()); + // Check whether the current cache ART module info differs from the current ART module info. // Always check APEX version. const auto cached_info = cache_info->getFirstArtModuleInfo(); @@ -546,13 +552,25 @@ class OnDeviceRefresh final { } if (cached_info->getVersionName() != current_info->getVersionName()) { - LOG(INFO) << "ART APEX version code mismatch (" + LOG(INFO) << "ART APEX version name mismatch (" << cached_info->getVersionName() << " != " << current_info->getVersionName() << ")."; metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch); return cleanup_return(ExitCode::kCompilationRequired); } + // Check lastUpdateMillis for samegrade installs. If `cached_info` is missing lastUpdateMillis + // then it is not current with the schema used by this binary so treat it as a samegrade + // update. Otherwise check whether the lastUpdateMillis changed. + if (!cached_info->hasLastUpdateMillis() || + cached_info->getLastUpdateMillis() != current_info->getLastUpdateMillis()) { + LOG(INFO) << "ART APEX last update time mismatch (" + << cached_info->getLastUpdateMillis() + << " != " << current_info->getLastUpdateMillis() << ")."; + metrics.SetTrigger(OdrMetrics::Trigger::kApexVersionMismatch); + return cleanup_return(ExitCode::kCompilationRequired); + } + // Check boot class components. // // This checks the size and checksums of odrefresh compilable files on the DEX2OATBOOTCLASSPATH @@ -1548,11 +1566,16 @@ class OnDeviceRefresh final { return exit_code; } OdrCompilationLog compilation_log; - if (!compilation_log.ShouldAttemptCompile(metrics.GetApexVersion(), metrics.GetTrigger())) { + if (!compilation_log.ShouldAttemptCompile(metrics.GetArtApexVersion(), + metrics.GetArtApexLastUpdateMillis(), + metrics.GetTrigger())) { return ExitCode::kOkay; } ExitCode compile_result = odr.Compile(metrics, /*force_compile=*/false); - compilation_log.Log(metrics.GetApexVersion(), metrics.GetTrigger(), compile_result); + compilation_log.Log(metrics.GetArtApexVersion(), + metrics.GetArtApexLastUpdateMillis(), + metrics.GetTrigger(), + compile_result); return compile_result; } else if (action == "--force-compile") { return odr.Compile(metrics, /*force_compile=*/true); diff --git a/odrefresh/schema/current.txt b/odrefresh/schema/current.txt index ae10712060..e6933f6f4c 100644 --- a/odrefresh/schema/current.txt +++ b/odrefresh/schema/current.txt @@ -3,8 +3,10 @@ package com.android.art { public class ArtModuleInfo { ctor public ArtModuleInfo(); + method public long getLastUpdateMillis(); method public long getVersionCode(); method public String getVersionName(); + method public void setLastUpdateMillis(long); method public void setVersionCode(long); method public void setVersionName(String); } |