update_engine: Merge remote-tracking branch 'cros/upstream' into cros/master
Done with:
git merge cros/upstream --commit -s recursive
- Added EC key support and its unittests.
- Resolved a conlict on error codes. Since Android versions are not
uploading any UMA metrics, I gave the priority to the Android version
Since they can't be changed.
- Changed the openssl functions to get1 version (from get0) version
because of a current issue with gale. Once the issue is resolved we
need to change them back.
- Some remaining styling issues fixed by clang-format
BUG=b:163153182
TEST=CQ passes
TEST=unittests
Change-Id: Ib95034422b92433ce26e28336bc4806b34910d38
diff --git a/BUILD.gn b/BUILD.gn
index b7de9fc..59aa004 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -44,6 +44,7 @@
":test_subprocess",
":update_engine-test_images",
":update_engine-testkeys",
+ ":update_engine-testkeys-ec",
":update_engine_test_libs",
":update_engine_unittests",
]
@@ -60,6 +61,7 @@
pkg_config("target_defaults") {
cflags_cc = [
"-fno-strict-aliasing",
+ "-std=gnu++17",
"-Wnon-virtual-dtor",
]
cflags = [
@@ -75,6 +77,7 @@
"__CHROMEOS__",
"_FILE_OFFSET_BITS=64",
"_POSIX_C_SOURCE=199309L",
+ "USE_CFM=${use.cfm}",
"USE_DBUS=${use.dbus}",
"USE_FEC=0",
"USE_HWID_OVERRIDE=${use.hwid_override}",
@@ -215,6 +218,7 @@
"payload_state.cc",
"power_manager_chromeos.cc",
"real_system_state.cc",
+ "requisition_util.cc",
"shill_proxy.cc",
"update_attempter.cc",
"update_boot_flags_action.cc",
@@ -256,7 +260,7 @@
"expat",
"libcurl",
"libdebugd-client",
- "libmetrics-${libbase_ver}",
+ "libmetrics",
"libpower_manager-client",
"libsession_manager-client",
"libshill-client",
@@ -416,10 +420,20 @@
openssl_pem_out_dir = "include/update_engine"
sources = [
"unittest_key.pem",
+ "unittest_key_RSA4096.pem",
"unittest_key2.pem",
]
}
+ genopenssl_key("update_engine-testkeys-ec") {
+ openssl_pem_in_dir = "."
+ openssl_pem_out_dir = "include/update_engine"
+ openssl_pem_algorithm = "ec"
+ sources = [
+ "unittest_key_EC.pem",
+ ]
+ }
+
# Unpacks sample images used for testing.
tar_bunzip2("update_engine-test_images") {
image_out_dir = "."
@@ -513,6 +527,7 @@
"payload_generator/squashfs_filesystem_unittest.cc",
"payload_generator/zip_unittest.cc",
"payload_state_unittest.cc",
+ "requisition_util_unittest.cc",
"testrunner.cc",
"update_attempter_unittest.cc",
"update_boot_flags_action_unittest.cc",
diff --git a/client_library/client_dbus.cc b/client_library/client_dbus.cc
index 8e9a7fd..caf7bef 100644
--- a/client_library/client_dbus.cc
+++ b/client_library/client_dbus.cc
@@ -17,6 +17,7 @@
#include "update_engine/client_library/client_dbus.h"
#include <base/message_loop/message_loop.h>
+#include <base/message_loop/message_loop_current.h>
#include <memory>
diff --git a/common/constants.cc b/common/constants.cc
index c85ba54..8883668 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -64,6 +64,8 @@
const char kPrefsP2PFirstAttemptTimestamp[] = "p2p-first-attempt-timestamp";
const char kPrefsP2PNumAttempts[] = "p2p-num-attempts";
const char kPrefsPayloadAttemptNumber[] = "payload-attempt-number";
+const char kPrefsTestUpdateCheckIntervalTimeout[] =
+ "test-update-check-interval-timeout";
// Keep |kPrefsPingActive| in sync with |kDlcMetadataFilePingActive| in
// dlcservice.
const char kPrefsPingActive[] = "active";
diff --git a/common/constants.h b/common/constants.h
index 7170201..3685102 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -67,6 +67,7 @@
extern const char kPrefsP2PFirstAttemptTimestamp[];
extern const char kPrefsP2PNumAttempts[];
extern const char kPrefsPayloadAttemptNumber[];
+extern const char kPrefsTestUpdateCheckIntervalTimeout[];
extern const char kPrefsPingActive[];
extern const char kPrefsPingLastActive[];
extern const char kPrefsPingLastRollcall[];
diff --git a/common/error_code.h b/common/error_code.h
index e473a05..7d9cfff 100644
--- a/common/error_code.h
+++ b/common/error_code.h
@@ -85,6 +85,7 @@
kUnresolvedHostRecovered = 59,
kNotEnoughSpace = 60,
kDeviceCorrupted = 61,
+ kPackageExcludedFromUpdate = 62,
// VERY IMPORTANT! When adding new error codes:
//
diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
index 64df24a..cda4c7e 100644
--- a/common/error_code_utils.cc
+++ b/common/error_code_utils.cc
@@ -171,6 +171,8 @@
return "ErrorCode::kNotEnoughSpace";
case ErrorCode::kDeviceCorrupted:
return "ErrorCode::kDeviceCorrupted";
+ case ErrorCode::kPackageExcludedFromUpdate:
+ return "ErrorCode::kPackageExcludedFromUpdate";
// Don't add a default case to let the compiler warn about newly added
// error codes which should be added here.
}
diff --git a/common/fake_boot_control.h b/common/fake_boot_control.h
index 5d8823a..98b93e6 100644
--- a/common/fake_boot_control.h
+++ b/common/fake_boot_control.h
@@ -116,7 +116,7 @@
is_bootable_[slot] = bootable;
}
- DynamicPartitionControlInterface* GetDynamicPartitionControl() {
+ DynamicPartitionControlInterface* GetDynamicPartitionControl() override {
return dynamic_partition_control_.get();
}
diff --git a/common/utils.cc b/common/utils.cc
index 5d76f3f..9e1e6c5 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -911,6 +911,25 @@
return true;
}
+bool GetVpdValue(string key, string* result) {
+ int exit_code = 0;
+ string value, error;
+ vector<string> cmd = {"vpd_get_value", key};
+ if (!chromeos_update_engine::Subprocess::SynchronousExec(
+ cmd, &exit_code, &value, &error) ||
+ exit_code) {
+ LOG(ERROR) << "Failed to get vpd key for " << value
+ << " with exit code: " << exit_code << " and error: " << error;
+ return false;
+ } else if (!error.empty()) {
+ LOG(INFO) << "vpd_get_value succeeded but with following errors: " << error;
+ }
+
+ base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
+ *result = value;
+ return true;
+}
+
bool GetBootId(string* boot_id) {
TEST_AND_RETURN_FALSE(
base::ReadFileToString(base::FilePath(kBootIdPath), boot_id));
diff --git a/common/utils.h b/common/utils.h
index 0a1dc0c..bcaed31 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -292,6 +292,10 @@
// reboot. Returns whether it succeeded getting the boot_id.
bool GetBootId(std::string* boot_id);
+// Gets a string value from the vpd for a given key using the `vpd_get_value`
+// shell command. Returns true on success.
+bool GetVpdValue(std::string key, std::string* result);
+
// This function gets the file path of the file pointed to by FileDiscriptor.
std::string GetFilePath(int fd);
diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
index 807e086..cce5e84 100644
--- a/hardware_chromeos.cc
+++ b/hardware_chromeos.cc
@@ -38,6 +38,9 @@
#include "update_engine/common/subprocess.h"
#include "update_engine/common/utils.h"
#include "update_engine/dbus_connection.h"
+#if USE_CFM
+#include "update_engine/requisition_util.h"
+#endif
using std::string;
using std::vector;
@@ -81,29 +84,6 @@
const char* kActivePingKey = "first_active_omaha_ping_sent";
-const char* kOemRequisitionKey = "oem_device_requisition";
-
-// Gets a string value from the vpd for a given key using the `vpd_get_value`
-// shell command. Returns true on success.
-int GetVpdValue(string key, string* result) {
- int exit_code = 0;
- string value, error;
- vector<string> cmd = {"vpd_get_value", key};
- if (!chromeos_update_engine::Subprocess::SynchronousExec(
- cmd, &exit_code, &value, &error) ||
- exit_code) {
- LOG(ERROR) << "Failed to get vpd key for " << value
- << " with exit code: " << exit_code << " and error: " << error;
- return false;
- } else if (!error.empty()) {
- LOG(INFO) << "vpd_get_value succeeded but with following errors: " << error;
- }
-
- base::TrimWhitespaceASCII(value, base::TRIM_ALL, &value);
- *result = value;
- return true;
-}
-
} // namespace
namespace chromeos_update_engine {
@@ -215,8 +195,12 @@
}
string HardwareChromeOS::GetDeviceRequisition() const {
- string requisition;
- return GetVpdValue(kOemRequisitionKey, &requisition) ? requisition : "";
+#if USE_CFM
+ const char* kLocalStatePath = "/home/chronos/Local State";
+ return ReadDeviceRequisition(base::FilePath(kLocalStatePath));
+#else
+ return "";
+#endif
}
int HardwareChromeOS::GetMinKernelKeyVersion() const {
@@ -341,7 +325,7 @@
bool HardwareChromeOS::GetFirstActiveOmahaPingSent() const {
string active_ping_str;
- if (!GetVpdValue(kActivePingKey, &active_ping_str)) {
+ if (!utils::GetVpdValue(kActivePingKey, &active_ping_str)) {
return false;
}
diff --git a/metrics_constants.h b/metrics_constants.h
index db21d90..679680c 100644
--- a/metrics_constants.h
+++ b/metrics_constants.h
@@ -106,7 +106,7 @@
kUpdateCanceled, // Update canceled by the user.
kUpdateSucceededNotActive, // Update succeeded but the new slot is not
// active.
-
+ kUpdateSkipped, // Current update skipped.
kNumConstants,
kUnset = -1
diff --git a/metrics_reporter_omaha.cc b/metrics_reporter_omaha.cc
index fb4e4ce..0cf0e59 100644
--- a/metrics_reporter_omaha.cc
+++ b/metrics_reporter_omaha.cc
@@ -146,8 +146,6 @@
void MetricsReporterOmaha::ReportDailyMetrics(base::TimeDelta os_age) {
string metric = metrics::kMetricDailyOSAgeDays;
- LOG(INFO) << "Uploading " << utils::FormatTimeDelta(os_age) << " for metric "
- << metric;
metrics_lib_->SendToUMA(metric,
static_cast<int>(os_age.InDays()),
0, // min: 0 days
@@ -168,20 +166,17 @@
metric = metrics::kMetricCheckResult;
value = static_cast<int>(result);
max_value = static_cast<int>(metrics::CheckResult::kNumConstants) - 1;
- LOG(INFO) << "Sending " << value << " for metric " << metric << " (enum)";
metrics_lib_->SendEnumToUMA(metric, value, max_value);
}
if (reaction != metrics::CheckReaction::kUnset) {
metric = metrics::kMetricCheckReaction;
value = static_cast<int>(reaction);
max_value = static_cast<int>(metrics::CheckReaction::kNumConstants) - 1;
- LOG(INFO) << "Sending " << value << " for metric " << metric << " (enum)";
metrics_lib_->SendEnumToUMA(metric, value, max_value);
}
if (download_error_code != metrics::DownloadErrorCode::kUnset) {
metric = metrics::kMetricCheckDownloadErrorCode;
value = static_cast<int>(download_error_code);
- LOG(INFO) << "Sending " << value << " for metric " << metric << " (sparse)";
metrics_lib_->SendSparseToUMA(metric, value);
}
@@ -191,8 +186,6 @@
kPrefsMetricsCheckLastReportingTime,
&time_since_last)) {
metric = metrics::kMetricCheckTimeSinceLastCheckMinutes;
- LOG(INFO) << "Sending " << utils::FormatTimeDelta(time_since_last)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
time_since_last.InMinutes(),
0, // min: 0 min
@@ -205,8 +198,6 @@
if (metrics_utils::MonotonicDurationHelper(
system_state, &uptime_since_last_storage, &uptime_since_last)) {
metric = metrics::kMetricCheckTimeSinceLastCheckUptimeMinutes;
- LOG(INFO) << "Sending " << utils::FormatTimeDelta(uptime_since_last)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
uptime_since_last.InMinutes(),
0, // min: 0 min
@@ -221,13 +212,9 @@
value = utils::VersionPrefix(target_version);
if (value != 0) {
metric = metrics::kMetricCheckTargetVersion;
- LOG(INFO) << "Sending " << value << " for metric " << metric
- << " (sparse)";
metrics_lib_->SendSparseToUMA(metric, value);
if (system_state->request_params()->rollback_allowed()) {
metric = metrics::kMetricCheckRollbackTargetVersion;
- LOG(INFO) << "Sending " << value << " for metric " << metric
- << " (sparse)";
metrics_lib_->SendSparseToUMA(metric, value);
}
}
@@ -239,8 +226,6 @@
metrics::AttemptResult attempt_result =
metrics::AttemptResult::kAbnormalTermination;
- LOG(INFO) << "Uploading " << static_cast<int>(attempt_result)
- << " for metric " << metric;
metrics_lib_->SendEnumToUMA(
metric,
static_cast<int>(attempt_result),
@@ -257,7 +242,6 @@
metrics::AttemptResult attempt_result,
ErrorCode internal_error_code) {
string metric = metrics::kMetricAttemptNumber;
- LOG(INFO) << "Uploading " << attempt_number << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
attempt_number,
0, // min: 0 attempts
@@ -265,13 +249,9 @@
50); // num_buckets
metric = metrics::kMetricAttemptPayloadType;
- LOG(INFO) << "Uploading " << utils::ToString(payload_type) << " for metric "
- << metric;
metrics_lib_->SendEnumToUMA(metric, payload_type, kNumPayloadTypes);
metric = metrics::kMetricAttemptDurationMinutes;
- LOG(INFO) << "Uploading " << utils::FormatTimeDelta(duration)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
duration.InMinutes(),
0, // min: 0 min
@@ -279,8 +259,6 @@
50); // num_buckets
metric = metrics::kMetricAttemptDurationUptimeMinutes;
- LOG(INFO) << "Uploading " << utils::FormatTimeDelta(duration_uptime)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
duration_uptime.InMinutes(),
0, // min: 0 min
@@ -289,7 +267,6 @@
metric = metrics::kMetricAttemptPayloadSizeMiB;
int64_t payload_size_mib = payload_size / kNumBytesInOneMiB;
- LOG(INFO) << "Uploading " << payload_size_mib << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
payload_size_mib,
0, // min: 0 MiB
@@ -297,8 +274,6 @@
50); // num_buckets
metric = metrics::kMetricAttemptResult;
- LOG(INFO) << "Uploading " << static_cast<int>(attempt_result)
- << " for metric " << metric;
metrics_lib_->SendEnumToUMA(
metric,
static_cast<int>(attempt_result),
@@ -314,8 +289,6 @@
kPrefsMetricsAttemptLastReportingTime,
&time_since_last)) {
metric = metrics::kMetricAttemptTimeSinceLastAttemptMinutes;
- LOG(INFO) << "Sending " << utils::FormatTimeDelta(time_since_last)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
time_since_last.InMinutes(),
0, // min: 0 min
@@ -328,8 +301,6 @@
if (metrics_utils::MonotonicDurationHelper(
system_state, &uptime_since_last_storage, &uptime_since_last)) {
metric = metrics::kMetricAttemptTimeSinceLastAttemptUptimeMinutes;
- LOG(INFO) << "Sending " << utils::FormatTimeDelta(uptime_since_last)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
uptime_since_last.InMinutes(),
0, // min: 0 min
@@ -347,8 +318,6 @@
string metric = metrics::kMetricAttemptPayloadBytesDownloadedMiB;
int64_t payload_bytes_downloaded_mib =
payload_bytes_downloaded / kNumBytesInOneMiB;
- LOG(INFO) << "Uploading " << payload_bytes_downloaded_mib << " for metric "
- << metric;
metrics_lib_->SendToUMA(metric,
payload_bytes_downloaded_mib,
0, // min: 0 MiB
@@ -357,8 +326,6 @@
metric = metrics::kMetricAttemptPayloadDownloadSpeedKBps;
int64_t payload_download_speed_kbps = payload_download_speed_bps / 1000;
- LOG(INFO) << "Uploading " << payload_download_speed_kbps << " for metric "
- << metric;
metrics_lib_->SendToUMA(metric,
payload_download_speed_kbps,
0, // min: 0 kB/s
@@ -366,20 +333,15 @@
50); // num_buckets
metric = metrics::kMetricAttemptDownloadSource;
- LOG(INFO) << "Uploading " << download_source << " for metric " << metric;
metrics_lib_->SendEnumToUMA(metric, download_source, kNumDownloadSources);
if (payload_download_error_code != metrics::DownloadErrorCode::kUnset) {
metric = metrics::kMetricAttemptDownloadErrorCode;
- LOG(INFO) << "Uploading " << static_cast<int>(payload_download_error_code)
- << " for metric " << metric << " (sparse)";
metrics_lib_->SendSparseToUMA(
metric, static_cast<int>(payload_download_error_code));
}
metric = metrics::kMetricAttemptConnectionType;
- LOG(INFO) << "Uploading " << static_cast<int>(connection_type)
- << " for metric " << metric;
metrics_lib_->SendEnumToUMA(
metric,
static_cast<int>(connection_type),
@@ -399,7 +361,6 @@
int url_switch_count) {
string metric = metrics::kMetricSuccessfulUpdatePayloadSizeMiB;
int64_t mbs = payload_size / kNumBytesInOneMiB;
- LOG(INFO) << "Uploading " << mbs << " (MiBs) for metric " << metric;
metrics_lib_->SendToUMA(metric,
mbs,
0, // min: 0 MiB
@@ -429,7 +390,6 @@
}
if (mbs > 0) {
- LOG(INFO) << "Uploading " << mbs << " (MiBs) for metric " << metric;
metrics_lib_->SendToUMA(metric,
mbs,
0, // min: 0 MiB
@@ -439,8 +399,6 @@
}
metric = metrics::kMetricSuccessfulUpdateDownloadSourcesUsed;
- LOG(INFO) << "Uploading 0x" << std::hex << download_sources_used
- << " (bit flags) for metric " << metric;
metrics_lib_->SendToUMA(metric,
download_sources_used,
0, // min
@@ -448,8 +406,6 @@
1 << kNumDownloadSources); // num_buckets
metric = metrics::kMetricSuccessfulUpdateDownloadOverheadPercentage;
- LOG(INFO) << "Uploading " << download_overhead_percentage << "% for metric "
- << metric;
metrics_lib_->SendToUMA(metric,
download_overhead_percentage,
0, // min: 0% overhead
@@ -457,8 +413,6 @@
50); // num_buckets
metric = metrics::kMetricSuccessfulUpdateUrlSwitchCount;
- LOG(INFO) << "Uploading " << url_switch_count << " (count) for metric "
- << metric;
metrics_lib_->SendToUMA(metric,
url_switch_count,
0, // min: 0 URL switches
@@ -466,8 +420,6 @@
50); // num_buckets
metric = metrics::kMetricSuccessfulUpdateTotalDurationMinutes;
- LOG(INFO) << "Uploading " << utils::FormatTimeDelta(total_duration)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
static_cast<int>(total_duration.InMinutes()),
0, // min: 0 min
@@ -475,8 +427,6 @@
50); // num_buckets
metric = metrics::kMetricSuccessfulUpdateTotalDurationUptimeMinutes;
- LOG(INFO) << "Uploading " << utils::FormatTimeDelta(total_duration_uptime)
- << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
static_cast<int>(total_duration_uptime.InMinutes()),
0, // min: 0 min
@@ -484,8 +434,6 @@
50); // num_buckets
metric = metrics::kMetricSuccessfulUpdateRebootCount;
- LOG(INFO) << "Uploading reboot count of " << reboot_count << " for metric "
- << metric;
metrics_lib_->SendToUMA(metric,
reboot_count,
0, // min: 0 reboots
@@ -494,8 +442,6 @@
metric = metrics::kMetricSuccessfulUpdatePayloadType;
metrics_lib_->SendEnumToUMA(metric, payload_type, kNumPayloadTypes);
- LOG(INFO) << "Uploading " << utils::ToString(payload_type) << " for metric "
- << metric;
metric = metrics::kMetricSuccessfulUpdateAttemptCount;
metrics_lib_->SendToUMA(metric,
@@ -503,11 +449,8 @@
1, // min: 1 attempt
50, // max: 50 attempts
50); // num_buckets
- LOG(INFO) << "Uploading " << attempt_count << " for metric " << metric;
metric = metrics::kMetricSuccessfulUpdateUpdatesAbandonedCount;
- LOG(INFO) << "Uploading " << updates_abandoned_count << " (count) for metric "
- << metric;
metrics_lib_->SendToUMA(metric,
updates_abandoned_count,
0, // min: 0 counts
@@ -519,7 +462,6 @@
metrics::RollbackResult result) {
string metric = metrics::kMetricRollbackResult;
int value = static_cast<int>(result);
- LOG(INFO) << "Sending " << value << " for metric " << metric << " (enum)";
metrics_lib_->SendEnumToUMA(
metric, value, static_cast<int>(metrics::RollbackResult::kNumConstants));
}
@@ -530,7 +472,6 @@
string metric = metrics::kMetricEnterpriseRollbackSuccess;
if (!success)
metric = metrics::kMetricEnterpriseRollbackFailure;
- LOG(INFO) << "Sending " << value << " for metric " << metric;
metrics_lib_->SendSparseToUMA(metric, value);
}
@@ -547,8 +488,6 @@
case ServerToCheck::kNone:
return;
}
- LOG(INFO) << "Uploading " << static_cast<int>(result) << " for metric "
- << metric;
metrics_lib_->SendEnumToUMA(
metric,
static_cast<int>(result),
@@ -562,9 +501,6 @@
1, // min value
50, // max value
kNumDefaultUmaBuckets);
-
- LOG(INFO) << "Uploading " << target_attempt << " (count) for metric "
- << metric;
}
void MetricsReporterOmaha::ReportTimeToReboot(int time_to_reboot_minutes) {
@@ -574,9 +510,6 @@
0, // min: 0 minute
30 * 24 * 60, // max: 1 month (approx)
kNumDefaultUmaBuckets);
-
- LOG(INFO) << "Uploading " << time_to_reboot_minutes << " for metric "
- << metric;
}
void MetricsReporterOmaha::ReportInstallDateProvisioningSource(int source,
@@ -588,7 +521,6 @@
void MetricsReporterOmaha::ReportInternalErrorCode(ErrorCode error_code) {
auto metric = metrics::kMetricAttemptInternalErrorCode;
- LOG(INFO) << "Uploading " << error_code << " for metric " << metric;
metrics_lib_->SendEnumToUMA(metric,
static_cast<int>(error_code),
static_cast<int>(ErrorCode::kUmaReportedMax));
@@ -600,18 +532,14 @@
bool kernel_max_rollforward_success) {
int value = kernel_min_version;
string metric = metrics::kMetricKernelMinVersion;
- LOG(INFO) << "Sending " << value << " for metric " << metric;
metrics_lib_->SendSparseToUMA(metric, value);
value = kernel_max_rollforward_version;
metric = metrics::kMetricKernelMaxRollforwardVersion;
- LOG(INFO) << "Sending " << value << " for metric " << metric;
metrics_lib_->SendSparseToUMA(metric, value);
bool bool_value = kernel_max_rollforward_success;
metric = metrics::kMetricKernelMaxRollforwardSetSuccess;
- LOG(INFO) << "Sending " << bool_value << " for metric " << metric
- << " (bool)";
metrics_lib_->SendBoolToUMA(metric, bool_value);
}
@@ -621,7 +549,6 @@
has_time_restriction_policy
? metrics::kMetricSuccessfulUpdateDurationFromSeenTimeRestrictedDays
: metrics::kMetricSuccessfulUpdateDurationFromSeenDays;
- LOG(INFO) << "Sending " << time_to_update_days << " for metric " << metric;
metrics_lib_->SendToUMA(metric,
time_to_update_days,
diff --git a/metrics_utils.cc b/metrics_utils.cc
index da3a2c3..2211a67 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -111,10 +111,6 @@
case ErrorCode::kDownloadInvalidMetadataSignature:
case ErrorCode::kOmahaResponseInvalid:
case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
- // TODO(deymo): The next two items belong in their own category; they
- // should not be counted as internal errors. b/27112092
- case ErrorCode::kOmahaUpdateDeferredPerPolicy:
- case ErrorCode::kNonCriticalUpdateInOOBE:
case ErrorCode::kOmahaErrorInHTTPResponse:
case ErrorCode::kDownloadMetadataSignatureMissingError:
case ErrorCode::kOmahaUpdateDeferredForBackoff:
@@ -124,8 +120,13 @@
case ErrorCode::kOmahaUpdateIgnoredOverCellular:
case ErrorCode::kNoUpdate:
case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
+ case ErrorCode::kPackageExcludedFromUpdate:
return metrics::AttemptResult::kInternalError;
+ case ErrorCode::kOmahaUpdateDeferredPerPolicy:
+ case ErrorCode::kNonCriticalUpdateInOOBE:
+ return metrics::AttemptResult::kUpdateSkipped;
+
// Special flags. These can't happen (we mask them out above) but
// the compiler doesn't know that. Just break out so we can warn and
// return |kInternalError|.
@@ -240,6 +241,7 @@
case ErrorCode::kVerityCalculationError:
case ErrorCode::kNotEnoughSpace:
case ErrorCode::kDeviceCorrupted:
+ case ErrorCode::kPackageExcludedFromUpdate:
break;
// Special flags. These can't happen (we mask them out above) but
diff --git a/mock_update_attempter.h b/mock_update_attempter.h
index ad34802..cc05648 100644
--- a/mock_update_attempter.h
+++ b/mock_update_attempter.h
@@ -30,16 +30,17 @@
public:
using UpdateAttempter::UpdateAttempter;
- MOCK_METHOD9(Update,
- void(const std::string& app_version,
- const std::string& omaha_url,
- const std::string& target_channel,
- const std::string& target_version_prefix,
- bool rollback_allowed,
- bool rollback_data_save_requested,
- int rollback_allowed_milestones,
- bool obey_proxies,
- bool interactive));
+ MOCK_METHOD10(Update,
+ void(const std::string& app_version,
+ const std::string& omaha_url,
+ const std::string& target_channel,
+ const std::string& lts_tag,
+ const std::string& target_version_prefix,
+ bool rollback_allowed,
+ bool rollback_data_save_requested,
+ int rollback_allowed_milestones,
+ bool obey_proxies,
+ bool interactive));
MOCK_METHOD1(GetStatus, bool(update_engine::UpdateEngineStatus* out_status));
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 95e1250..161cf43 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -582,6 +582,7 @@
LOG(INFO) << "Found package " << package.name;
OmahaResponse::Package out_package;
+ out_package.app_id = app->id;
out_package.can_exclude = can_exclude;
for (const string& codebase : app->url_codebase) {
if (codebase.empty()) {
@@ -631,6 +632,7 @@
// Removes the candidate URLs which are excluded within packages, if all the
// candidate URLs are excluded within a package, the package will be excluded.
void ProcessExclusions(OmahaResponse* output_object,
+ OmahaRequestParams* params,
ExcluderInterface* excluder) {
for (auto package_it = output_object->packages.begin();
package_it != output_object->packages.end();
@@ -657,6 +659,9 @@
// If there are no candidate payload URLs, remove the package.
if (package_it->payload_urls.empty()) {
LOG(INFO) << "Excluding payload hash=" << package_it->hash;
+ // Need to set DLC as not updated so correct metrics can be sent when an
+ // update is completed.
+ params->SetDlcNoUpdate(package_it->app_id);
package_it = output_object->packages.erase(package_it);
continue;
}
@@ -1023,6 +1028,7 @@
if (!ParseResponse(&parser_data, &output_object, &completer))
return;
ProcessExclusions(&output_object,
+ system_state_->request_params(),
system_state_->update_attempter()->GetExcluder());
output_object.update_exists = true;
SetOutputObject(output_object);
diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc
index 6a0c213..adb95df 100644
--- a/omaha_request_action_unittest.cc
+++ b/omaha_request_action_unittest.cc
@@ -1528,6 +1528,7 @@
request_params_.set_os_board("x86 generic<id");
request_params_.set_current_channel("unittest_track<");
request_params_.set_target_channel("unittest_track<");
+ request_params_.set_lts_tag("unittest_hint<");
request_params_.set_hwid("<OEM MODEL>");
fake_prefs_.SetString(kPrefsOmahaCohort, "evil\nstring");
fake_prefs_.SetString(kPrefsOmahaCohortHint, "evil&string\\");
@@ -1547,6 +1548,8 @@
EXPECT_EQ(string::npos, post_str.find("x86 generic<id"));
EXPECT_NE(string::npos, post_str.find("unittest_track&lt;"));
EXPECT_EQ(string::npos, post_str.find("unittest_track<"));
+ EXPECT_NE(string::npos, post_str.find("unittest_hint&lt;"));
+ EXPECT_EQ(string::npos, post_str.find("unittest_hint<"));
EXPECT_NE(string::npos, post_str.find("<OEM MODEL>"));
EXPECT_EQ(string::npos, post_str.find("<OEM MODEL>"));
EXPECT_NE(string::npos, post_str.find("cohort=\"evil\nstring\""));
@@ -1801,6 +1804,17 @@
EXPECT_EQ(string::npos, post_str.find(omaha_cohort_hint));
}
+TEST_F(OmahaRequestActionTest, TargetChannelHintTest) {
+ tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
+ tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
+ tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
+ request_params_.set_lts_tag("hint>");
+
+ ASSERT_TRUE(TestUpdateCheck());
+
+ EXPECT_NE(string::npos, post_str.find("ltstag=\"hint>\""));
+}
+
void OmahaRequestActionTest::PingTest(bool ping_only) {
NiceMock<MockPrefs> prefs;
fake_system_state_.set_prefs(&prefs);
@@ -2776,8 +2790,8 @@
}
TEST_F(OmahaRequestActionTest, UpdateWithPartiallyExcludedDlcTest) {
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
+ const string kDlcAppId = request_params_.GetDlcAppId(kDlcId1);
+ request_params_.set_dlc_apps_params({{kDlcAppId, {.name = kDlcId1}}});
fake_update_response_.dlc_app_update = true;
tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
// The first DLC candidate URL is excluded.
@@ -2790,11 +2804,12 @@
// One candidate URL.
EXPECT_EQ(response.packages[1].payload_urls.size(), 1u);
EXPECT_TRUE(response.update_exists);
+ EXPECT_TRUE(request_params_.dlc_apps_params().at(kDlcAppId).updated);
}
TEST_F(OmahaRequestActionTest, UpdateWithExcludedDlcTest) {
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
+ const string kDlcAppId = request_params_.GetDlcAppId(kDlcId1);
+ request_params_.set_dlc_apps_params({{kDlcAppId, {.name = kDlcId1}}});
fake_update_response_.dlc_app_update = true;
tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
// Both DLC candidate URLs are excluded.
@@ -2805,6 +2820,7 @@
EXPECT_EQ(response.packages.size(), 1u);
EXPECT_TRUE(response.update_exists);
+ EXPECT_FALSE(request_params_.dlc_apps_params().at(kDlcAppId).updated);
}
TEST_F(OmahaRequestActionTest, UpdateWithDeprecatedDlcTest) {
diff --git a/omaha_request_builder_xml.cc b/omaha_request_builder_xml.cc
index e2857f1..690a4ef 100644
--- a/omaha_request_builder_xml.cc
+++ b/omaha_request_builder_xml.cc
@@ -154,6 +154,11 @@
app_body += " rollback_allowed=\"true\"";
}
}
+ if (!params_->lts_tag().empty()) {
+ app_body += base::StringPrintf(
+ " ltstag=\"%s\"",
+ XmlEncodeWithDefault(params_->lts_tag()).c_str());
+ }
app_body += "></updatecheck>\n";
}
@@ -184,17 +189,26 @@
}
}
} else {
+ int event_result = event_->result;
// The error code is an optional attribute so append it only if the result
// is not success.
string error_code;
- if (event_->result != OmahaEvent::kResultSuccess) {
+ if (event_result != OmahaEvent::kResultSuccess) {
error_code = base::StringPrintf(" errorcode=\"%d\"",
static_cast<int>(event_->error_code));
+ } else if (app_data.is_dlc && !app_data.app_params.updated) {
+ // On a |OmahaEvent::kResultSuccess|, if the event is for an update
+ // completion and the App is a DLC, send error for excluded DLCs as they
+ // did not update.
+ event_result = OmahaEvent::Result::kResultError;
+ error_code = base::StringPrintf(
+ " errorcode=\"%d\"",
+ static_cast<int>(ErrorCode::kPackageExcludedFromUpdate));
}
app_body = base::StringPrintf(
" <event eventtype=\"%d\" eventresult=\"%d\"%s></event>\n",
event_->type,
- event_->result,
+ event_result,
error_code.c_str());
}
diff --git a/omaha_request_builder_xml_unittest.cc b/omaha_request_builder_xml_unittest.cc
index 017acec..a804420 100644
--- a/omaha_request_builder_xml_unittest.cc
+++ b/omaha_request_builder_xml_unittest.cc
@@ -148,10 +148,10 @@
0,
fake_system_state_.prefs(),
""};
- const string request_xml = omaha_request.GetRequest();
+ const string kRequestXml = omaha_request.GetRequest();
const string key = "requestid";
const string request_id =
- FindAttributeKeyValueInXml(request_xml, key, kGuidSize);
+ FindAttributeKeyValueInXml(kRequestXml, key, kGuidSize);
// A valid |request_id| is either a GUID version 4 or empty string.
if (!request_id.empty())
EXPECT_TRUE(base::IsValidGUID(request_id));
@@ -169,10 +169,10 @@
0,
fake_system_state_.prefs(),
gen_session_id};
- const string request_xml = omaha_request.GetRequest();
+ const string kRequestXml = omaha_request.GetRequest();
const string key = "sessionid";
const string session_id =
- FindAttributeKeyValueInXml(request_xml, key, kGuidSize);
+ FindAttributeKeyValueInXml(kRequestXml, key, kGuidSize);
// A valid |session_id| is either a GUID version 4 or empty string.
if (!session_id.empty()) {
EXPECT_TRUE(base::IsValidGUID(session_id));
@@ -191,9 +191,9 @@
0,
fake_system_state_.prefs(),
""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(1, CountSubstringInString(request_xml, "<updatecheck"))
- << request_xml;
+ const string kRequestXml = omaha_request.GetRequest();
+ EXPECT_EQ(1, CountSubstringInString(kRequestXml, "<updatecheck"))
+ << kRequestXml;
}
TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlPlatformUpdateWithDlcsTest) {
@@ -210,9 +210,9 @@
0,
fake_system_state_.prefs(),
""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(3, CountSubstringInString(request_xml, "<updatecheck"))
- << request_xml;
+ const string kRequestXml = omaha_request.GetRequest();
+ EXPECT_EQ(3, CountSubstringInString(kRequestXml, "<updatecheck"))
+ << kRequestXml;
}
TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcInstallationTest) {
@@ -231,25 +231,25 @@
0,
fake_system_state_.prefs(),
""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(2, CountSubstringInString(request_xml, "<updatecheck"))
- << request_xml;
+ const string kRequestXml = omaha_request.GetRequest();
+ EXPECT_EQ(2, CountSubstringInString(kRequestXml, "<updatecheck"))
+ << kRequestXml;
- auto FindAppId = [request_xml](size_t pos) -> size_t {
- return request_xml.find("<app appid", pos);
+ auto FindAppId = [kRequestXml](size_t pos) -> size_t {
+ return kRequestXml.find("<app appid", pos);
};
// Skip over the Platform AppID, which is always first.
size_t pos = FindAppId(0);
for (auto&& _ : dlcs) {
(void)_;
- EXPECT_NE(string::npos, (pos = FindAppId(pos + 1))) << request_xml;
+ EXPECT_NE(string::npos, (pos = FindAppId(pos + 1))) << kRequestXml;
const string dlc_app_id_version = FindAttributeKeyValueInXml(
- request_xml.substr(pos), "version", string(kNoVersion).size());
+ kRequestXml.substr(pos), "version", string(kNoVersion).size());
EXPECT_EQ(kNoVersion, dlc_app_id_version);
const string false_str = "false";
const string dlc_app_id_delta_okay = FindAttributeKeyValueInXml(
- request_xml.substr(pos), "delta_okay", false_str.length());
+ kRequestXml.substr(pos), "delta_okay", false_str.length());
EXPECT_EQ(false_str, dlc_app_id_delta_okay);
}
}
@@ -267,8 +267,8 @@
0,
fake_system_state_.prefs(),
""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(0, CountSubstringInString(request_xml, "<ping")) << request_xml;
+ const string kRequestXml = omaha_request.GetRequest();
+ EXPECT_EQ(0, CountSubstringInString(kRequestXml, "<ping")) << kRequestXml;
}
TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcPingRollCallNoActive) {
@@ -289,9 +289,9 @@
0,
fake_system_state_.prefs(),
""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(1, CountSubstringInString(request_xml, "<ping rd=\"36\""))
- << request_xml;
+ const string kRequestXml = omaha_request.GetRequest();
+ EXPECT_EQ(1, CountSubstringInString(kRequestXml, "<ping rd=\"36\""))
+ << kRequestXml;
}
TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcPingRollCallAndActive) {
@@ -313,10 +313,93 @@
0,
fake_system_state_.prefs(),
""};
- const string request_xml = omaha_request.GetRequest();
+ const string kRequestXml = omaha_request.GetRequest();
EXPECT_EQ(1,
- CountSubstringInString(request_xml,
+ CountSubstringInString(kRequestXml,
"<ping active=\"1\" ad=\"25\" rd=\"36\""))
- << request_xml;
+ << kRequestXml;
+}
+
+TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlUpdateCompleteEvent) {
+ OmahaRequestParams omaha_request_params{&fake_system_state_};
+ OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
+ OmahaRequestBuilderXml omaha_request{&event,
+ &omaha_request_params,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ fake_system_state_.prefs(),
+ ""};
+ const string kRequestXml = omaha_request.GetRequest();
+ LOG(INFO) << kRequestXml;
+ EXPECT_EQ(
+ 1,
+ CountSubstringInString(
+ kRequestXml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
+ << kRequestXml;
+}
+
+TEST_F(OmahaRequestBuilderXmlTest,
+ GetRequestXmlUpdateCompleteEventSomeDlcsExcluded) {
+ OmahaRequestParams omaha_request_params{&fake_system_state_};
+ omaha_request_params.set_dlc_apps_params({
+ {omaha_request_params.GetDlcAppId("dlc_1"), {.updated = true}},
+ {omaha_request_params.GetDlcAppId("dlc_2"), {.updated = false}},
+ });
+ OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
+ OmahaRequestBuilderXml omaha_request{&event,
+ &omaha_request_params,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ fake_system_state_.prefs(),
+ ""};
+ const string kRequestXml = omaha_request.GetRequest();
+ EXPECT_EQ(
+ 2,
+ CountSubstringInString(
+ kRequestXml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
+ << kRequestXml;
+ EXPECT_EQ(
+ 1,
+ CountSubstringInString(
+ kRequestXml,
+ "<event eventtype=\"3\" eventresult=\"0\" errorcode=\"62\"></event>"))
+ << kRequestXml;
+}
+
+TEST_F(OmahaRequestBuilderXmlTest,
+ GetRequestXmlUpdateCompleteEventAllDlcsExcluded) {
+ OmahaRequestParams omaha_request_params{&fake_system_state_};
+ omaha_request_params.set_dlc_apps_params({
+ {omaha_request_params.GetDlcAppId("dlc_1"), {.updated = false}},
+ {omaha_request_params.GetDlcAppId("dlc_2"), {.updated = false}},
+ });
+ OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
+ OmahaRequestBuilderXml omaha_request{&event,
+ &omaha_request_params,
+ false,
+ false,
+ 0,
+ 0,
+ 0,
+ fake_system_state_.prefs(),
+ ""};
+ const string kRequestXml = omaha_request.GetRequest();
+ EXPECT_EQ(
+ 1,
+ CountSubstringInString(
+ kRequestXml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
+ << kRequestXml;
+ EXPECT_EQ(
+ 2,
+ CountSubstringInString(
+ kRequestXml,
+ "<event eventtype=\"3\" eventresult=\"0\" errorcode=\"62\"></event>"))
+ << kRequestXml;
}
} // namespace chromeos_update_engine
diff --git a/omaha_request_params.h b/omaha_request_params.h
index 76fc806..aad9290 100644
--- a/omaha_request_params.h
+++ b/omaha_request_params.h
@@ -148,6 +148,10 @@
return target_version_prefix_;
}
+ inline std::string lts_tag() const { return lts_tag_; }
+
+ inline void set_lts_tag(const std::string& hint) { lts_tag_ = hint; }
+
inline void set_rollback_allowed(bool rollback_allowed) {
rollback_allowed_ = rollback_allowed;
}
@@ -367,6 +371,9 @@
// changed and cancel the current download attempt.
std::string download_channel_;
+ // The value defining the parameters of the LTS (Long Term Support).
+ std::string lts_tag_;
+
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.
diff --git a/omaha_request_params_unittest.cc b/omaha_request_params_unittest.cc
index bfcbc32..110fb2b 100644
--- a/omaha_request_params_unittest.cc
+++ b/omaha_request_params_unittest.cc
@@ -236,6 +236,13 @@
EXPECT_FALSE(params_.ToMoreStableChannel());
}
+TEST_F(OmahaRequestParamsTest, TargetChannelHintTest) {
+ EXPECT_TRUE(params_.Init("", "", false));
+ const string kHint("foo-hint");
+ params_.set_lts_tag(kHint);
+ EXPECT_EQ(kHint, params_.lts_tag());
+}
+
TEST_F(OmahaRequestParamsTest, ShouldPowerwashTest) {
params_.mutable_image_props_.is_powerwash_allowed = false;
EXPECT_FALSE(params_.ShouldPowerwash());
diff --git a/omaha_response.h b/omaha_response.h
index 2b86fe7..77f9083 100644
--- a/omaha_response.h
+++ b/omaha_response.h
@@ -54,6 +54,8 @@
// True if the payload can be excluded from updating if consistently faulty.
// False if the payload is critical to update.
bool can_exclude = false;
+ // The App ID associated with the package.
+ std::string app_id;
};
std::vector<Package> packages;
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index d9efc30..7375d37 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -1623,13 +1623,6 @@
}
}
- if (manifest_.has_old_rootfs_info() || manifest_.has_new_rootfs_info() ||
- manifest_.has_old_kernel_info() || manifest_.has_new_kernel_info() ||
- manifest_.install_operations_size() != 0 ||
- manifest_.kernel_install_operations_size() != 0) {
- LOG(ERROR) << "Manifest contains deprecated fields.";
- return ErrorCode::kPayloadMismatchedType;
- }
ErrorCode error_code = CheckTimestampError();
if (error_code != ErrorCode::kSuccess) {
if (error_code == ErrorCode::kPayloadTimestampError) {
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index a313627..c7ef7b2 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -98,8 +98,8 @@
<< version_str
<< ", source_slot: " << BootControlInterface::SlotName(source_slot)
<< ", target_slot: " << BootControlInterface::SlotName(target_slot)
- << ", initial url: " << url_str << payloads_str
- << partitions_str << ", hash_checks_mandatory: "
+ << ", initial url: " << url_str << payloads_str << partitions_str
+ << ", hash_checks_mandatory: "
<< utils::ToString(hash_checks_mandatory)
<< ", powerwash_required: " << utils::ToString(powerwash_required)
<< ", switch_slot_on_reboot: "
diff --git a/payload_consumer/partition_update_generator_android.cc b/payload_consumer/partition_update_generator_android.cc
index d5d5313..25771e1 100644
--- a/payload_consumer/partition_update_generator_android.cc
+++ b/payload_consumer/partition_update_generator_android.cc
@@ -32,10 +32,8 @@
namespace chromeos_update_engine {
PartitionUpdateGeneratorAndroid::PartitionUpdateGeneratorAndroid(
- BootControlInterface* boot_control,
- size_t block_size)
- : boot_control_(boot_control),
- block_size_(block_size) {}
+ BootControlInterface* boot_control, size_t block_size)
+ : boot_control_(boot_control), block_size_(block_size) {}
bool PartitionUpdateGeneratorAndroid::
GenerateOperationsForPartitionsNotInPayload(
diff --git a/payload_consumer/partition_update_generator_stub.cc b/payload_consumer/partition_update_generator_stub.cc
index 8f73fbb..cfbd5e1 100644
--- a/payload_consumer/partition_update_generator_stub.cc
+++ b/payload_consumer/partition_update_generator_stub.cc
@@ -30,7 +30,7 @@
namespace partition_update_generator {
std::unique_ptr<PartitionUpdateGeneratorInterface> Create(
- BootControlInterface* boot_control, size_t block_size)) {
+ BootControlInterface* boot_control, size_t block_size) {
return std::make_unique<PartitionUpdateGeneratorStub>();
}
} // namespace partition_update_generator
diff --git a/payload_consumer/payload_constants.cc b/payload_consumer/payload_constants.cc
index d62a0ec..663ab81 100644
--- a/payload_consumer/payload_constants.cc
+++ b/payload_consumer/payload_constants.cc
@@ -66,10 +66,6 @@
return "PUFFDIFF";
case InstallOperation::BROTLI_BSDIFF:
return "BROTLI_BSDIFF";
-
- case InstallOperation::BSDIFF:
- case InstallOperation::MOVE:
- NOTREACHED();
}
return "<unknown_op>";
}
diff --git a/payload_consumer/payload_verifier.cc b/payload_consumer/payload_verifier.cc
index 24e337e..7fd2b8e 100644
--- a/payload_consumer/payload_verifier.cc
+++ b/payload_consumer/payload_verifier.cc
@@ -175,7 +175,10 @@
}
if (key_type == EVP_PKEY_EC) {
- EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(public_key.get());
+ // TODO(b/158580694): Switch back to get0 version and remove manual
+ // freeing of the object once the bug is resolved or gale has been moved
+ // to informational.
+ EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(public_key.get());
TEST_AND_RETURN_FALSE(ec_key != nullptr);
if (ECDSA_verify(0,
sha256_hash_data.data(),
@@ -183,8 +186,10 @@
sig_data.data(),
sig_data.size(),
ec_key) == 1) {
+ EC_KEY_free(ec_key);
return true;
}
+ EC_KEY_free(ec_key);
}
LOG(ERROR) << "Unsupported key type " << key_type;
@@ -199,16 +204,21 @@
const brillo::Blob& sig_data,
const EVP_PKEY* public_key,
brillo::Blob* out_hash_data) const {
+ // TODO(b/158580694): Switch back to get0 version and remove manual freeing of
+ // the object once the bug is resolved or gale has been moved to
+ // informational.
+ //
// The code below executes the equivalent of:
//
// openssl rsautl -verify -pubin -inkey <(echo pem_public_key)
// -in |sig_data| -out |out_hash_data|
- RSA* rsa = EVP_PKEY_get0_RSA(public_key);
+ RSA* rsa = EVP_PKEY_get1_RSA(const_cast<EVP_PKEY*>(public_key));
TEST_AND_RETURN_FALSE(rsa != nullptr);
unsigned int keysize = RSA_size(rsa);
if (sig_data.size() > 2 * keysize) {
LOG(ERROR) << "Signature size is too big for public key size.";
+ RSA_free(rsa);
return false;
}
@@ -216,6 +226,7 @@
brillo::Blob hash_data(keysize);
int decrypt_size = RSA_public_decrypt(
sig_data.size(), sig_data.data(), hash_data.data(), rsa, RSA_NO_PADDING);
+ RSA_free(rsa);
TEST_AND_RETURN_FALSE(decrypt_size > 0 &&
decrypt_size <= static_cast<int>(hash_data.size()));
hash_data.resize(decrypt_size);
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index dd41a29..5c1fb47 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -501,7 +501,11 @@
Terminator::Init();
logging::LoggingSettings log_settings;
+#if BASE_VER < 780000
log_settings.log_file = "delta_generator.log";
+#else
+ log_settings.log_file_path = "delta_generator.log";
+#endif
log_settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
log_settings.lock_log = logging::LOCK_LOG_FILE;
log_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index 9c5832d..35a95dc 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -266,10 +266,6 @@
case InstallOperation::PUFFDIFF:
return minor >= kPuffdiffMinorPayloadVersion;
-
- case InstallOperation::MOVE:
- case InstallOperation::BSDIFF:
- NOTREACHED();
}
return false;
}
diff --git a/payload_generator/payload_signer.cc b/payload_generator/payload_signer.cc
index c3264c1..9a44f94 100644
--- a/payload_generator/payload_signer.cc
+++ b/payload_generator/payload_signer.cc
@@ -309,7 +309,10 @@
int key_type = EVP_PKEY_id(private_key.get());
brillo::Blob signature;
if (key_type == EVP_PKEY_RSA) {
- RSA* rsa = EVP_PKEY_get0_RSA(private_key.get());
+ // TODO(b/158580694): Switch back to get0 version and remove manual freeing
+ // of the object once the bug is resolved or gale has been moved to
+ // informational.
+ RSA* rsa = EVP_PKEY_get1_RSA(private_key.get());
TEST_AND_RETURN_FALSE(rsa != nullptr);
brillo::Blob padded_hash = hash;
@@ -321,16 +324,20 @@
signature.data(),
rsa,
RSA_NO_PADDING);
-
if (signature_size < 0) {
LOG(ERROR) << "Signing hash failed: "
<< ERR_error_string(ERR_get_error(), nullptr);
+ RSA_free(rsa);
return false;
}
+ RSA_free(rsa);
TEST_AND_RETURN_FALSE(static_cast<size_t>(signature_size) ==
signature.size());
} else if (key_type == EVP_PKEY_EC) {
- EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(private_key.get());
+ // TODO(b/158580694): Switch back to get0 version and remove manual freeing
+ // of the object once the bug is resolved or gale has been moved to
+ // informational.
+ EC_KEY* ec_key = EVP_PKEY_get1_EC_KEY(private_key.get());
TEST_AND_RETURN_FALSE(ec_key != nullptr);
signature.resize(ECDSA_size(ec_key));
@@ -343,8 +350,10 @@
ec_key) != 1) {
LOG(ERROR) << "Signing hash failed: "
<< ERR_error_string(ERR_get_error(), nullptr);
+ EC_KEY_free(ec_key);
return false;
}
+ EC_KEY_free(ec_key);
// NIST P-256
LOG(ERROR) << "signature max size " << signature.size() << " size "
diff --git a/payload_state.cc b/payload_state.cc
index 4945fe7..1d1583b 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -375,6 +375,7 @@
case ErrorCode::kUnresolvedHostRecovered:
case ErrorCode::kNotEnoughSpace:
case ErrorCode::kDeviceCorrupted:
+ case ErrorCode::kPackageExcludedFromUpdate:
LOG(INFO) << "Not incrementing URL index or failure count for this error";
break;
@@ -463,6 +464,7 @@
}
void PayloadState::IncrementFullPayloadAttemptNumber() {
+ DCHECK(payload_index_ < response_.packages.size());
// Update the payload attempt number for full payloads and the backoff time.
if (response_.packages[payload_index_].is_delta) {
LOG(INFO) << "Not incrementing payload attempt number for delta payloads";
@@ -475,6 +477,7 @@
}
void PayloadState::IncrementUrlIndex() {
+ DCHECK(payload_index_ < candidate_urls_.size());
size_t next_url_index = url_index_ + 1;
size_t max_url_size = candidate_urls_[payload_index_].size();
if (next_url_index < max_url_size) {
@@ -511,6 +514,10 @@
}
void PayloadState::ExcludeCurrentPayload() {
+ if (payload_index_ >= response_.packages.size()) {
+ LOG(INFO) << "Skipping exclusion of the current payload.";
+ return;
+ }
const auto& package = response_.packages[payload_index_];
if (!package.can_exclude) {
LOG(INFO) << "Not excluding as marked non-excludable for package hash="
@@ -613,10 +620,6 @@
return kPayloadTypeForcedFull;
}
-// TODO(zeuthen): Currently we don't report the UpdateEngine.Attempt.*
-// metrics if the attempt ends abnormally, e.g. if the update_engine
-// process crashes or the device is rebooted. See
-// http://crbug.com/357676
void PayloadState::CollectAndReportAttemptMetrics(ErrorCode code) {
int attempt_number = GetPayloadAttemptNumber();
@@ -671,6 +674,7 @@
case metrics::AttemptResult::kAbnormalTermination:
case metrics::AttemptResult::kUpdateCanceled:
case metrics::AttemptResult::kUpdateSucceededNotActive:
+ case metrics::AttemptResult::kUpdateSkipped:
case metrics::AttemptResult::kNumConstants:
case metrics::AttemptResult::kUnset:
break;
@@ -924,10 +928,12 @@
}
bool PayloadState::NextPayload() {
- if (payload_index_ + 1 >= candidate_urls_.size())
+ if (payload_index_ >= candidate_urls_.size())
+ return false;
+ SetPayloadIndex(payload_index_ + 1);
+ if (payload_index_ >= candidate_urls_.size())
return false;
SetUrlIndex(0);
- SetPayloadIndex(payload_index_ + 1);
return true;
}
diff --git a/payload_state.h b/payload_state.h
index 427836b..77197a7 100644
--- a/payload_state.h
+++ b/payload_state.h
@@ -161,6 +161,8 @@
FRIEND_TEST(PayloadStateTest, ExcludeNoopForNonExcludables);
FRIEND_TEST(PayloadStateTest, ExcludeOnlyCanExcludables);
FRIEND_TEST(PayloadStateTest, IncrementFailureExclusionTest);
+ FRIEND_TEST(PayloadStateTest, HaltExclusionPostPayloadExhaustion);
+ FRIEND_TEST(PayloadStateTest, NonInfinitePayloadIndexIncrement);
// Helper called when an attempt has begun, is called by
// UpdateResumed(), UpdateRestarted() and Rollback().
diff --git a/payload_state_unittest.cc b/payload_state_unittest.cc
index c33bda4..8667548 100644
--- a/payload_state_unittest.cc
+++ b/payload_state_unittest.cc
@@ -1778,4 +1778,49 @@
payload_state.IncrementFailureCount();
}
+TEST(PayloadStateTest, HaltExclusionPostPayloadExhaustion) {
+ PayloadState payload_state;
+ FakeSystemState fake_system_state;
+ StrictMock<MockExcluder> mock_excluder;
+ EXPECT_CALL(*fake_system_state.mock_update_attempter(), GetExcluder())
+ .WillOnce(Return(&mock_excluder));
+ EXPECT_TRUE(payload_state.Initialize(&fake_system_state));
+
+ OmahaResponse response;
+ // Non-critical package.
+ response.packages.push_back(
+ {.payload_urls = {"http://test1a", "http://test2a"},
+ .size = 123456789,
+ .metadata_size = 58123,
+ .metadata_signature = "msign",
+ .hash = "hash",
+ .can_exclude = true});
+ payload_state.SetResponse(response);
+
+ // Exclusion should be called when excluded.
+ EXPECT_CALL(mock_excluder, Exclude(utils::GetExclusionName("http://test1a")))
+ .WillOnce(Return(true));
+ payload_state.ExcludeCurrentPayload();
+
+ // No more paylods to go through.
+ EXPECT_FALSE(payload_state.NextPayload());
+
+ // Exclusion should not be called as all |Payload|s are exhausted.
+ payload_state.ExcludeCurrentPayload();
+}
+
+TEST(PayloadStateTest, NonInfinitePayloadIndexIncrement) {
+ PayloadState payload_state;
+ FakeSystemState fake_system_state;
+ EXPECT_TRUE(payload_state.Initialize(&fake_system_state));
+
+ payload_state.SetResponse({});
+
+ EXPECT_FALSE(payload_state.NextPayload());
+ int payload_index = payload_state.payload_index_;
+
+ EXPECT_FALSE(payload_state.NextPayload());
+ EXPECT_EQ(payload_index, payload_state.payload_index_);
+}
+
} // namespace chromeos_update_engine
diff --git a/requisition_util.cc b/requisition_util.cc
new file mode 100644
index 0000000..5445bce
--- /dev/null
+++ b/requisition_util.cc
@@ -0,0 +1,69 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/requisition_util.h"
+
+#include <memory>
+#include <vector>
+
+#include <base/files/file_util.h>
+#include <base/json/json_file_value_serializer.h>
+#include <base/logging.h>
+#include <base/strings/string_util.h>
+
+#include "update_engine/common/subprocess.h"
+#include "update_engine/common/utils.h"
+
+using std::string;
+using std::vector;
+
+namespace {
+
+constexpr char kOemRequisitionKey[] = "oem_device_requisition";
+
+} // namespace
+
+namespace chromeos_update_engine {
+
+string ReadDeviceRequisition(const base::FilePath& local_state) {
+ string requisition;
+ bool vpd_retval = utils::GetVpdValue(kOemRequisitionKey, &requisition);
+
+ // Some users manually convert non-CfM hardware at enrollment time, so VPD
+ // value may be missing. So check the Local State JSON as well.
+ if ((requisition.empty() || !vpd_retval) && base::PathExists(local_state)) {
+ int error_code;
+ std::string error_msg;
+ JSONFileValueDeserializer deserializer(local_state);
+ std::unique_ptr<base::Value> root =
+ deserializer.Deserialize(&error_code, &error_msg);
+ if (!root) {
+ if (error_code != 0) {
+ LOG(ERROR) << "Unable to deserialize Local State with exit code: "
+ << error_code << " and error: " << error_msg;
+ }
+ return "";
+ }
+ auto* path = root->FindPath({"enrollment", "device_requisition"});
+ if (!path || !path->is_string()) {
+ return "";
+ }
+ path->GetAsString(&requisition);
+ }
+ return requisition;
+}
+
+} // namespace chromeos_update_engine
diff --git a/requisition_util.h b/requisition_util.h
new file mode 100644
index 0000000..8577ee7
--- /dev/null
+++ b/requisition_util.h
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#ifndef UPDATE_ENGINE_REQUISITION_UTIL_H_
+#define UPDATE_ENGINE_REQUISITION_UTIL_H_
+
+#include <string>
+
+#include <base/files/file_path.h>
+
+namespace chromeos_update_engine {
+
+// Checks the VPD and Local State for the device's requisition and returns it,
+// or an empty string if the device has no requisition.
+std::string ReadDeviceRequisition(const base::FilePath& local_state);
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_REQUISITION_UTIL_H_
diff --git a/requisition_util_unittest.cc b/requisition_util_unittest.cc
new file mode 100644
index 0000000..c21c9c7
--- /dev/null
+++ b/requisition_util_unittest.cc
@@ -0,0 +1,94 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+#include "update_engine/requisition_util.h"
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/files/scoped_temp_dir.h>
+#include <gtest/gtest.h>
+
+#include "update_engine/common/test_utils.h"
+
+using chromeos_update_engine::test_utils::WriteFileString;
+using std::string;
+
+namespace {
+
+const char kRemoraJSON[] =
+ "{\n"
+ " \"the_list\": [ \"val1\", \"val2\" ],\n"
+ " \"enrollment\": {\n"
+ " \"autostart\": true,\n"
+ " \"can_exit\": false,\n"
+ " \"device_requisition\": \"remora\"\n"
+ " },\n"
+ " \"some_String\": \"1337\",\n"
+ " \"some_int\": 42\n"
+ "}\n";
+
+const char kNoEnrollmentJSON[] =
+ "{\n"
+ " \"the_list\": [ \"val1\", \"val2\" ],\n"
+ " \"enrollment\": {\n"
+ " \"autostart\": true,\n"
+ " \"can_exit\": false,\n"
+ " \"device_requisition\": \"\"\n"
+ " },\n"
+ " \"some_String\": \"1337\",\n"
+ " \"some_int\": 42\n"
+ "}\n";
+} // namespace
+
+namespace chromeos_update_engine {
+
+class RequisitionUtilTest : public ::testing::Test {
+ protected:
+ void SetUp() override { ASSERT_TRUE(root_dir_.CreateUniqueTempDir()); }
+
+ void WriteJsonToFile(const string& json) {
+ path_ =
+ base::FilePath(root_dir_.GetPath().value() + "/chronos/Local State");
+ ASSERT_TRUE(base::CreateDirectory(path_.DirName()));
+ ASSERT_TRUE(WriteFileString(path_.value(), json));
+ }
+
+ base::ScopedTempDir root_dir_;
+ base::FilePath path_;
+};
+
+TEST_F(RequisitionUtilTest, BadJsonReturnsEmpty) {
+ WriteJsonToFile("this isn't JSON");
+ EXPECT_EQ("", ReadDeviceRequisition(path_));
+}
+
+TEST_F(RequisitionUtilTest, NoFileReturnsEmpty) {
+ EXPECT_EQ("", ReadDeviceRequisition(path_));
+}
+
+TEST_F(RequisitionUtilTest, EnrollmentRequisition) {
+ WriteJsonToFile(kRemoraJSON);
+ EXPECT_EQ("remora", ReadDeviceRequisition(path_));
+}
+
+TEST_F(RequisitionUtilTest, BlankEnrollment) {
+ WriteJsonToFile(kNoEnrollmentJSON);
+ EXPECT_EQ("", ReadDeviceRequisition(path_));
+}
+
+} // namespace chromeos_update_engine
diff --git a/test_http_server.cc b/test_http_server.cc
index 1c3a2e0..cf6f10d 100644
--- a/test_http_server.cc
+++ b/test_http_server.cc
@@ -409,7 +409,6 @@
return;
WriteString(fd, "Connection: close" EOL);
WriteString(fd, "Location: " + url + EOL);
-
}
// Generate a page not found error response with actual text payload. Return
diff --git a/update_attempter.cc b/update_attempter.cc
index c4fe348..24562e2 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -247,6 +247,7 @@
void UpdateAttempter::Update(const string& app_version,
const string& omaha_url,
const string& target_channel,
+ const string& lts_tag,
const string& target_version_prefix,
bool rollback_allowed,
bool rollback_data_save_requested,
@@ -284,6 +285,7 @@
if (!CalculateUpdateParams(app_version,
omaha_url,
target_channel,
+ lts_tag,
target_version_prefix,
rollback_allowed,
rollback_data_save_requested,
@@ -359,6 +361,7 @@
bool UpdateAttempter::CalculateUpdateParams(const string& app_version,
const string& omaha_url,
const string& target_channel,
+ const string& lts_tag,
const string& target_version_prefix,
bool rollback_allowed,
bool rollback_data_save_requested,
@@ -378,6 +381,9 @@
// Update the target version prefix.
omaha_request_params_->set_target_version_prefix(target_version_prefix);
+ // Update the LTS support.
+ omaha_request_params_->set_lts_tag(lts_tag);
+
// Set whether rollback is allowed.
omaha_request_params_->set_rollback_allowed(rollback_allowed);
@@ -1103,6 +1109,7 @@
Update(forced_app_version_,
forced_omaha_url_,
params.target_channel,
+ params.lts_tag,
params.target_version_prefix,
params.rollback_allowed,
params.rollback_data_save_requested,
diff --git a/update_attempter.h b/update_attempter.h
index dd958f5..abd0bd4 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -85,6 +85,7 @@
virtual void Update(const std::string& app_version,
const std::string& omaha_url,
const std::string& target_channel,
+ const std::string& lts_tag,
const std::string& target_version_prefix,
bool rollback_allowed,
bool rollback_data_save_requested,
@@ -293,6 +294,7 @@
FRIEND_TEST(UpdateAttempterTest, SessionIdTestOnOmahaRequestActions);
FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedNotRollback);
FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedRollback);
+ FRIEND_TEST(UpdateAttempterTest, TargetChannelHintSetAndReset);
FRIEND_TEST(UpdateAttempterTest, TargetVersionPrefixSetAndReset);
FRIEND_TEST(UpdateAttempterTest, UpdateAfterInstall);
FRIEND_TEST(UpdateAttempterTest, UpdateAttemptFlagsCachedAtUpdateStart);
@@ -369,6 +371,7 @@
bool CalculateUpdateParams(const std::string& app_version,
const std::string& omaha_url,
const std::string& target_channel,
+ const std::string& lts_tag,
const std::string& target_version_prefix,
bool rollback_allowed,
bool rollback_data_save_requested,
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 305dbdb..354416e 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -174,6 +174,7 @@
void Update(const std::string& app_version,
const std::string& omaha_url,
const std::string& target_channel,
+ const std::string& lts_tag,
const std::string& target_version_prefix,
bool rollback_allowed,
bool rollback_data_save_requested,
@@ -185,6 +186,7 @@
UpdateAttempter::Update(app_version,
omaha_url,
target_channel,
+ lts_tag,
target_version_prefix,
rollback_allowed,
rollback_data_save_requested,
@@ -425,7 +427,7 @@
void UpdateAttempterTest::SessionIdTestChange() {
EXPECT_NE(UpdateStatus::UPDATED_NEED_REBOOT, attempter_.status());
const auto old_session_id = attempter_.session_id_;
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_NE(old_session_id, attempter_.session_id_);
ScheduleQuitMainLoop();
}
@@ -796,7 +798,7 @@
EXPECT_CALL(*processor_, StartProcessing());
}
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
loop_.PostTask(FROM_HERE,
base::Bind(&UpdateAttempterTest::UpdateTestVerify,
base::Unretained(this)));
@@ -996,7 +998,7 @@
fake_system_state_.set_p2p_manager(&mock_p2p_manager);
mock_p2p_manager.fake().SetP2PEnabled(false);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping()).Times(0);
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_FALSE(actual_using_p2p_for_downloading_);
EXPECT_FALSE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -1018,7 +1020,7 @@
mock_p2p_manager.fake().SetEnsureP2PRunningResult(false);
mock_p2p_manager.fake().SetPerformHousekeepingResult(false);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping()).Times(0);
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_FALSE(actual_using_p2p_for_downloading());
EXPECT_FALSE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -1041,7 +1043,7 @@
mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
mock_p2p_manager.fake().SetPerformHousekeepingResult(false);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_FALSE(actual_using_p2p_for_downloading());
EXPECT_FALSE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -1063,7 +1065,7 @@
mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
mock_p2p_manager.fake().SetPerformHousekeepingResult(true);
EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_TRUE(actual_using_p2p_for_downloading());
EXPECT_TRUE(actual_using_p2p_for_sharing());
ScheduleQuitMainLoop();
@@ -1090,6 +1092,7 @@
"",
"",
"",
+ "",
false,
false,
/*rollback_allowed_milestones=*/0,
@@ -1124,7 +1127,7 @@
attempter_.policy_provider_.reset(
new policy::PolicyProvider(std::move(device_policy)));
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
ScheduleQuitMainLoop();
@@ -1162,7 +1165,7 @@
attempter_.policy_provider_.reset(
new policy::PolicyProvider(std::move(device_policy)));
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
// Make sure the file still exists.
@@ -1178,7 +1181,7 @@
// However, if the count is already 0, it's not decremented. Test that.
initial_value = 0;
EXPECT_TRUE(fake_prefs.SetInt64(kPrefsUpdateCheckCount, initial_value));
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_TRUE(fake_prefs.Exists(kPrefsUpdateCheckCount));
EXPECT_TRUE(fake_prefs.GetInt64(kPrefsUpdateCheckCount, &new_value));
EXPECT_EQ(initial_value, new_value);
@@ -1229,6 +1232,7 @@
"",
"",
"",
+ "",
false,
false,
/*rollback_allowed_milestones=*/0,
@@ -1285,7 +1289,7 @@
FakePrefs fake_prefs;
SetUpStagingTest(kValidStagingSchedule, &fake_prefs);
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
// Check that prefs have the correct values.
int64_t update_count;
EXPECT_TRUE(fake_prefs.GetInt64(kPrefsUpdateCheckCount, &update_count));
@@ -1343,7 +1347,7 @@
SetUpStagingTest(kValidStagingSchedule, &fake_prefs);
attempter_.Update(
- "", "", "", "", false, false, 0, false, /* interactive = */ true);
+ "", "", "", "", "", false, false, 0, false, /* interactive = */ true);
CheckStagingOff();
ScheduleQuitMainLoop();
@@ -1364,7 +1368,7 @@
SetUpStagingTest(kValidStagingSchedule, &fake_prefs);
attempter_.Update(
- "", "", "", "", false, false, 0, false, /* interactive = */ true);
+ "", "", "", "", "", false, false, 0, false, /* interactive = */ true);
CheckStagingOff();
ScheduleQuitMainLoop();
@@ -1693,20 +1697,31 @@
TEST_F(UpdateAttempterTest, TargetVersionPrefixSetAndReset) {
attempter_.CalculateUpdateParams(
- "", "", "", "1234", false, false, 4, false, false);
+ "", "", "", "", "1234", false, false, 4, false, false);
EXPECT_EQ("1234",
fake_system_state_.request_params()->target_version_prefix());
attempter_.CalculateUpdateParams(
- "", "", "", "", false, 4, false, false, false);
+ "", "", "", "", "", false, 4, false, false, false);
EXPECT_TRUE(
fake_system_state_.request_params()->target_version_prefix().empty());
}
+TEST_F(UpdateAttempterTest, TargetChannelHintSetAndReset) {
+ attempter_.CalculateUpdateParams(
+ "", "", "", "hint", "", false, false, 4, false, false);
+ EXPECT_EQ("hint", fake_system_state_.request_params()->lts_tag());
+
+ attempter_.CalculateUpdateParams(
+ "", "", "", "", "", false, 4, false, false, false);
+ EXPECT_TRUE(fake_system_state_.request_params()->lts_tag().empty());
+}
+
TEST_F(UpdateAttempterTest, RollbackAllowedSetAndReset) {
attempter_.CalculateUpdateParams("",
"",
"",
+ "",
"1234",
/*rollback_allowed=*/true,
/*rollback_data_save_requested=*/false,
@@ -1720,6 +1735,7 @@
attempter_.CalculateUpdateParams("",
"",
"",
+ "",
"1234",
/*rollback_allowed=*/false,
/*rollback_data_save_requested=*/false,
@@ -1845,7 +1861,7 @@
SetRollbackHappened(false))
.Times(expected_reset ? 1 : 0);
attempter_.policy_provider_ = std::move(mock_policy_provider);
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
ScheduleQuitMainLoop();
}
@@ -2186,7 +2202,7 @@
.WillOnce(Return(false));
attempter_.policy_provider_.reset(
new policy::PolicyProvider(std::move(device_policy)));
- attempter_.Update("", "", "", "", false, false, 0, false, false);
+ attempter_.Update("", "", "", "", "", false, false, 0, false, false);
EXPECT_EQ(token, attempter_.omaha_request_params_->autoupdate_token());
ScheduleQuitMainLoop();
diff --git a/update_engine.conf.chromeos b/update_engine.conf.chromeos
new file mode 100644
index 0000000..af213ad
--- /dev/null
+++ b/update_engine.conf.chromeos
@@ -0,0 +1,2 @@
+PAYLOAD_MAJOR_VERSION=2
+PAYLOAD_MINOR_VERSION=6
diff --git a/update_manager/android_things_policy.cc b/update_manager/android_things_policy.cc
index a76ea48..6362a73 100644
--- a/update_manager/android_things_policy.cc
+++ b/update_manager/android_things_policy.cc
@@ -58,6 +58,7 @@
// Set the default return values.
result->updates_enabled = true;
result->target_channel.clear();
+ result->lts_tag.clear();
result->target_version_prefix.clear();
result->rollback_allowed = false;
result->rollback_data_save_requested = false;
diff --git a/update_manager/boxed_value.cc b/update_manager/boxed_value.cc
index b031dfc..ba84a41 100644
--- a/update_manager/boxed_value.cc
+++ b/update_manager/boxed_value.cc
@@ -23,6 +23,7 @@
#include <base/strings/string_number_conversions.h>
#include <base/time/time.h>
+#include <base/version.h>
#include "update_engine/common/utils.h"
#include "update_engine/connection_utils.h"
@@ -234,4 +235,30 @@
return retval;
}
+template <>
+string BoxedValue::ValuePrinter<ChannelDowngradeBehavior>(const void* value) {
+ const ChannelDowngradeBehavior* val =
+ reinterpret_cast<const ChannelDowngradeBehavior*>(value);
+ switch (*val) {
+ case ChannelDowngradeBehavior::kUnspecified:
+ return "Unspecified";
+ case ChannelDowngradeBehavior::kWaitForVersionToCatchUp:
+ return "Wait for the target channel to catch up";
+ case ChannelDowngradeBehavior::kRollback:
+ return "Roll back and powerwash on channel downgrade";
+ case ChannelDowngradeBehavior::kAllowUserToConfigure:
+ return "User decides on channel downgrade behavior";
+ }
+ NOTREACHED();
+ return "Unknown";
+}
+
+template <>
+string BoxedValue::ValuePrinter<base::Version>(const void* value) {
+ const base::Version* val = reinterpret_cast<const base::Version*>(value);
+ if (val->IsValid())
+ return val->GetString();
+ return "Unknown";
+}
+
} // namespace chromeos_update_manager
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
index be5f914..85cc3ae 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -156,6 +156,7 @@
case ErrorCode::kUnresolvedHostRecovered:
case ErrorCode::kNotEnoughSpace:
case ErrorCode::kDeviceCorrupted:
+ case ErrorCode::kPackageExcludedFromUpdate:
LOG(INFO) << "Not changing URL index or failure count due to error "
<< chromeos_update_engine::utils::ErrorCodeToString(err_code)
<< " (" << static_cast<int>(err_code) << ")";
@@ -216,6 +217,7 @@
// Set the default return values.
result->updates_enabled = true;
result->target_channel.clear();
+ result->lts_tag.clear();
result->target_version_prefix.clear();
result->rollback_allowed = false;
result->rollback_allowed_milestones = -1;
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
index 414ac0d..996db2b 100644
--- a/update_manager/chromeos_policy_unittest.cc
+++ b/update_manager/chromeos_policy_unittest.cc
@@ -262,6 +262,8 @@
new bool(false));
fake_state_.device_policy_provider()->var_release_channel()->reset(
new string("foo-channel"));
+ fake_state_.device_policy_provider()->var_release_lts_tag()->reset(
+ new string("foo-hint"));
UpdateCheckParams result;
ExpectPolicyStatus(
@@ -270,6 +272,7 @@
EXPECT_EQ("1.2", result.target_version_prefix);
EXPECT_EQ(5, result.rollback_allowed_milestones);
EXPECT_EQ("foo-channel", result.target_channel);
+ EXPECT_EQ("foo-hint", result.lts_tag);
EXPECT_FALSE(result.interactive);
}
@@ -338,6 +341,26 @@
EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
}
+TEST_F(UmChromeOSPolicyTest, TestUpdateCheckIntervalTimeout) {
+ fake_state_.updater_provider()
+ ->var_test_update_check_interval_timeout()
+ ->reset(new int64_t(10));
+ fake_state_.system_provider()->var_is_official_build()->reset(
+ new bool(false));
+
+ // The first time, update should not be allowed.
+ UpdateCheckParams result;
+ ExpectPolicyStatus(
+ EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
+
+ // After moving the time forward more than the update check interval, it
+ // should now allow for update.
+ fake_clock_.SetWallclockTime(fake_clock_.GetWallclockTime() +
+ TimeDelta::FromSeconds(11));
+ ExpectPolicyStatus(
+ EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
+}
+
TEST_F(UmChromeOSPolicyTest,
UpdateCheckAllowedUpdatesDisabledWhenNotEnoughSlotsAbUpdates) {
// UpdateCheckAllowed should return false (kSucceeded) if the image booted
diff --git a/update_manager/default_policy.cc b/update_manager/default_policy.cc
index 81ab795..cc13c44 100644
--- a/update_manager/default_policy.cc
+++ b/update_manager/default_policy.cc
@@ -40,6 +40,7 @@
UpdateCheckParams* result) const {
result->updates_enabled = true;
result->target_channel.clear();
+ result->lts_tag.clear();
result->target_version_prefix.clear();
result->rollback_allowed = false;
result->rollback_allowed_milestones = -1; // No version rolls should happen.
diff --git a/update_manager/device_policy_provider.h b/update_manager/device_policy_provider.h
index b68fe96..a59f2a3 100644
--- a/update_manager/device_policy_provider.h
+++ b/update_manager/device_policy_provider.h
@@ -21,6 +21,7 @@
#include <string>
#include <base/time/time.h>
+#include <base/version.h>
#include <policy/libpolicy.h>
#include "update_engine/update_manager/provider.h"
@@ -44,6 +45,8 @@
virtual Variable<bool>* var_release_channel_delegated() = 0;
+ virtual Variable<std::string>* var_release_lts_tag() = 0;
+
virtual Variable<bool>* var_update_disabled() = 0;
virtual Variable<std::string>* var_target_version_prefix() = 0;
@@ -85,6 +88,15 @@
virtual Variable<WeeklyTimeIntervalVector>*
var_disallowed_time_intervals() = 0;
+ // Variable that determins whether we should powerwash and rollback on channel
+ // downgrade for enrolled devices.
+ virtual Variable<ChannelDowngradeBehavior>*
+ var_channel_downgrade_behavior() = 0;
+
+ // Variable that contains Chrome OS minimum required version. It contains a
+ // Chrome OS version number.
+ virtual Variable<base::Version>* var_device_minimum_version() = 0;
+
protected:
DevicePolicyProvider() {}
diff --git a/update_manager/enterprise_device_policy_impl.cc b/update_manager/enterprise_device_policy_impl.cc
index dea38ba..fed50a9 100644
--- a/update_manager/enterprise_device_policy_impl.cc
+++ b/update_manager/enterprise_device_policy_impl.cc
@@ -126,6 +126,12 @@
if (release_channel_p)
result->target_channel = *release_channel_p;
}
+
+ const string* release_lts_tag_p =
+ ec->GetValue(dp_provider->var_release_lts_tag());
+ if (release_lts_tag_p) {
+ result->lts_tag = *release_lts_tag_p;
+ }
}
return EvalStatus::kContinue;
}
diff --git a/update_manager/evaluation_context-inl.h b/update_manager/evaluation_context-inl.h
index 59d85da..82861fa 100644
--- a/update_manager/evaluation_context-inl.h
+++ b/update_manager/evaluation_context-inl.h
@@ -39,7 +39,7 @@
std::string errmsg;
const T* result =
var->GetValue(RemainingTime(evaluation_monotonic_deadline_), &errmsg);
- if (result == nullptr) {
+ if (result == nullptr && !var->IsMissingOk()) {
LOG(WARNING) << "Error reading Variable " << var->GetName() << ": \""
<< errmsg << "\"";
}
diff --git a/update_manager/fake_device_policy_provider.h b/update_manager/fake_device_policy_provider.h
index 86bdef1..55d66b3 100644
--- a/update_manager/fake_device_policy_provider.h
+++ b/update_manager/fake_device_policy_provider.h
@@ -42,6 +42,10 @@
return &var_release_channel_delegated_;
}
+ FakeVariable<std::string>* var_release_lts_tag() override {
+ return &var_release_lts_tag_;
+ }
+
FakeVariable<bool>* var_update_disabled() override {
return &var_update_disabled_;
}
@@ -91,6 +95,15 @@
return &var_disallowed_time_intervals_;
}
+ FakeVariable<ChannelDowngradeBehavior>* var_channel_downgrade_behavior()
+ override {
+ return &var_channel_downgrade_behavior_;
+ }
+
+ FakeVariable<base::Version>* var_device_minimum_version() override {
+ return &var_device_minimum_version_;
+ }
+
private:
FakeVariable<bool> var_device_policy_is_loaded_{"policy_is_loaded",
kVariableModePoll};
@@ -98,6 +111,8 @@
kVariableModePoll};
FakeVariable<bool> var_release_channel_delegated_{"release_channel_delegated",
kVariableModePoll};
+ FakeVariable<std::string> var_release_lts_tag_{"release_lts_tag",
+ kVariableModePoll};
FakeVariable<bool> var_update_disabled_{"update_disabled", kVariableModePoll};
FakeVariable<std::string> var_target_version_prefix_{"target_version_prefix",
kVariableModePoll};
@@ -120,6 +135,10 @@
"auto_launched_kiosk_app_id", kVariableModePoll};
FakeVariable<WeeklyTimeIntervalVector> var_disallowed_time_intervals_{
"disallowed_time_intervals", kVariableModePoll};
+ FakeVariable<ChannelDowngradeBehavior> var_channel_downgrade_behavior_{
+ "channel_downgrade_behavior", kVariableModePoll};
+ FakeVariable<base::Version> var_device_minimum_version_{
+ "device_minimum_version", kVariableModePoll};
DISALLOW_COPY_AND_ASSIGN(FakeDevicePolicyProvider);
};
diff --git a/update_manager/fake_updater_provider.h b/update_manager/fake_updater_provider.h
index 7295765..d967f42 100644
--- a/update_manager/fake_updater_provider.h
+++ b/update_manager/fake_updater_provider.h
@@ -83,6 +83,10 @@
return &var_update_restrictions_;
}
+ FakeVariable<int64_t>* var_test_update_check_interval_timeout() override {
+ return &var_test_update_check_interval_timeout_;
+ }
+
private:
FakeVariable<base::Time> var_updater_started_time_{"updater_started_time",
kVariableModePoll};
@@ -108,6 +112,8 @@
"forced_update_requested", kVariableModeAsync};
FakeVariable<UpdateRestrictions> var_update_restrictions_{
"update_restrictions", kVariableModePoll};
+ FakeVariable<int64_t> var_test_update_check_interval_timeout_{
+ "test_update_check_interval_timeout", kVariableModePoll};
DISALLOW_COPY_AND_ASSIGN(FakeUpdaterProvider);
};
diff --git a/update_manager/next_update_check_policy_impl.cc b/update_manager/next_update_check_policy_impl.cc
index 6f9748e..0a78718 100644
--- a/update_manager/next_update_check_policy_impl.cc
+++ b/update_manager/next_update_check_policy_impl.cc
@@ -72,6 +72,11 @@
ec->GetValue(updater_provider->var_updater_started_time());
POLICY_CHECK_VALUE_AND_FAIL(updater_started_time, error);
+ // This value is used for testing only and it will get deleted after the first
+ // time it is read.
+ const int64_t* interval_timeout =
+ ec->GetValue(updater_provider->var_test_update_check_interval_timeout());
+
const Time* last_checked_time =
ec->GetValue(updater_provider->var_last_checked_time());
@@ -83,13 +88,21 @@
// If this is the first attempt, compute and return an initial value.
if (last_checked_time == nullptr ||
*last_checked_time < *updater_started_time) {
- *next_update_check = *updater_started_time +
- FuzzedInterval(&prng,
- constants.timeout_initial_interval,
- constants.timeout_regular_fuzz);
+ TimeDelta time_diff =
+ interval_timeout == nullptr
+ ? FuzzedInterval(&prng,
+ constants.timeout_initial_interval,
+ constants.timeout_regular_fuzz)
+ : TimeDelta::FromSeconds(*interval_timeout);
+ *next_update_check = *updater_started_time + time_diff;
return EvalStatus::kSucceeded;
}
+ if (interval_timeout != nullptr) {
+ *next_update_check =
+ *last_checked_time + TimeDelta::FromSeconds(*interval_timeout);
+ return EvalStatus::kSucceeded;
+ }
// Check whether the server is enforcing a poll interval; if not, this value
// will be zero.
const unsigned int* server_dictated_poll_interval =
diff --git a/update_manager/official_build_check_policy_impl.cc b/update_manager/official_build_check_policy_impl.cc
index 096f7bf..e80c09f 100644
--- a/update_manager/official_build_check_policy_impl.cc
+++ b/update_manager/official_build_check_policy_impl.cc
@@ -27,8 +27,16 @@
const bool* is_official_build_p =
ec->GetValue(state->system_provider()->var_is_official_build());
if (is_official_build_p != nullptr && !(*is_official_build_p)) {
- LOG(INFO) << "Unofficial build, blocking periodic update checks.";
- return EvalStatus::kAskMeAgainLater;
+ const int64_t* interval_timeout_p = ec->GetValue(
+ state->updater_provider()->var_test_update_check_interval_timeout());
+ // The |interval_timeout | is used for testing only to test periodic
+ // update checks on unofficial images.
+ if (interval_timeout_p == nullptr) {
+ LOG(INFO) << "Unofficial build, blocking periodic update checks.";
+ return EvalStatus::kAskMeAgainLater;
+ }
+ LOG(INFO) << "Unofficial build, but periodic update check interval "
+ << "timeout is defined, so update is not blocked.";
}
return EvalStatus::kContinue;
}
diff --git a/update_manager/policy.h b/update_manager/policy.h
index 844a4d0..9194c38 100644
--- a/update_manager/policy.h
+++ b/update_manager/policy.h
@@ -60,6 +60,8 @@
int rollback_allowed_milestones;
// A target channel, if so imposed by policy; otherwise, an empty string.
std::string target_channel;
+ // Specifies if the channel hint, e.g. LTS (Long Term Support) updates.
+ std::string lts_tag;
// Whether the allowed update is interactive (user-initiated) or periodic.
bool interactive;
diff --git a/update_manager/policy_utils.h b/update_manager/policy_utils.h
index 3204780..dc606f2 100644
--- a/update_manager/policy_utils.h
+++ b/update_manager/policy_utils.h
@@ -55,7 +55,6 @@
EvalStatus status =
(policy->*policy_method)(ec, state, error, result, args...);
if (status != EvalStatus::kContinue) {
- LOG(INFO) << "decision by " << policy->PolicyRequestName(policy_method);
return status;
}
}
diff --git a/update_manager/real_device_policy_provider.cc b/update_manager/real_device_policy_provider.cc
index 781e2ac..0aaf20e 100644
--- a/update_manager/real_device_policy_provider.cc
+++ b/update_manager/real_device_policy_provider.cc
@@ -104,9 +104,10 @@
}
template <typename T>
-void RealDevicePolicyProvider::UpdateVariable(AsyncCopyVariable<T>* var,
- bool (DevicePolicy::*getter)(T*)
- const) {
+void RealDevicePolicyProvider::UpdateVariable(
+ AsyncCopyVariable<T>* var,
+ // NOLINTNEXTLINE(readability/casting)
+ bool (DevicePolicy::*getter)(T*) const) {
T new_value;
if (policy_provider_->device_policy_is_loaded() &&
(policy_provider_->GetDevicePolicy().*getter)(&new_value)) {
@@ -208,6 +209,21 @@
return true;
}
+bool RealDevicePolicyProvider::ConvertChannelDowngradeBehavior(
+ ChannelDowngradeBehavior* channel_downgrade_behavior) const {
+ int behavior;
+ if (!policy_provider_->GetDevicePolicy().GetChannelDowngradeBehavior(
+ &behavior)) {
+ return false;
+ }
+ if (behavior < static_cast<int>(ChannelDowngradeBehavior::kFirstValue) ||
+ behavior > static_cast<int>(ChannelDowngradeBehavior::kLastValue)) {
+ return false;
+ }
+ *channel_downgrade_behavior = static_cast<ChannelDowngradeBehavior>(behavior);
+ return true;
+}
+
void RealDevicePolicyProvider::RefreshDevicePolicy() {
if (!policy_provider_->Reload()) {
LOG(INFO) << "No device policies/settings present.";
@@ -219,6 +235,7 @@
UpdateVariable(&var_release_channel_, &DevicePolicy::GetReleaseChannel);
UpdateVariable(&var_release_channel_delegated_,
&DevicePolicy::GetReleaseChannelDelegated);
+ UpdateVariable(&var_release_lts_tag_, &DevicePolicy::GetReleaseLtsTag);
UpdateVariable(&var_update_disabled_, &DevicePolicy::GetUpdateDisabled);
UpdateVariable(&var_target_version_prefix_,
&DevicePolicy::GetTargetVersionPrefix);
@@ -245,6 +262,10 @@
&DevicePolicy::GetAutoLaunchedKioskAppId);
UpdateVariable(&var_disallowed_time_intervals_,
&RealDevicePolicyProvider::ConvertDisallowedTimeIntervals);
+ UpdateVariable(&var_channel_downgrade_behavior_,
+ &RealDevicePolicyProvider::ConvertChannelDowngradeBehavior);
+ UpdateVariable(&var_device_minimum_version_,
+ &DevicePolicy::GetHighestDeviceMinimumVersion);
}
} // namespace chromeos_update_manager
diff --git a/update_manager/real_device_policy_provider.h b/update_manager/real_device_policy_provider.h
index 9da052d..ebda8fd 100644
--- a/update_manager/real_device_policy_provider.h
+++ b/update_manager/real_device_policy_provider.h
@@ -64,6 +64,10 @@
return &var_release_channel_delegated_;
}
+ Variable<std::string>* var_release_lts_tag() override {
+ return &var_release_lts_tag_;
+ }
+
Variable<bool>* var_update_disabled() override {
return &var_update_disabled_;
}
@@ -109,6 +113,15 @@
return &var_disallowed_time_intervals_;
}
+ Variable<ChannelDowngradeBehavior>* var_channel_downgrade_behavior()
+ override {
+ return &var_channel_downgrade_behavior_;
+ }
+
+ Variable<base::Version>* var_device_minimum_version() override {
+ return &var_device_minimum_version_;
+ }
+
private:
FRIEND_TEST(UmRealDevicePolicyProviderTest, RefreshScheduledTest);
FRIEND_TEST(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded);
@@ -170,6 +183,11 @@
// devices do not have an owner).
bool ConvertHasOwner(bool* has_owner) const;
+ // Wrapper for |DevicePolicy::GetChannelDowngradeBehavior| that converts the
+ // result to |ChannelDowngradeBehavior|.
+ bool ConvertChannelDowngradeBehavior(
+ ChannelDowngradeBehavior* channel_downgrade_behavior) const;
+
// Used for fetching information about the device policy.
policy::PolicyProvider* policy_provider_;
@@ -191,6 +209,7 @@
AsyncCopyVariable<std::string> var_release_channel_{"release_channel"};
AsyncCopyVariable<bool> var_release_channel_delegated_{
"release_channel_delegated"};
+ AsyncCopyVariable<std::string> var_release_lts_tag_{"release_lts_tag"};
AsyncCopyVariable<bool> var_update_disabled_{"update_disabled"};
AsyncCopyVariable<std::string> var_target_version_prefix_{
"target_version_prefix"};
@@ -211,6 +230,10 @@
"update_time_restrictions"};
AsyncCopyVariable<std::string> var_auto_launched_kiosk_app_id_{
"auto_launched_kiosk_app_id"};
+ AsyncCopyVariable<ChannelDowngradeBehavior> var_channel_downgrade_behavior_{
+ "channel_downgrade_behavior"};
+ AsyncCopyVariable<base::Version> var_device_minimum_version_{
+ "device_minimum_version"};
DISALLOW_COPY_AND_ASSIGN(RealDevicePolicyProvider);
};
diff --git a/update_manager/real_device_policy_provider_unittest.cc b/update_manager/real_device_policy_provider_unittest.cc
index 84debd1..4699ad1 100644
--- a/update_manager/real_device_policy_provider_unittest.cc
+++ b/update_manager/real_device_policy_provider_unittest.cc
@@ -177,6 +177,7 @@
UmTestUtils::ExpectVariableNotSet(provider_->var_release_channel());
UmTestUtils::ExpectVariableNotSet(provider_->var_release_channel_delegated());
+ UmTestUtils::ExpectVariableNotSet(provider_->var_release_lts_tag());
UmTestUtils::ExpectVariableNotSet(provider_->var_update_disabled());
UmTestUtils::ExpectVariableNotSet(provider_->var_target_version_prefix());
UmTestUtils::ExpectVariableNotSet(
@@ -194,6 +195,8 @@
UmTestUtils::ExpectVariableNotSet(
provider_->var_auto_launched_kiosk_app_id());
UmTestUtils::ExpectVariableNotSet(provider_->var_disallowed_time_intervals());
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_channel_downgrade_behavior());
}
TEST_F(UmRealDevicePolicyProviderTest, ValuesUpdated) {
@@ -376,4 +379,70 @@
provider_->var_disallowed_time_intervals());
}
+TEST_F(UmRealDevicePolicyProviderTest, ChannelDowngradeBehaviorConverted) {
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetChannelDowngradeBehavior(_))
+#if USE_DBUS
+ .Times(2)
+#else
+ .Times(1)
+#endif // USE_DBUS
+ .WillRepeatedly(DoAll(SetArgPointee<0>(static_cast<int>(
+ ChannelDowngradeBehavior::kRollback)),
+ Return(true)));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableHasValue(
+ ChannelDowngradeBehavior::kRollback,
+ provider_->var_channel_downgrade_behavior());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, ChannelDowngradeBehaviorTooSmall) {
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetChannelDowngradeBehavior(_))
+#if USE_DBUS
+ .Times(2)
+#else
+ .Times(1)
+#endif // USE_DBUS
+ .WillRepeatedly(DoAll(SetArgPointee<0>(-1), Return(true)));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_channel_downgrade_behavior());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, ChannelDowngradeBehaviorTooLarge) {
+ SetUpExistentDevicePolicy();
+ EXPECT_CALL(mock_device_policy_, GetChannelDowngradeBehavior(_))
+#if USE_DBUS
+ .Times(2)
+#else
+ .Times(1)
+#endif // USE_DBUS
+ .WillRepeatedly(DoAll(SetArgPointee<0>(10), Return(true)));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_channel_downgrade_behavior());
+}
+
+TEST_F(UmRealDevicePolicyProviderTest, DeviceMinimumVersionPolicySet) {
+ SetUpExistentDevicePolicy();
+
+ base::Version device_minimum_version("13315.60.12");
+
+ EXPECT_CALL(mock_device_policy_, GetHighestDeviceMinimumVersion(_))
+ .WillRepeatedly(
+ DoAll(SetArgPointee<0>(device_minimum_version), Return(true)));
+ EXPECT_TRUE(provider_->Init());
+ loop_.RunOnce(false);
+
+ UmTestUtils::ExpectVariableHasValue(device_minimum_version,
+ provider_->var_device_minimum_version());
+}
+
} // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.cc b/update_manager/real_updater_provider.cc
index 1f9af0d..1548d57 100644
--- a/update_manager/real_updater_provider.cc
+++ b/update_manager/real_updater_provider.cc
@@ -18,6 +18,7 @@
#include <inttypes.h>
+#include <algorithm>
#include <string>
#include <base/bind.h>
@@ -441,6 +442,46 @@
DISALLOW_COPY_AND_ASSIGN(UpdateRestrictionsVariable);
};
+// A variable class for reading timeout interval prefs value.
+class TestUpdateCheckIntervalTimeoutVariable : public Variable<int64_t> {
+ public:
+ TestUpdateCheckIntervalTimeoutVariable(
+ const string& name, chromeos_update_engine::PrefsInterface* prefs)
+ : Variable<int64_t>(name, kVariableModePoll),
+ prefs_(prefs),
+ read_count_(0) {
+ SetMissingOk();
+ }
+ ~TestUpdateCheckIntervalTimeoutVariable() = default;
+
+ private:
+ const int64_t* GetValue(TimeDelta /* timeout */,
+ string* /* errmsg */) override {
+ auto key = chromeos_update_engine::kPrefsTestUpdateCheckIntervalTimeout;
+ int64_t result;
+ if (prefs_ && prefs_->Exists(key) && prefs_->GetInt64(key, &result)) {
+ // This specific value is used for testing only. So it should not be kept
+ // around and should be deleted after a few reads.
+ if (++read_count_ > 5)
+ prefs_->Delete(key);
+
+ // Limit the timeout interval to 10 minutes so it is not abused if it is
+ // seen on official images.
+ return new int64_t(std::min(result, static_cast<int64_t>(10 * 60)));
+ }
+ return nullptr;
+ }
+
+ chromeos_update_engine::PrefsInterface* prefs_;
+
+ // Counts how many times this variable is read. This is used to delete the
+ // underlying file defining the variable after a certain number of reads in
+ // order to prevent any abuse of this variable.
+ int read_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestUpdateCheckIntervalTimeoutVariable);
+};
+
// RealUpdaterProvider methods.
RealUpdaterProvider::RealUpdaterProvider(SystemState* system_state)
@@ -474,6 +515,9 @@
"server_dictated_poll_interval", system_state_)),
var_forced_update_requested_(new ForcedUpdateRequestedVariable(
"forced_update_requested", system_state_)),
- var_update_restrictions_(new UpdateRestrictionsVariable(
- "update_restrictions", system_state_)) {}
+ var_update_restrictions_(
+ new UpdateRestrictionsVariable("update_restrictions", system_state_)),
+ var_test_update_check_interval_timeout_(
+ new TestUpdateCheckIntervalTimeoutVariable(
+ "test_update_check_interval_timeout", system_state_->prefs())) {}
} // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.h b/update_manager/real_updater_provider.h
index 1b46895..0819357 100644
--- a/update_manager/real_updater_provider.h
+++ b/update_manager/real_updater_provider.h
@@ -94,6 +94,10 @@
return var_update_restrictions_.get();
}
+ Variable<int64_t>* var_test_update_check_interval_timeout() override {
+ return var_test_update_check_interval_timeout_.get();
+ }
+
private:
// A pointer to the update engine's system state aggregator.
chromeos_update_engine::SystemState* system_state_;
@@ -114,6 +118,7 @@
std::unique_ptr<Variable<unsigned int>> var_server_dictated_poll_interval_;
std::unique_ptr<Variable<UpdateRequestStatus>> var_forced_update_requested_;
std::unique_ptr<Variable<UpdateRestrictions>> var_update_restrictions_;
+ std::unique_ptr<Variable<int64_t>> var_test_update_check_interval_timeout_;
DISALLOW_COPY_AND_ASSIGN(RealUpdaterProvider);
};
diff --git a/update_manager/real_updater_provider_unittest.cc b/update_manager/real_updater_provider_unittest.cc
index fb7a763..f0804c4 100644
--- a/update_manager/real_updater_provider_unittest.cc
+++ b/update_manager/real_updater_provider_unittest.cc
@@ -445,4 +445,29 @@
UmTestUtils::ExpectVariableHasValue(UpdateRestrictions::kNone,
provider_->var_update_restrictions());
}
+
+TEST_F(UmRealUpdaterProviderTest, TestUpdateCheckIntervalTimeout) {
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_test_update_check_interval_timeout());
+ fake_prefs_.SetInt64(
+ chromeos_update_engine::kPrefsTestUpdateCheckIntervalTimeout, 1);
+ UmTestUtils::ExpectVariableHasValue(
+ static_cast<int64_t>(1),
+ provider_->var_test_update_check_interval_timeout());
+
+ // Make sure the value does not exceed a threshold of 10 minutes.
+ fake_prefs_.SetInt64(
+ chromeos_update_engine::kPrefsTestUpdateCheckIntervalTimeout, 11 * 60);
+ // The next 5 reads should return valid values.
+ for (int i = 0; i < 5; ++i)
+ UmTestUtils::ExpectVariableHasValue(
+ static_cast<int64_t>(10 * 60),
+ provider_->var_test_update_check_interval_timeout());
+
+ // Just to make sure it is not cached anywhere and deleted. The variable is
+ // allowd to be read 6 times.
+ UmTestUtils::ExpectVariableNotSet(
+ provider_->var_test_update_check_interval_timeout());
+}
+
} // namespace chromeos_update_manager
diff --git a/update_manager/rollback_prefs.h b/update_manager/rollback_prefs.h
index 9567701..6cbc447 100644
--- a/update_manager/rollback_prefs.h
+++ b/update_manager/rollback_prefs.h
@@ -35,6 +35,19 @@
kMaxValue = 4
};
+// Whether the device should do rollback and powerwash on channel downgrade.
+// Matches chrome_device_policy.proto's
+// |AutoUpdateSettingsProto::ChannelDowngradeBehavior|.
+enum class ChannelDowngradeBehavior {
+ kUnspecified = 0,
+ kWaitForVersionToCatchUp = 1,
+ kRollback = 2,
+ kAllowUserToConfigure = 3,
+ // These values must be kept up to date.
+ kFirstValue = kUnspecified,
+ kLastValue = kAllowUserToConfigure
+};
+
} // namespace chromeos_update_manager
#endif // UPDATE_ENGINE_UPDATE_MANAGER_ROLLBACK_PREFS_H_
diff --git a/update_manager/update_manager-inl.h b/update_manager/update_manager-inl.h
index a1d172d..550642c 100644
--- a/update_manager/update_manager-inl.h
+++ b/update_manager/update_manager-inl.h
@@ -49,7 +49,6 @@
ec->ResetEvaluation();
const std::string policy_name = policy_->PolicyRequestName(policy_method);
- LOG(INFO) << policy_name << ": START";
// First try calling the actual policy.
std::string error;
@@ -71,8 +70,6 @@
}
}
- LOG(INFO) << policy_name << ": END";
-
return status;
}
diff --git a/update_manager/updater_provider.h b/update_manager/updater_provider.h
index 81ffb41..86af1c8 100644
--- a/update_manager/updater_provider.h
+++ b/update_manager/updater_provider.h
@@ -116,6 +116,10 @@
// for all updates.
virtual Variable<UpdateRestrictions>* var_update_restrictions() = 0;
+ // A variable that returns the number of seconds for the first update check to
+ // happen.
+ virtual Variable<int64_t>* var_test_update_check_interval_timeout() = 0;
+
protected:
UpdaterProvider() {}
diff --git a/update_manager/variable.h b/update_manager/variable.h
index 6c7d350..9ac7dae 100644
--- a/update_manager/variable.h
+++ b/update_manager/variable.h
@@ -83,6 +83,10 @@
// variable. In other case, it returns 0.
base::TimeDelta GetPollInterval() const { return poll_interval_; }
+ // Returns true, if the value for this variable is expected to be missing
+ // sometimes so we can avoid printing confusing error logs.
+ bool IsMissingOk() const { return missing_ok_; }
+
// Adds and removes observers for value changes on the variable. This only
// works for kVariableAsync variables since the other modes don't track value
// changes. Adding the same observer twice has no effect.
@@ -115,6 +119,8 @@
poll_interval_ = poll_interval;
}
+ void SetMissingOk() { missing_ok_ = true; }
+
// Calls ValueChanged on all the observers.
void NotifyValueChanged() {
// Fire all the observer methods from the main loop as single call. In order
@@ -140,7 +146,8 @@
: name_(name),
mode_(mode),
poll_interval_(mode == kVariableModePoll ? poll_interval
- : base::TimeDelta()) {}
+ : base::TimeDelta()),
+ missing_ok_(false) {}
void OnValueChangedNotification() {
// A ValueChanged() method can change the list of observers, for example
@@ -174,6 +181,9 @@
// The list of value changes observers.
std::list<BaseVariable::ObserverInterface*> observer_list_;
+ // Defines whether this variable is expected to have no value.
+ bool missing_ok_;
+
DISALLOW_COPY_AND_ASSIGN(BaseVariable);
};