Parse and expose end-of-life flag.

Omaha update or noupdate response can include _key=value pairs with
arbitrary data. One of those key can be "_eol" with the one of the
values "supported", "security-only" or "eol" which notifies the device
the end-of-life status of the device with respect to updates. This
information is now exposed via GetEolStatus() to the client so it
can be properly displayed in the UI.

Bug: 27924505
TEST=Added unittest. Run `update_engine_client --eol_status` on link.

Change-Id: Icc15f25b4d0b19cc894f5afc52ac7c43c7818982
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 018f9aa..16338a8 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -77,6 +77,9 @@
 
 static const char* kOmahaUpdaterVersion = "0.1.0.0";
 
+// updatecheck attributes (without the underscore prefix).
+static const char* kEolAttr = "eol";
+
 namespace {
 
 // Returns an XML ping element attribute assignment with attribute
@@ -339,6 +342,7 @@
   bool app_cohortname_set = false;
   string updatecheck_status;
   string updatecheck_poll_interval;
+  map<string, string> updatecheck_attrs;
   string daystart_elapsed_days;
   string daystart_elapsed_seconds;
   vector<string> url_codebase;
@@ -386,6 +390,12 @@
     // There is only supposed to be a single <updatecheck> element.
     data->updatecheck_status = attrs["status"];
     data->updatecheck_poll_interval = attrs["PollInterval"];
+    // Omaha sends arbitrary key-value pairs as extra attributes starting with
+    // an underscore.
+    for (const auto& attr : attrs) {
+      if (!attr.first.empty() && attr.first[0] == '_')
+        data->updatecheck_attrs[attr.first.substr(1)] = attr.second;
+    }
   } else if (data->current_path == "/response/daystart") {
     // Get the install-date.
     data->daystart_elapsed_days = attrs["elapsed_days"];
@@ -748,6 +758,9 @@
   if (parser_data->app_cohortname_set)
     PersistCohortData(kPrefsOmahaCohortName, parser_data->app_cohortname);
 
+  // Parse the updatecheck attributes.
+  PersistEolStatus(parser_data->updatecheck_attrs);
+
   if (!ParseStatus(parser_data, output_object, completer))
     return false;
 
@@ -1384,6 +1397,17 @@
   return true;
 }
 
+bool OmahaRequestAction::PersistEolStatus(const map<string, string>& attrs) {
+  auto eol_attr = attrs.find(kEolAttr);
+  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);
+  }
+  return true;
+}
+
 void OmahaRequestAction::ActionCompleted(ErrorCode code) {
   // We only want to report this on "update check".
   if (ping_only_ || event_ != nullptr)