update_engine: Parse and supply EOL date for Chrome
From Omaha, the optional field |_eol_date| is to indicate the EOL of a
device. Chrome side will leverage these values to display a
notification. The value for |_eol_date| should be an integer value
indicating the days from Unix Epoch date.
If |_eol_date| does not exist in the Omaha response or have non-integer
values, the default will fallback to |kEolDateInvalid|.
BUG=chromium:998983
TEST=FEATURES="test" emerge-$B update_engine update_engine-client system_api
TEST=test_that -b $B $IP autoupdate_EOL
TEST=test_that -b $B $IP autoupdate_EOL.approaching_eol
TEST=test_that -b $B $IP autoupdate_EOL.future_eol
Cq-Depend:chromium:1783596, chromium:1811116
Change-Id: I2b1063873118ccf8fe22ba09a5961e27aa980c7b
Reviewed-on: https://chromium-review.googlesource.com/1783897
Tested-by: Jae Hoon Kim <kimjae@chromium.org>
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
diff --git a/client_library/client_dbus.cc b/client_library/client_dbus.cc
index e6aba92..d1d6cc0 100644
--- a/client_library/client_dbus.cc
+++ b/client_library/client_dbus.cc
@@ -56,6 +56,7 @@
out_status->status = static_cast<UpdateStatus>(status.current_operation());
out_status->is_enterprise_rollback = status.is_enterprise_rollback();
out_status->is_install = status.is_install();
+ out_status->eol_date = status.eol_date();
}
} // namespace
diff --git a/client_library/include/update_engine/update_status.h b/client_library/include/update_engine/update_status.h
index c877df6..c1d0968 100644
--- a/client_library/include/update_engine/update_status.h
+++ b/client_library/include/update_engine/update_status.h
@@ -88,6 +88,8 @@
bool is_enterprise_rollback;
// Indication of install for DLC(s).
bool is_install;
+ // The end-of-life date of the device in the number of days since Unix Epoch.
+ int64_t eol_date;
};
} // namespace update_engine
diff --git a/common/constants.cc b/common/constants.cc
index 87bdf91..64bdf0c 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -55,6 +55,7 @@
const char kPrefsOmahaCohort[] = "omaha-cohort";
const char kPrefsOmahaCohortHint[] = "omaha-cohort-hint";
const char kPrefsOmahaCohortName[] = "omaha-cohort-name";
+const char kPrefsOmahaEolDate[] = "omaha-eol-date";
const char kPrefsOmahaEolStatus[] = "omaha-eol-status";
const char kPrefsP2PEnabled[] = "p2p-enabled";
const char kPrefsP2PFirstAttemptTimestamp[] = "p2p-first-attempt-timestamp";
diff --git a/common/constants.h b/common/constants.h
index d95a56a..23c9003 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -56,6 +56,7 @@
extern const char kPrefsOmahaCohort[];
extern const char kPrefsOmahaCohortHint[];
extern const char kPrefsOmahaCohortName[];
+extern const char kPrefsOmahaEolDate[];
extern const char kPrefsOmahaEolStatus[];
extern const char kPrefsP2PEnabled[];
extern const char kPrefsP2PFirstAttemptTimestamp[];
diff --git a/dbus_service.cc b/dbus_service.cc
index b0dc076..065fe0c 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -49,6 +49,7 @@
out_status->set_new_size(ue_status.new_size_bytes);
out_status->set_is_enterprise_rollback(ue_status.is_enterprise_rollback);
out_status->set_is_install(ue_status.is_install);
+ out_status->set_eol_date(ue_status.eol_date);
}
} // namespace
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 4d86586..7ca4372 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -109,6 +109,7 @@
// updatecheck attributes (without the underscore prefix).
constexpr char kAttrEol[] = "eol";
+constexpr char kAttrEolDate[] = "eol_date";
constexpr char kAttrRollback[] = "rollback";
constexpr char kAttrFirmwareVersion[] = "firmware_version";
constexpr char kAttrKernelVersion[] = "kernel_version";
@@ -1317,14 +1318,29 @@
}
bool OmahaRequestAction::PersistEolStatus(const map<string, string>& attrs) {
- auto eol_attr = attrs.find(kAttrEol);
- if (eol_attr != attrs.end()) {
- return system_state_->prefs()->SetString(kPrefsOmahaEolStatus,
- eol_attr->second);
- } else if (system_state_->prefs()->Exists(kPrefsOmahaEolStatus)) {
- return system_state_->prefs()->Delete(kPrefsOmahaEolStatus);
+ bool ret = true;
+
+ // Set EOL date.
+ auto eol_date_attr = attrs.find(kAttrEolDate);
+ if (eol_date_attr == attrs.end()) {
+ system_state_->prefs()->Delete(kPrefsOmahaEolDate);
+ } else if (!system_state_->prefs()->SetString(kPrefsOmahaEolDate,
+ eol_date_attr->second)) {
+ LOG(ERROR) << "Setting EOL date failed.";
+ ret = false;
}
- return true;
+
+ // Set EOL.
+ auto eol_attr = attrs.find(kAttrEol);
+ if (eol_attr == attrs.end()) {
+ system_state_->prefs()->Delete(kPrefsOmahaEolStatus);
+ } else if (!system_state_->prefs()->SetString(kPrefsOmahaEolStatus,
+ eol_attr->second)) {
+ LOG(ERROR) << "Setting EOL status failed.";
+ ret = false;
+ }
+
+ return ret;
}
void OmahaRequestAction::ActionCompleted(ErrorCode code) {
diff --git a/omaha_request_action.h b/omaha_request_action.h
index 12d36d9..96f09e9 100644
--- a/omaha_request_action.h
+++ b/omaha_request_action.h
@@ -184,7 +184,9 @@
const std::string& new_value);
// Parse and persist the end-of-life status flag sent back in the updatecheck
- // tag attributes. The flag will be validated and stored in the Prefs.
+ // tag attributes. In addition, the optional end-of-life date flag will also
+ // be parsed and persisted. The flags will be validated and stored in the
+ // Prefs.
bool PersistEolStatus(const std::map<std::string, std::string>& attrs);
// If this is an update check request, initializes
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index 8008e00..94d5152 100644
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -53,6 +53,7 @@
#include "update_engine/mock_payload_state.h"
#include "update_engine/omaha_request_builder_xml.h"
#include "update_engine/omaha_request_params.h"
+#include "update_engine/omaha_utils.h"
#include "update_engine/update_manager/rollback_prefs.h"
using base::Time;
@@ -2809,4 +2810,65 @@
EXPECT_EQ(string::npos, post_str.find("requisition"));
}
+TEST_F(OmahaRequestActionTest, PersistEolDatesTest) {
+ tuc_params_.http_response =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ "protocol=\"3.0\"><app appid=\"foo\" status=\"ok\">"
+ "<ping status=\"ok\"/><updatecheck status=\"noupdate\" "
+ "_eol=\"supported\" _eol_date=\"200\" "
+ "_foo=\"bar\"/></app></response>";
+ tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
+ tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
+
+ ASSERT_TRUE(TestUpdateCheck());
+
+ string eol, eol_date;
+ EXPECT_TRUE(
+ fake_system_state_.prefs()->GetString(kPrefsOmahaEolStatus, &eol));
+ EXPECT_EQ(kEolStatusSupported, eol);
+ EXPECT_TRUE(
+ fake_system_state_.prefs()->GetString(kPrefsOmahaEolDate, &eol_date));
+ EXPECT_EQ("200", eol_date);
+}
+
+TEST_F(OmahaRequestActionTest, PersistEolMissingDatesTest) {
+ tuc_params_.http_response =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ "protocol=\"3.0\"><app appid=\"foo\" status=\"ok\">"
+ "<ping status=\"ok\"/><updatecheck status=\"noupdate\" "
+ "_eol=\"supported\" _foo=\"bar\"/></app></response>";
+ tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
+ tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
+
+ ASSERT_TRUE(TestUpdateCheck());
+
+ string eol, eol_date;
+ EXPECT_TRUE(
+ fake_system_state_.prefs()->GetString(kPrefsOmahaEolStatus, &eol));
+ EXPECT_EQ(kEolStatusSupported, eol);
+ EXPECT_FALSE(
+ fake_system_state_.prefs()->GetString(kPrefsOmahaEolDate, &eol_date));
+}
+
+TEST_F(OmahaRequestActionTest, PersistEolBadDatesTest) {
+ tuc_params_.http_response =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
+ "protocol=\"3.0\"><app appid=\"foo\" status=\"ok\">"
+ "<ping status=\"ok\"/><updatecheck status=\"noupdate\" "
+ "_eol=\"supported\" _eol_date=\"bad\" "
+ "foo=\"bar\"/></app></response>";
+ tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
+ tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
+
+ ASSERT_TRUE(TestUpdateCheck());
+
+ string eol, eol_date;
+ EXPECT_TRUE(
+ fake_system_state_.prefs()->GetString(kPrefsOmahaEolStatus, &eol));
+ EXPECT_EQ(kEolStatusSupported, eol);
+ EXPECT_TRUE(
+ fake_system_state_.prefs()->GetString(kPrefsOmahaEolDate, &eol_date));
+ EXPECT_EQ(kEolDateInvalid, StringToEolDate(eol_date));
+}
+
} // namespace chromeos_update_engine
diff --git a/omaha_utils.cc b/omaha_utils.cc
index 6bd7525..9fe425b 100644
--- a/omaha_utils.cc
+++ b/omaha_utils.cc
@@ -17,17 +17,15 @@
#include "update_engine/omaha_utils.h"
#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
namespace chromeos_update_engine {
-namespace {
-
-// The possible string values for the end-of-life status.
const char kEolStatusSupported[] = "supported";
const char kEolStatusSecurityOnly[] = "security-only";
const char kEolStatusEol[] = "eol";
-} // namespace
+const EolDate kEolDateInvalid = -9999;
const char* EolStatusToString(EolStatus eol_status) {
switch (eol_status) {
@@ -54,4 +52,21 @@
return EolStatus::kSupported;
}
+std::string EolDateToString(EolDate eol_date) {
+#if BASE_VER < 576279
+ return base::Int64ToString(eol_date);
+#else
+ return base::NumberToString(eol_date);
+#endif
+}
+
+EolDate StringToEolDate(const std::string& eol_date) {
+ EolDate date = kEolDateInvalid;
+ if (!base::StringToInt64(eol_date, &date)) {
+ LOG(WARNING) << "Invalid EOL date attribute: " << eol_date;
+ return kEolDateInvalid;
+ }
+ return date;
+}
+
} // namespace chromeos_update_engine
diff --git a/omaha_utils.h b/omaha_utils.h
index 8614540..128232a 100644
--- a/omaha_utils.h
+++ b/omaha_utils.h
@@ -21,6 +21,16 @@
namespace chromeos_update_engine {
+using EolDate = int64_t;
+
+// |EolDate| indicating an invalid end-of-life date.
+extern const EolDate kEolDateInvalid;
+
+// The possible string values for the end-of-life status.
+extern const char kEolStatusSupported[];
+extern const char kEolStatusSecurityOnly[];
+extern const char kEolStatusEol[];
+
// The end-of-life status of the device.
enum class EolStatus {
kSupported = 0,
@@ -35,6 +45,14 @@
// of an invalid string, the default "supported" value will be used instead.
EolStatus StringToEolStatus(const std::string& eol_status);
+// Returns the string representation of the |eol_date|.
+std::string EolDateToString(EolDate eol_date);
+
+// Converts the end-of-life date string to an EolDate numeric value. In case
+// of an invalid string, the default |kEolDateInvalid| value will be used
+// instead.
+EolDate StringToEolDate(const std::string& eol_date);
+
} // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_OMAHA_UTILS_H_
diff --git a/omaha_utils_unittest.cc b/omaha_utils_unittest.cc
index 8ceb76b..ccb9578 100644
--- a/omaha_utils_unittest.cc
+++ b/omaha_utils_unittest.cc
@@ -39,4 +39,17 @@
EXPECT_EQ(EolStatus::kSupported, StringToEolStatus("hello, world!"));
}
+TEST(OmahaUtilsTest, EolDateTest) {
+ // Supported values are converted back and forth properly.
+ const std::vector<EolDate> tests = {kEolDateInvalid, -1, 0, 1};
+ for (EolDate eol_date : tests) {
+ EXPECT_EQ(eol_date, StringToEolDate(EolDateToString(eol_date)))
+ << "The StringToEolDate() was " << EolDateToString(eol_date);
+ }
+
+ // Invalid values are assumed as "supported".
+ EXPECT_EQ(kEolDateInvalid, StringToEolDate(""));
+ EXPECT_EQ(kEolDateInvalid, StringToEolDate("hello, world!"));
+}
+
} // namespace chromeos_update_engine
diff --git a/update_attempter.cc b/update_attempter.cc
index 780ba7b..18e5088 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -54,6 +54,7 @@
#include "update_engine/omaha_request_action.h"
#include "update_engine/omaha_request_params.h"
#include "update_engine/omaha_response_handler_action.h"
+#include "update_engine/omaha_utils.h"
#include "update_engine/p2p_manager.h"
#include "update_engine/payload_consumer/download_action.h"
#include "update_engine/payload_consumer/filesystem_verifier_action.h"
@@ -1385,6 +1386,11 @@
out_status->is_enterprise_rollback =
install_plan_ && install_plan_->is_rollback;
out_status->is_install = is_install_;
+
+ string str_eol_date;
+ system_state_->prefs()->GetString(kPrefsOmahaEolDate, &str_eol_date);
+ out_status->eol_date = StringToEolDate(str_eol_date);
+
return true;
}
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 0e74353..4aff897 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -18,6 +18,7 @@
#include <stdint.h>
+#include <limits>
#include <memory>
#include <unordered_set>
@@ -48,6 +49,7 @@
#include "update_engine/mock_p2p_manager.h"
#include "update_engine/mock_payload_state.h"
#include "update_engine/mock_service_observer.h"
+#include "update_engine/omaha_utils.h"
#include "update_engine/payload_consumer/filesystem_verifier_action.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/payload_consumer/payload_constants.h"
@@ -2244,4 +2246,36 @@
EXPECT_TRUE(status.is_enterprise_rollback);
}
+TEST_F(UpdateAttempterTest, FutureEolTest) {
+ EolDate eol_date = std::numeric_limits<int64_t>::max();
+ EXPECT_CALL(*prefs_, GetString(kPrefsOmahaEolDate, _))
+ .WillOnce(
+ DoAll(SetArgPointee<1>(EolDateToString(eol_date)), Return(true)));
+
+ UpdateEngineStatus status;
+ attempter_.GetStatus(&status);
+ EXPECT_EQ(eol_date, status.eol_date);
+}
+
+TEST_F(UpdateAttempterTest, PastEolTest) {
+ EolDate eol_date = 1;
+ EXPECT_CALL(*prefs_, GetString(kPrefsOmahaEolDate, _))
+ .WillOnce(
+ DoAll(SetArgPointee<1>(EolDateToString(eol_date)), Return(true)));
+
+ UpdateEngineStatus status;
+ attempter_.GetStatus(&status);
+ EXPECT_EQ(eol_date, status.eol_date);
+}
+
+TEST_F(UpdateAttempterTest, FailedEolTest) {
+ EolDate eol_date = kEolDateInvalid;
+ EXPECT_CALL(*prefs_, GetString(kPrefsOmahaEolDate, _))
+ .WillOnce(Return(false));
+
+ UpdateEngineStatus status;
+ attempter_.GetStatus(&status);
+ EXPECT_EQ(eol_date, status.eol_date);
+}
+
} // namespace chromeos_update_engine
diff --git a/update_engine_client.cc b/update_engine_client.cc
index d78cee7..7b5c4df 100644
--- a/update_engine_client.cc
+++ b/update_engine_client.cc
@@ -42,6 +42,8 @@
#include "update_engine/update_status_utils.h"
using brillo::KeyValueStore;
+using chromeos_update_engine::EolDate;
+using chromeos_update_engine::EolDateToString;
using chromeos_update_engine::EolStatus;
using chromeos_update_engine::ErrorCode;
using chromeos_update_engine::UpdateEngineStatusToString;
@@ -569,16 +571,14 @@
}
if (FLAGS_eol_status) {
- int eol_status;
- if (!client_->GetEolStatus(&eol_status)) {
- LOG(ERROR) << "Error getting the end-of-life status.";
+ UpdateEngineStatus status;
+ if (!client_->GetStatus(&status)) {
+ LOG(ERROR) << "Error GetStatus() for getting EOL info.";
} else {
- EolStatus eol_status_code = static_cast<EolStatus>(eol_status);
+ EolDate eol_date_code = status.eol_date;
KeyValueStore eol_status_store;
- eol_status_store.SetString("EOL_STATUS",
- EolStatusToString(eol_status_code));
-
+ eol_status_store.SetString("EOL_DATE", EolDateToString(eol_date_code));
printf("%s", eol_status_store.SaveToString().c_str());
}
}