Add EC and Firmware Versions to the Omaha Response.
This CL adds 2 additional utils methods to get the version for both the
fw and ec versions. I've added a unittest to verify these work and piped
in the values into the omaha response.
BUG=chromium:219871
TEST=Unittests + on device
Change-Id: Iadf70fff858988f52797d94bcdb062bb2482bbf3
Reviewed-on: https://gerrit.chromium.org/gerrit/49713
Commit-Queue: Chris Sosa <sosa@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Tested-by: Chris Sosa <sosa@chromium.org>
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index c28e0d6..15d3188 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -209,6 +209,8 @@
"board=\"" + XmlEncode(params->os_board()) + "\" " +
"hardware_class=\"" + XmlEncode(params->hwid()) + "\" " +
"delta_okay=\"" + delta_okay_str + "\" "
+ "fw_version=\"" + XmlEncode(params->fw_version()) + "\" " +
+ "ec_version=\"" + XmlEncode(params->ec_version()) + "\" " +
">\n" +
app_body +
" </app>\n";
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index 8ae951e..de5f49f 100644
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -53,6 +53,8 @@
"en-US",
"unittest",
"OEM MODEL 09235 7471",
+ "ChromeOSFirmware.1.0",
+ "0X0A1",
false, // delta okay
false, // interactive
"http://url",
@@ -827,6 +829,8 @@
"en-US",
"unittest_track<",
"<OEM MODEL>",
+ "ChromeOSFirmware.1.0",
+ "EC100",
false, // delta okay
false, // interactive
"http://url",
@@ -927,6 +931,10 @@
string::npos);
EXPECT_NE(post_str.find("hardware_class=\"OEM MODEL 09235 7471\""),
string::npos);
+ EXPECT_NE(post_str.find("fw_version=\"ChromeOSFirmware.1.0\""),
+ string::npos);
+ EXPECT_NE(post_str.find("ec_version=\"0X0A1\""),
+ string::npos);
}
@@ -954,6 +962,10 @@
string::npos);
EXPECT_NE(post_str.find("hardware_class=\"OEM MODEL 09235 7471\""),
string::npos);
+ EXPECT_NE(post_str.find("fw_version=\"ChromeOSFirmware.1.0\""),
+ string::npos);
+ EXPECT_NE(post_str.find("ec_version=\"0X0A1\""),
+ string::npos);
}
TEST(OmahaRequestActionTest, FormatSuccessEventOutputTest) {
@@ -1035,6 +1047,8 @@
"en-US",
"unittest_track",
"OEM MODEL REV 1234",
+ "ChromeOSFirmware.1.0",
+ "EC100",
delta_okay,
false, // interactive
"http://url",
@@ -1072,6 +1086,8 @@
"en-US",
"unittest_track",
"OEM MODEL REV 1234",
+ "ChromeOSFirmware.1.0",
+ "EC100",
true, // delta_okay
interactive,
"http://url",
diff --git a/omaha_request_params.cc b/omaha_request_params.cc
index f30e771..38262a9 100644
--- a/omaha_request_params.cc
+++ b/omaha_request_params.cc
@@ -13,6 +13,7 @@
#include <vector>
#include <base/file_util.h>
+#include <base/string_util.h>
#include <policy/device_policy.h>
#include "update_engine/constants.h"
@@ -78,6 +79,10 @@
stateful_override);
app_lang_ = "en-US";
hwid_ = utils::GetHardwareClass();
+ if (CollectECFWVersions()) {
+ fw_version_ = utils::GetFirmwareVersion();
+ ec_version_ = utils::GetECVersion(NULL);
+ }
if (current_channel_ == target_channel_) {
// deltas are only okay if the /.nodelta file does not exist. if we don't
@@ -107,6 +112,17 @@
return true;
}
+bool OmahaRequestParams::CollectECFWVersions() const {
+ return (
+ StartsWithASCII(hwid_, string("SAMS ALEX"), true) ||
+ StartsWithASCII(hwid_, string("BUTTERFLY"), true) ||
+ StartsWithASCII(hwid_, string("LUMPY"), true) ||
+ StartsWithASCII(hwid_, string("PARROT"), true) ||
+ StartsWithASCII(hwid_, string("SPRING"), true) ||
+ StartsWithASCII(hwid_, string("SNOW"), true)
+ );
+}
+
bool OmahaRequestParams::SetTargetChannel(const std::string& new_target_channel,
bool is_powerwash_allowed) {
LOG(INFO) << "SetTargetChannel called with " << new_target_channel
diff --git a/omaha_request_params.h b/omaha_request_params.h
index a3d08ce..7a85500 100644
--- a/omaha_request_params.h
+++ b/omaha_request_params.h
@@ -58,6 +58,8 @@
const std::string& in_app_lang,
const std::string& in_target_channel,
const std::string& in_hwid,
+ const std::string& in_fw_version,
+ const std::string& in_ec_version,
bool in_delta_okay,
bool in_interactive,
const std::string& in_update_url,
@@ -75,6 +77,8 @@
current_channel_(in_target_channel),
target_channel_(in_target_channel),
hwid_(in_hwid),
+ fw_version_(in_fw_version),
+ ec_version_(in_ec_version),
delta_okay_(in_delta_okay),
interactive_(in_interactive),
update_url_(in_update_url),
@@ -97,6 +101,8 @@
inline std::string canary_app_id() const { return canary_app_id_; }
inline std::string app_lang() const { return app_lang_; }
inline std::string hwid() const { return hwid_; }
+ inline std::string fw_version() const { return fw_version_; }
+ inline std::string ec_version() const { return ec_version_; }
inline void set_app_version(const std::string& version) {
app_version_ = version;
@@ -219,6 +225,7 @@
FRIEND_TEST(OmahaRequestParamsTest, ShouldLockDownTest);
FRIEND_TEST(OmahaRequestParamsTest, ChannelIndexTest);
FRIEND_TEST(OmahaRequestParamsTest, LsbPreserveTest);
+ FRIEND_TEST(OmahaRequestParamsTest, CollectECFWVersionsTest);
// Use a validator that is a non-static member of this class so that its
// inputs can be mocked in unit tests (e.g., build type for IsValidChannel).
@@ -239,6 +246,10 @@
// Returns the index of the given channel.
int GetChannelIndex(const std::string& channel) const;
+ // Returns True if we should store the fw/ec versions based on our hwid_.
+ // Compares hwid to a set of whitelisted prefixes.
+ bool CollectECFWVersions() const;
+
// These are individual helper methods to initialize the said properties from
// the LSB value.
void SetTargetChannelFromLsbValue();
@@ -300,6 +311,8 @@
std::string download_channel_;
std::string hwid_; // Hardware Qualification ID of the client
+ std::string fw_version_; // Chrome OS Firmware Version.
+ std::string ec_version_; // Chrome OS EC Version.
bool delta_okay_; // If this client can accept a delta
bool interactive_; // Whether this is a user-initiated update check
diff --git a/omaha_request_params_unittest.cc b/omaha_request_params_unittest.cc
index c12abcb..986aacb 100644
--- a/omaha_request_params_unittest.cc
+++ b/omaha_request_params_unittest.cc
@@ -577,4 +577,23 @@
EXPECT_EQ("r", out.GetAppId());
}
+TEST_F(OmahaRequestParamsTest, CollectECFWVersionsTest) {
+ ASSERT_TRUE(WriteFileString(
+ kTestDir + "/etc/lsb-release",
+ "CHROMEOS_RELEASE_APPID=r\n"
+ "CHROMEOS_CANARY_APPID=c\n"
+ "CHROMEOS_RELEASE_TRACK=stable-channel\n"));
+ MockSystemState mock_system_state;
+ OmahaRequestParams out(&mock_system_state);
+ out.hwid_ = string("STUMPY ALEX 12345");
+ EXPECT_FALSE(out.CollectECFWVersions());
+
+ out.hwid_ = string("SNOW 12345");
+ EXPECT_TRUE(out.CollectECFWVersions());
+
+ out.hwid_ = string("SAMS ALEX 12345");
+ EXPECT_TRUE(out.CollectECFWVersions());
+}
+
+
} // namespace chromeos_update_engine
diff --git a/utils.cc b/utils.cc
index a6d8d91..d24a61f 100644
--- a/utils.cc
+++ b/utils.cc
@@ -18,6 +18,7 @@
#include <unistd.h>
#include <algorithm>
+#include <vector>
#include <base/file_path.h>
#include <base/file_util.h>
@@ -25,6 +26,7 @@
#include <base/posix/eintr_wrapper.h>
#include <base/rand_util.h>
#include <base/string_number_conversions.h>
+#include <base/string_split.h>
#include <base/string_util.h>
#include <base/stringprintf.h>
#include <glib.h>
@@ -41,6 +43,7 @@
using base::Time;
using base::TimeDelta;
using std::min;
+using std::pair;
using std::string;
using std::vector;
@@ -82,23 +85,70 @@
return !dev_mode;
}
-string GetHardwareClass() {
- // TODO(petkov): Convert to a library call once a crossystem library is
- // available (crosbug.com/13291).
+string ReadValueFromCrosSystem(const string& key){
int exit_code = 0;
vector<string> cmd(1, "/usr/bin/crossystem");
- cmd.push_back("hwid");
+ cmd.push_back(key);
- string hwid;
- bool success = Subprocess::SynchronousExec(cmd, &exit_code, &hwid);
+ string return_value;
+ bool success = Subprocess::SynchronousExec(cmd, &exit_code, &return_value);
if (success && !exit_code) {
- TrimWhitespaceASCII(hwid, TRIM_ALL, &hwid);
- return hwid;
+ TrimWhitespaceASCII(return_value, TRIM_ALL, &return_value);
+ return return_value;
}
- LOG(ERROR) << "Unable to read HWID (" << exit_code << ") " << hwid;
+ LOG(ERROR) << "Unable to read " << key << " (" << exit_code << ") "
+ << return_value;
return "";
}
+string GetHardwareClass() {
+ return ReadValueFromCrosSystem("hwid");
+}
+
+string GetFirmwareVersion() {
+ return ReadValueFromCrosSystem("fwid");
+}
+
+string GetECVersion(const char* input_line) {
+ string line;
+ if(input_line == NULL) {
+ int exit_code = 0;
+ vector<string> cmd(1, "/usr/sbin/mosys");
+ cmd.push_back("-k");
+ cmd.push_back("ec");
+ cmd.push_back("info");
+
+ bool success = Subprocess::SynchronousExec(cmd, &exit_code, &line);
+ if (!success || exit_code) {
+ LOG(ERROR) << "Unable to read ec info from mosys (" << exit_code << ")";
+ return "";
+ }
+ } else {
+ line = input_line;
+ }
+
+ TrimWhitespaceASCII(line, TRIM_ALL, &line);
+
+ // At this point we want to conver the format key=value pair from mosys to
+ // a vector of key value pairs.
+ vector<pair<string, string> > kv_pairs;
+ if (base::SplitStringIntoKeyValuePairs(line, '=', ' ', &kv_pairs)) {
+ for (vector<pair<string, string> >::iterator it = kv_pairs.begin();
+ it != kv_pairs.end(); ++it) {
+ // Finally match against the fw_verion which may have quotes.
+ if (it->first == "fw_version") {
+ string output;
+ // Trim any quotes.
+ TrimString(it->second, "\"", &output);
+ return output;
+ }
+ }
+ }
+ LOG(ERROR) << "Unable to parse fwid from ec info.";
+ return "";
+}
+
+
bool WriteFile(const char* path, const char* data, int data_len) {
DirectFileWriter writer;
TEST_AND_RETURN_FALSE_ERRNO(0 == writer.Open(path,
diff --git a/utils.h b/utils.h
index bc645d2..5193845 100644
--- a/utils.h
+++ b/utils.h
@@ -38,6 +38,16 @@
// Returns the HWID or an empty string on error.
std::string GetHardwareClass();
+// Returns the firmware version or an empty string if the system is not running
+// chrome os firmware.
+std::string GetFirmwareVersion();
+
+// Returns the ec version or an empty string if the system is not running a
+// custom chrome os ec. If input_line is not NULL, reads from this line,
+// otherwise polls the system for the input line. input_line should contain
+// fw_version=value.
+std::string GetECVersion(const char* input_line);
+
// Writes the data passed to path. The file at path will be overwritten if it
// exists. Returns true on success, false otherwise.
bool WriteFile(const char* path, const char* data, int data_len);
diff --git a/utils_unittest.cc b/utils_unittest.cc
index 3d2feaa..4d9dea4 100644
--- a/utils_unittest.cc
+++ b/utils_unittest.cc
@@ -37,6 +37,21 @@
EXPECT_TRUE(utils::IsNormalBootMode());
}
+TEST(UtilsTest, CanParseECVersion) {
+ // Chroot won't have an ec version.
+ EXPECT_EQ("", utils::GetECVersion(NULL));
+
+ // Should be able to parse and valid key value line.
+ EXPECT_EQ("12345", utils::GetECVersion("fw_version=12345"));
+ EXPECT_EQ("123456", utils::GetECVersion("b=1231a fw_version=123456 a=fasd2"));
+ EXPECT_EQ("12345", utils::GetECVersion("fw_version=12345"));
+ EXPECT_EQ("00VFA616", utils::GetECVersion(
+ "vendor=\"sam\" fw_version=\"00VFA616\""));
+
+ // For invalid entries, should return the empty string.
+ EXPECT_EQ("", utils::GetECVersion("b=1231a fw_version a=fasd2"));
+}
+
TEST(UtilsTest, NormalizePathTest) {
EXPECT_EQ("", utils::NormalizePath("", false));
EXPECT_EQ("", utils::NormalizePath("", true));