Merge commit '51871ea530e88c90cd761a228f96372cae96abeb' into HEAD
Change-Id: Ie83699c8947c9260c02a2b9653d75bb0dd06468c
diff --git a/Android.mk b/Android.mk
index cc06643..6a23168 100644
--- a/Android.mk
+++ b/Android.mk
@@ -14,6 +14,8 @@
# limitations under the License.
#
+ifneq ($(TARGET_BUILD_PDK),true)
+
LOCAL_PATH := $(my-dir)
# Default values for the USE flags. Override these USE flags from your product
@@ -82,6 +84,7 @@
generated_sources_dir := $(call local-generated-sources-dir)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(generated_sources_dir)/proto/system
LOCAL_SRC_FILES := $(ue_update_metadata_protos_src_files)
+LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_HOST_STATIC_LIBRARY)
# Build for the target.
@@ -91,6 +94,7 @@
generated_sources_dir := $(call local-generated-sources-dir)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(generated_sources_dir)/proto/system
LOCAL_SRC_FILES := $(ue_update_metadata_protos_src_files)
+LOCAL_CFLAGS := -Wall -Werror
include $(BUILD_STATIC_LIBRARY)
# libpayload_consumer (type: static_library)
@@ -101,6 +105,7 @@
libxz \
libbz \
libbspatch \
+ libbrotli \
$(ue_update_metadata_protos_exported_static_libraries)
ue_libpayload_consumer_exported_shared_libraries := \
libcrypto \
@@ -466,7 +471,7 @@
LOCAL_SRC_FILES := \
boot_control_recovery.cc \
hardware_android.cc \
- metrics_reporter_android.cc \
+ metrics_reporter_stub.cc \
metrics_utils.cc \
network_selector_stub.cc \
proxy_resolver.cc \
@@ -599,6 +604,7 @@
libbsdiff \
libdivsufsort \
libdivsufsort64 \
+ libbrotli \
libpayload_consumer \
liblzma \
update_metadata-protos \
@@ -1019,3 +1025,5 @@
simg2img
include $(BUILD_PREBUILT)
endif # HOST_OS == linux
+
+endif # ifneq ($(TARGET_BUILD_PDK),true)
diff --git a/common/constants.cc b/common/constants.cc
index c0a6e27..5941c93 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -57,6 +57,7 @@
const char kPrefsP2PFirstAttemptTimestamp[] = "p2p-first-attempt-timestamp";
const char kPrefsP2PNumAttempts[] = "p2p-num-attempts";
const char kPrefsPayloadAttemptNumber[] = "payload-attempt-number";
+const char kPrefsPostInstallSucceeded[] = "post-install-succeeded";
const char kPrefsPreviousVersion[] = "previous-version";
const char kPrefsResumedUpdateFailures[] = "resumed-update-failures";
const char kPrefsRollbackVersion[] = "rollback-version";
@@ -103,5 +104,12 @@
// This can be used to zero-rate OTA traffic by sending it over the correct
// network.
const char kPayloadPropertyNetworkId[] = "NETWORK_ID";
+// Set "SWITCH_SLOT_ON_REBOOT=0" to skip marking the updated partitions active.
+// The default is 1 (always switch slot if update succeeded).
+const char kPayloadPropertySwitchSlotOnReboot[] = "SWITCH_SLOT_ON_REBOOT";
+// Set "RUN_POST_INSTALL=0" to skip running post install, this will only be
+// honored if we're resuming an update and post install has already succeeded.
+// The default is 1 (always run post install).
+const char kPayloadPropertyRunPostInstall[] = "RUN_POST_INSTALL";
} // namespace chromeos_update_engine
diff --git a/common/constants.h b/common/constants.h
index 776e726..fefd08c 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -59,6 +59,7 @@
extern const char kPrefsP2PFirstAttemptTimestamp[];
extern const char kPrefsP2PNumAttempts[];
extern const char kPrefsPayloadAttemptNumber[];
+extern const char kPrefsPostInstallSucceeded[];
extern const char kPrefsPreviousVersion[];
extern const char kPrefsResumedUpdateFailures[];
extern const char kPrefsRollbackVersion[];
@@ -96,6 +97,8 @@
extern const char kPayloadPropertyUserAgent[];
extern const char kPayloadPropertyPowerwash[];
extern const char kPayloadPropertyNetworkId[];
+extern const char kPayloadPropertySwitchSlotOnReboot[];
+extern const char kPayloadPropertyRunPostInstall[];
// A download source is any combination of protocol and server (that's of
// interest to us when looking at UMA metrics) using which we may download
diff --git a/common/error_code.h b/common/error_code.h
index e08ec46..adae391 100644
--- a/common/error_code.h
+++ b/common/error_code.h
@@ -73,6 +73,9 @@
kFilesystemVerifierError = 47,
kUserCanceled = 48,
kNonCriticalUpdateInOOBE = 49,
+ // kOmahaUpdateIgnoredOverCellular = 50,
+ // kPayloadTimestampError = 51,
+ kUpdatedButNotActive = 52,
// VERY IMPORTANT! When adding new error codes:
//
diff --git a/common/error_code_utils.cc b/common/error_code_utils.cc
index ad4aeeb..983d004 100644
--- a/common/error_code_utils.cc
+++ b/common/error_code_utils.cc
@@ -144,8 +144,10 @@
return "ErrorCode::kUserCanceled";
case ErrorCode::kNonCriticalUpdateInOOBE:
return "ErrorCode::kNonCriticalUpdateInOOBE";
- // Don't add a default case to let the compiler warn about newly added
- // error codes which should be added here.
+ case ErrorCode::kUpdatedButNotActive:
+ return "ErrorCode::kUpdatedButNotActive";
+ // Don't add a default case to let the compiler warn about newly added
+ // error codes which should be added here.
}
return "Unknown error: " + base::UintToString(static_cast<unsigned>(code));
diff --git a/common/test_utils.cc b/common/test_utils.cc
index fb22c80..e410283 100644
--- a/common/test_utils.cc
+++ b/common/test_utils.cc
@@ -24,6 +24,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
+#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <sys/types.h>
@@ -201,6 +202,13 @@
device_info.lo_file_name[LO_NAME_SIZE - 1] = '\0';
TEST_AND_RETURN_FALSE_ERRNO(
ioctl(loop_device_fd, LOOP_SET_STATUS64, &device_info) == 0);
+ if (writable) {
+ // Make sure loop device isn't read only.
+ int ro = 0;
+ if (ioctl(loop_device_fd, BLKROSET, &ro) != 0) {
+ PLOG(WARNING) << "Failed to mark loop device writable.";
+ }
+ }
return true;
}
diff --git a/common/test_utils.h b/common/test_utils.h
index ba9f5f2..ddb3d34 100644
--- a/common/test_utils.h
+++ b/common/test_utils.h
@@ -31,6 +31,7 @@
#include <base/callback.h>
#include <base/files/file_path.h>
#include <base/files/scoped_temp_dir.h>
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "update_engine/common/action.h"
@@ -101,6 +102,11 @@
void FillWithData(brillo::Blob* buffer);
+// Compare the value of native array for download source parameter.
+MATCHER_P(DownloadSourceMatcher, source_array, "") {
+ return std::equal(source_array, source_array + kNumDownloadSources, arg);
+}
+
// Class to unmount FS when object goes out of scope
class ScopedFilesystemUnmounter {
public:
diff --git a/image_properties.h b/image_properties.h
index 4f94eeb..2d1a408 100644
--- a/image_properties.h
+++ b/image_properties.h
@@ -41,6 +41,9 @@
// The system version of this image.
std::string system_version;
+ // The version of all product components in key values pairs.
+ std::string product_components;
+
// A unique string that identifies this build. Normally a combination of the
// the version, signing keys and build target.
std::string build_fingerprint;
diff --git a/image_properties_android.cc b/image_properties_android.cc
index 886a6b6..608bca7 100644
--- a/image_properties_android.cc
+++ b/image_properties_android.cc
@@ -27,6 +27,7 @@
#include "update_engine/common/constants.h"
#include "update_engine/common/platform_constants.h"
#include "update_engine/common/prefs_interface.h"
+#include "update_engine/common/utils.h"
#include "update_engine/system_state.h"
using android::base::GetProperty;
@@ -42,6 +43,10 @@
const char kSystemId[] = "system_id";
const char kSystemVersion[] = "system_version";
+// The path to the product_components file which stores the version of each
+// components in OEM partition.
+const char kProductComponentsPath[] = "/oem/os-release.d/product_components";
+
// Prefs used to store the target channel and powerwash settings.
const char kPrefsImgPropChannelName[] = "img-prop-channel-name";
const char kPrefsImgPropPowerwashAllowed[] = "img-prop-powerwash-allowed";
@@ -97,6 +102,8 @@
result.version = GetStringWithDefault(osrelease, kProductVersion, "0.0.0.0");
result.system_version =
GetStringWithDefault(osrelease, kSystemVersion, "0.0.0.0");
+ // Can't read it with OsReleaseReader because it has multiple lines.
+ utils::ReadFile(kProductComponentsPath, &result.product_components);
result.board = GetProperty(kPropProductName, "brillo");
result.build_fingerprint = GetProperty(kPropBuildFingerprint, "none");
diff --git a/main.cc b/main.cc
index 91805ae..0b96307 100644
--- a/main.cc
+++ b/main.cc
@@ -89,7 +89,7 @@
string log_file;
if (log_to_file) {
#ifdef __ANDROID__
- log_file = "/data/misc/update_engine/update_engine.log";
+ log_file = "/data/misc/update_engine_log/update_engine.log";
log_settings.delete_old = logging::DELETE_OLD_LOG_FILE;
#else
log_file = SetupLogFile("/var/log");
@@ -98,6 +98,12 @@
log_settings.log_file = log_file.c_str();
}
logging::InitLogging(log_settings);
+
+#ifdef __ANDROID__
+ // The log file will have AID_LOG as group ID; this GID is inherited from the
+ // parent directory "/data/misc/update_engine_log" which sets the SGID bit.
+ chmod(log_file.c_str(), 0640);
+#endif
}
} // namespace
diff --git a/metrics_constants.h b/metrics_constants.h
index f6d0c74..abec2ad 100644
--- a/metrics_constants.h
+++ b/metrics_constants.h
@@ -95,6 +95,8 @@
kPostInstallFailed, // The postinstall step failed.
kAbnormalTermination, // The attempt ended abnormally.
kUpdateCanceled, // Update canceled by the user.
+ kUpdateSucceededNotActive, // Update succeeded but the new slot is not
+ // active.
kNumConstants,
diff --git a/metrics_reporter_android.cc b/metrics_reporter_android.cc
index 4a57918..26aa057 100644
--- a/metrics_reporter_android.cc
+++ b/metrics_reporter_android.cc
@@ -16,33 +16,143 @@
#include "update_engine/metrics_reporter_android.h"
-#ifndef _UE_SIDELOAD
+#include <memory>
+#include <string>
+
#include <metricslogger/metrics_logger.h>
-#endif // _UE_SIDELOAD
+
+#include "update_engine/common/constants.h"
+
+namespace {
+void LogHistogram(const std::string& metrics, int value) {
+ android::metricslogger::LogHistogram(metrics, value);
+ LOG(INFO) << "uploading " << value << "to histogram for metric " << metrics;
+}
+} // namespace
namespace chromeos_update_engine {
namespace metrics {
-#ifndef _UE_SIDELOAD
-const char kMetricsUpdateEngineErrorCode[] = "ota_update_engine_error_code";
-#endif
+// The histograms are defined in:
+// depot/google3/analysis/uma/configs/clearcut/TRON/histograms.xml
+constexpr char kMetricsUpdateEngineAttemptNumber[] =
+ "ota_update_engine_attempt_count";
+constexpr char kMetricsUpdateEngineAttemptResult[] =
+ "ota_update_engine_attempt_result";
+constexpr char kMetricsUpdateEngineAttemptDurationInMinutes[] =
+ "ota_update_engine_attempt_duration_boottime_in_minutes";
+constexpr char kMetricsUpdateEngineAttemptDurationUptimeInMinutes[] =
+ "ota_update_engine_attempt_duration_monotonic_in_minutes";
+constexpr char kMetricsUpdateEngineAttemptErrorCode[] =
+ "ota_update_engine_attempt_error_code";
+constexpr char kMetricsUpdateEngineAttemptPayloadSizeMiB[] =
+ "ota_update_engine_attempt_payload_size_mib";
+constexpr char kMetricsUpdateEngineAttemptPayloadType[] =
+ "ota_update_engine_attempt_payload_type";
+constexpr char kMetricsUpdateEngineAttemptCurrentBytesDownloadedMiB[] =
+ "ota_update_engine_attempt_current_bytes_downloaded_mib";
+
+constexpr char kMetricsUpdateEngineSuccessfulUpdateAttemptCount[] =
+ "ota_update_engine_successful_update_attempt_count";
+constexpr char kMetricsUpdateEngineSuccessfulUpdateTotalDurationInMinutes[] =
+ "ota_update_engine_successful_update_total_duration_in_minutes";
+constexpr char kMetricsUpdateEngineSuccessfulUpdatePayloadSizeMiB[] =
+ "ota_update_engine_successful_update_payload_size_mib";
+constexpr char kMetricsUpdateEngineSuccessfulUpdatePayloadType[] =
+ "ota_update_engine_successful_update_payload_type";
+constexpr char kMetricsUpdateEngineSuccessfulUpdateRebootCount[] =
+ "ota_update_engine_successful_update_reboot_count";
+constexpr char kMetricsUpdateEngineSuccessfulUpdateTotalBytesDownloadedMiB[] =
+ "ota_update_engine_successful_update_total_bytes_downloaded_mib";
+constexpr char
+ kMetricsUpdateEngineSuccessfulUpdateDownloadOverheadPercentage[] =
+ "ota_update_engine_successful_update_download_overhead_percentage";
+
+std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter() {
+ return std::make_unique<MetricsReporterAndroid>();
+}
+
} // namespace metrics
void MetricsReporterAndroid::ReportUpdateAttemptMetrics(
SystemState* /* system_state */,
- int /* attempt_number */,
- PayloadType /* payload_type */,
- base::TimeDelta /* duration */,
- base::TimeDelta /* duration_uptime */,
- int64_t /* payload_size */,
- metrics::AttemptResult /* attempt_result */,
+ int attempt_number,
+ PayloadType payload_type,
+ base::TimeDelta duration,
+ base::TimeDelta duration_uptime,
+ int64_t payload_size,
+ metrics::AttemptResult attempt_result,
ErrorCode error_code) {
-// No need to log histogram under sideload mode.
-#ifndef _UE_SIDELOAD
- android::metricslogger::LogHistogram(metrics::kMetricsUpdateEngineErrorCode,
- static_cast<int>(error_code));
-#endif
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptNumber, attempt_number);
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptPayloadType,
+ static_cast<int>(payload_type));
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptDurationInMinutes,
+ duration.InMinutes());
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptDurationUptimeInMinutes,
+ duration_uptime.InMinutes());
+
+ int64_t payload_size_mib = payload_size / kNumBytesInOneMiB;
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptPayloadSizeMiB,
+ payload_size_mib);
+
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptResult,
+ static_cast<int>(attempt_result));
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptErrorCode,
+ static_cast<int>(error_code));
+}
+
+void MetricsReporterAndroid::ReportUpdateAttemptDownloadMetrics(
+ int64_t payload_bytes_downloaded,
+ int64_t /* payload_download_speed_bps */,
+ DownloadSource /* download_source */,
+ metrics::DownloadErrorCode /* payload_download_error_code */,
+ metrics::ConnectionType /* connection_type */) {
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptCurrentBytesDownloadedMiB,
+ payload_bytes_downloaded);
+}
+
+void MetricsReporterAndroid::ReportSuccessfulUpdateMetrics(
+ int attempt_count,
+ int /* updates_abandoned_count */,
+ PayloadType payload_type,
+ int64_t payload_size,
+ int64_t num_bytes_downloaded[kNumDownloadSources],
+ int download_overhead_percentage,
+ base::TimeDelta total_duration,
+ int reboot_count,
+ int /* url_switch_count */) {
+ LogHistogram(metrics::kMetricsUpdateEngineSuccessfulUpdateAttemptCount,
+ attempt_count);
+ LogHistogram(metrics::kMetricsUpdateEngineSuccessfulUpdatePayloadType,
+ static_cast<int>(payload_type));
+
+ int64_t payload_size_mib = payload_size / kNumBytesInOneMiB;
+ LogHistogram(metrics::kMetricsUpdateEngineSuccessfulUpdatePayloadSizeMiB,
+ payload_size_mib);
+
+ int64_t total_bytes_downloaded = 0;
+ for (size_t i = 0; i < kNumDownloadSources; i++) {
+ total_bytes_downloaded += num_bytes_downloaded[i] / kNumBytesInOneMiB;
+ }
+ LogHistogram(
+ metrics::kMetricsUpdateEngineSuccessfulUpdateTotalBytesDownloadedMiB,
+ total_bytes_downloaded);
+ LogHistogram(
+ metrics::kMetricsUpdateEngineSuccessfulUpdateDownloadOverheadPercentage,
+ download_overhead_percentage);
+
+ LogHistogram(
+ metrics::kMetricsUpdateEngineSuccessfulUpdateTotalDurationInMinutes,
+ total_duration.InMinutes());
+ LogHistogram(metrics::kMetricsUpdateEngineSuccessfulUpdateRebootCount,
+ reboot_count);
+}
+
+void MetricsReporterAndroid::ReportAbnormallyTerminatedUpdateAttemptMetrics() {
+ int attempt_result =
+ static_cast<int>(metrics::AttemptResult::kAbnormalTermination);
+ LogHistogram(metrics::kMetricsUpdateEngineAttemptResult, attempt_result);
}
}; // namespace chromeos_update_engine
diff --git a/metrics_reporter_android.h b/metrics_reporter_android.h
index b83e651..ee94e43 100644
--- a/metrics_reporter_android.h
+++ b/metrics_reporter_android.h
@@ -55,9 +55,9 @@
int64_t payload_download_speed_bps,
DownloadSource download_source,
metrics::DownloadErrorCode payload_download_error_code,
- metrics::ConnectionType connection_type) override {}
+ metrics::ConnectionType connection_type) override;
- void ReportAbnormallyTerminatedUpdateAttemptMetrics() override {}
+ void ReportAbnormallyTerminatedUpdateAttemptMetrics() override;
void ReportSuccessfulUpdateMetrics(
int attempt_count,
@@ -68,7 +68,7 @@
int download_overhead_percentage,
base::TimeDelta total_duration,
int reboot_count,
- int url_switch_count) override {}
+ int url_switch_count) override;
void ReportCertificateCheckMetrics(ServerToCheck server_to_check,
CertificateCheckResult result) override {}
diff --git a/metrics_reporter_interface.h b/metrics_reporter_interface.h
index bc9d387..2c7ce5b 100644
--- a/metrics_reporter_interface.h
+++ b/metrics_reporter_interface.h
@@ -17,6 +17,8 @@
#ifndef UPDATE_ENGINE_METRICS_REPORTER_INTERFACE_H_
#define UPDATE_ENGINE_METRICS_REPORTER_INTERFACE_H_
+#include <memory>
+
#include <base/time/time.h>
#include "update_engine/common/constants.h"
@@ -29,6 +31,12 @@
enum class ServerToCheck;
enum class CertificateCheckResult;
+namespace metrics {
+
+std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter();
+
+} // namespace metrics
+
class MetricsReporterInterface {
public:
virtual ~MetricsReporterInterface() = default;
diff --git a/metrics_reporter_omaha.cc b/metrics_reporter_omaha.cc
index 5f24cbf..0397b83 100644
--- a/metrics_reporter_omaha.cc
+++ b/metrics_reporter_omaha.cc
@@ -112,6 +112,10 @@
"UpdateEngine.InstallDateProvisioningSource";
const char kMetricTimeToRebootMinutes[] = "UpdateEngine.TimeToRebootMinutes";
+std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter() {
+ return std::make_unique<MetricsReporterOmaha>();
+}
+
} // namespace metrics
MetricsReporterOmaha::MetricsReporterOmaha()
diff --git a/metrics_reporter_stub.cc b/metrics_reporter_stub.cc
new file mode 100644
index 0000000..81664a5
--- /dev/null
+++ b/metrics_reporter_stub.cc
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2017 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/metrics_reporter_stub.h"
+
+#include <memory>
+
+namespace chromeos_update_engine {
+
+namespace metrics {
+
+std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter() {
+ return std::make_unique<MetricsReporterStub>();
+}
+
+} // namespace metrics
+
+} // namespace chromeos_update_engine
diff --git a/metrics_reporter_stub.h b/metrics_reporter_stub.h
new file mode 100644
index 0000000..d0f75ab
--- /dev/null
+++ b/metrics_reporter_stub.h
@@ -0,0 +1,88 @@
+//
+// Copyright (C) 2017 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_METRICS_REPORTER_STUB_H_
+#define UPDATE_ENGINE_METRICS_REPORTER_STUB_H_
+
+#include "update_engine/common/error_code.h"
+#include "update_engine/metrics_constants.h"
+#include "update_engine/metrics_reporter_interface.h"
+
+namespace chromeos_update_engine {
+
+class MetricsReporterStub : public MetricsReporterInterface {
+ public:
+ MetricsReporterStub() = default;
+
+ ~MetricsReporterStub() override = default;
+
+ void Initialize() override {}
+
+ void ReportRollbackMetrics(metrics::RollbackResult result) override {}
+
+ void ReportDailyMetrics(base::TimeDelta os_age) override {}
+
+ void ReportUpdateCheckMetrics(
+ SystemState* system_state,
+ metrics::CheckResult result,
+ metrics::CheckReaction reaction,
+ metrics::DownloadErrorCode download_error_code) override {}
+
+ void ReportUpdateAttemptMetrics(SystemState* system_state,
+ int attempt_number,
+ PayloadType payload_type,
+ base::TimeDelta duration,
+ base::TimeDelta duration_uptime,
+ int64_t payload_size,
+ metrics::AttemptResult attempt_result,
+ ErrorCode internal_error_code) override {}
+
+ void ReportUpdateAttemptDownloadMetrics(
+ int64_t payload_bytes_downloaded,
+ int64_t payload_download_speed_bps,
+ DownloadSource download_source,
+ metrics::DownloadErrorCode payload_download_error_code,
+ metrics::ConnectionType connection_type) override {}
+
+ void ReportAbnormallyTerminatedUpdateAttemptMetrics() override {}
+
+ void ReportSuccessfulUpdateMetrics(
+ int attempt_count,
+ int updates_abandoned_count,
+ PayloadType payload_type,
+ int64_t payload_size,
+ int64_t num_bytes_downloaded[kNumDownloadSources],
+ int download_overhead_percentage,
+ base::TimeDelta total_duration,
+ int reboot_count,
+ int url_switch_count) override {}
+
+ void ReportCertificateCheckMetrics(ServerToCheck server_to_check,
+ CertificateCheckResult result) override {}
+
+ void ReportFailedUpdateCount(int target_attempt) override {}
+
+ void ReportTimeToReboot(int time_to_reboot_minutes) override {}
+
+ void ReportInstallDateProvisioningSource(int source, int max) override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MetricsReporterStub);
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_METRICS_REPORTER_STUB_H_
diff --git a/metrics_utils.cc b/metrics_utils.cc
index 5cff293..7e6b20f 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -39,6 +39,9 @@
case ErrorCode::kSuccess:
return metrics::AttemptResult::kUpdateSucceeded;
+ case ErrorCode::kUpdatedButNotActive:
+ return metrics::AttemptResult::kUpdateSucceededNotActive;
+
case ErrorCode::kDownloadTransferError:
return metrics::AttemptResult::kPayloadDownloadError;
@@ -210,6 +213,7 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ case ErrorCode::kUpdatedButNotActive:
break;
// Special flags. These can't happen (we mask them out above) but
diff --git a/omaha_request_action.cc b/omaha_request_action.cc
index 7e41f94..4332702 100644
--- a/omaha_request_action.cc
+++ b/omaha_request_action.cc
@@ -31,6 +31,7 @@
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/time/time.h>
+#include <brillo/key_value_store.h>
#include <expat.h>
#include <metrics/metrics_library.h>
@@ -207,8 +208,17 @@
struct OmahaAppData {
string id;
string version;
+ string product_components;
};
+bool IsValidComponentID(const string& id) {
+ for (char c : id) {
+ if (!isalnum(c) && c != '-' && c != '_' && c != '.')
+ return false;
+ }
+ return true;
+}
+
// Returns an XML that corresponds to the entire <app> node of the Omaha
// request based on the given parameters.
string GetAppXml(const OmahaEvent* event,
@@ -276,11 +286,39 @@
XmlEncodeWithDefault(params->os_build_type(), "") + "\" ";
}
+ string product_components_args;
+ if (!app_data.product_components.empty()) {
+ brillo::KeyValueStore store;
+ if (store.LoadFromString(app_data.product_components)) {
+ for (const string& key : store.GetKeys()) {
+ if (!IsValidComponentID(key)) {
+ LOG(ERROR) << "Invalid component id: " << key;
+ continue;
+ }
+ string version;
+ if (!store.GetString(key, &version)) {
+ LOG(ERROR) << "Failed to get version for " << key
+ << " in product_components.";
+ continue;
+ }
+ product_components_args +=
+ base::StringPrintf("_%s.version=\"%s\" ",
+ key.c_str(),
+ XmlEncodeWithDefault(version, "").c_str());
+ }
+ } else {
+ LOG(ERROR) << "Failed to parse product_components:\n"
+ << app_data.product_components;
+ }
+ }
+
+ // clang-format off
string app_xml = " <app "
"appid=\"" + XmlEncodeWithDefault(app_data.id, "") + "\" " +
app_cohort_args +
app_versions +
app_channels +
+ product_components_args +
fingerprint_arg +
buildtype_arg +
"lang=\"" + XmlEncodeWithDefault(params->app_lang(), "en-US") + "\" " +
@@ -293,7 +331,7 @@
">\n" +
app_body +
" </app>\n";
-
+ // clang-format on
return app_xml;
}
@@ -319,8 +357,10 @@
int install_date_in_days,
SystemState* system_state) {
string os_xml = GetOsXml(params);
- OmahaAppData product_app = {.id = params->GetAppId(),
- .version = params->app_version()};
+ OmahaAppData product_app = {
+ .id = params->GetAppId(),
+ .version = params->app_version(),
+ .product_components = params->product_components()};
string app_xml = GetAppXml(event,
params,
product_app,
diff --git a/omaha_request_params.h b/omaha_request_params.h
index ba7f2c3..73edd6f 100644
--- a/omaha_request_params.h
+++ b/omaha_request_params.h
@@ -130,6 +130,9 @@
inline std::string system_version() const {
return image_props_.system_version;
}
+ inline std::string product_components() const {
+ return image_props_.product_components;
+ }
inline std::string current_channel() const {
return image_props_.current_channel;
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index d6ac16c..d384e45 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -24,6 +24,7 @@
#include <cstring>
#include <memory>
#include <string>
+#include <utility>
#include <vector>
#include <base/files/file_util.h>
@@ -975,8 +976,8 @@
for (uint64_t offset = 0; offset < length; offset += zeros.size()) {
uint64_t chunk_length = min(length - offset,
static_cast<uint64_t>(zeros.size()));
- TEST_AND_RETURN_FALSE(
- utils::PWriteAll(target_fd_, zeros.data(), chunk_length, start + offset));
+ TEST_AND_RETURN_FALSE(utils::PWriteAll(
+ target_fd_, zeros.data(), chunk_length, start + offset));
}
}
return true;
@@ -1152,8 +1153,8 @@
const uint64_t begin_byte =
end_byte - (block_size_ - operation.dst_length() % block_size_);
brillo::Blob zeros(end_byte - begin_byte);
- TEST_AND_RETURN_FALSE(
- utils::PWriteAll(target_fd_, zeros.data(), end_byte - begin_byte, begin_byte));
+ TEST_AND_RETURN_FALSE(utils::PWriteAll(
+ target_fd_, zeros.data(), end_byte - begin_byte, begin_byte));
}
return true;
}
@@ -1629,6 +1630,7 @@
prefs->SetInt64(kPrefsManifestMetadataSize, -1);
prefs->SetInt64(kPrefsManifestSignatureSize, -1);
prefs->SetInt64(kPrefsResumedUpdateFailures, 0);
+ prefs->Delete(kPrefsPostInstallSucceeded);
}
return true;
}
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index b0dff31..45112d6 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -87,7 +87,10 @@
<< ", url: " << download_url << payloads_str << partitions_str
<< ", hash_checks_mandatory: "
<< utils::ToString(hash_checks_mandatory)
- << ", powerwash_required: " << utils::ToString(powerwash_required);
+ << ", powerwash_required: " << utils::ToString(powerwash_required)
+ << ", switch_slot_on_reboot: "
+ << utils::ToString(switch_slot_on_reboot)
+ << ", run_post_install: " << utils::ToString(run_post_install);
}
bool InstallPlan::LoadPartitionsFromSlots(BootControlInterface* boot_control) {
diff --git a/payload_consumer/install_plan.h b/payload_consumer/install_plan.h
index 551f8c2..5cdfbc1 100644
--- a/payload_consumer/install_plan.h
+++ b/payload_consumer/install_plan.h
@@ -119,6 +119,14 @@
// False otherwise.
bool powerwash_required{false};
+ // True if the updated slot should be marked active on success.
+ // False otherwise.
+ bool switch_slot_on_reboot{true};
+
+ // True if the update should run its post-install step.
+ // False otherwise.
+ bool run_post_install{true};
+
// If not blank, a base-64 encoded representation of the PEM-encoded
// public key in the response.
std::string public_key_rsa;
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index 27a9ed6..cedecda 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -82,6 +82,11 @@
}
void PostinstallRunnerAction::PerformPartitionPostinstall() {
+ if (!install_plan_.run_post_install) {
+ LOG(INFO) << "Skipping post-install according to install plan.";
+ return CompletePostinstall(ErrorCode::kSuccess);
+ }
+
if (install_plan_.download_url.empty()) {
LOG(INFO) << "Skipping post-install during rollback";
return CompletePostinstall(ErrorCode::kSuccess);
@@ -331,15 +336,21 @@
void PostinstallRunnerAction::CompletePostinstall(ErrorCode error_code) {
// We only attempt to mark the new slot as active if all the postinstall
// steps succeeded.
- if (error_code == ErrorCode::kSuccess &&
- !boot_control_->SetActiveBootSlot(install_plan_.target_slot)) {
- error_code = ErrorCode::kPostinstallRunnerError;
+ if (error_code == ErrorCode::kSuccess) {
+ if (install_plan_.switch_slot_on_reboot) {
+ if (!boot_control_->SetActiveBootSlot(install_plan_.target_slot)) {
+ error_code = ErrorCode::kPostinstallRunnerError;
+ }
+ } else {
+ error_code = ErrorCode::kUpdatedButNotActive;
+ }
}
ScopedActionCompleter completer(processor_, this);
completer.set_code(error_code);
- if (error_code != ErrorCode::kSuccess) {
+ if (error_code != ErrorCode::kSuccess &&
+ error_code != ErrorCode::kUpdatedButNotActive) {
LOG(ERROR) << "Postinstall action failed.";
// Undo any changes done to trigger Powerwash.
diff --git a/payload_state.cc b/payload_state.cc
index 1ec32c5..cff02b1 100644
--- a/payload_state.cc
+++ b/payload_state.cc
@@ -357,6 +357,7 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ case ErrorCode::kUpdatedButNotActive:
LOG(INFO) << "Not incrementing URL index or failure count for this error";
break;
@@ -633,6 +634,7 @@
case metrics::AttemptResult::kPostInstallFailed:
case metrics::AttemptResult::kAbnormalTermination:
case metrics::AttemptResult::kUpdateCanceled:
+ case metrics::AttemptResult::kUpdateSucceededNotActive:
case metrics::AttemptResult::kNumConstants:
case metrics::AttemptResult::kUnset:
break;
diff --git a/payload_state_unittest.cc b/payload_state_unittest.cc
index c47e389..e469d2f 100644
--- a/payload_state_unittest.cc
+++ b/payload_state_unittest.cc
@@ -103,11 +103,6 @@
EXPECT_EQ(expected_response_sign, stored_response_sign);
}
-// Compare the value of native array for download source parameter.
-MATCHER_P(DownloadSourceMatcher, source_array, "") {
- return memcmp(source_array, arg, kNumDownloadSources) == 0;
-}
-
class PayloadStateTest : public ::testing::Test { };
TEST(PayloadStateTest, SetResponseWorksWithEmptyResponse) {
@@ -917,7 +912,15 @@
EXPECT_CALL(*fake_system_state.mock_metrics_reporter(),
ReportSuccessfulUpdateMetrics(
- _, _, _, _, DownloadSourceMatcher(total_bytes), _, _, _, _))
+ _,
+ _,
+ _,
+ _,
+ test_utils::DownloadSourceMatcher(total_bytes),
+ _,
+ _,
+ _,
+ _))
.Times(1);
payload_state.UpdateSucceeded();
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index 868e723..61ecadf 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -397,7 +397,8 @@
if grep -v -E '^[a-zA-Z0-9_-]*$' "${ab_partitions_list}" >&2; then
die "Invalid partition names found in the partition list."
fi
- partitions=($(cat "${ab_partitions_list}"))
+ # Get partition list without duplicates.
+ partitions=($(awk '!seen[$0]++' "${ab_partitions_list}"))
if [[ ${#partitions[@]} -eq 0 ]]; then
die "The list of partitions is empty. Can't generate a payload."
fi
diff --git a/scripts/update_device.py b/scripts/update_device.py
index 1a0daf8..64cfbe3 100755
--- a/scripts/update_device.py
+++ b/scripts/update_device.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python2
#
# Copyright (C) 2017 The Android Open Source Project
#
@@ -276,14 +276,13 @@
return t
-def AndroidUpdateCommand(ota_filename, payload_url):
+def AndroidUpdateCommand(ota_filename, payload_url, extra_headers):
"""Return the command to run to start the update in the Android device."""
ota = AndroidOTAPackage(ota_filename)
headers = ota.properties
headers += 'USER_AGENT=Dalvik (something, something)\n'
-
- # headers += 'POWERWASH=1\n'
headers += 'NETWORK_ID=0\n'
+ headers += extra_headers
return ['update_engine_client', '--update', '--follow',
'--payload=%s' % payload_url, '--offset=%d' % ota.offset,
@@ -360,6 +359,8 @@
help='Less verbose output')
parser.add_argument('--public-key', type=str, default='',
help='Override the public key used to verify payload.')
+ parser.add_argument('--extra-headers', type=str, default='',
+ help='Extra headers to pass to the device.')
args = parser.parse_args()
logging.basicConfig(
level=logging.WARNING if args.no_verbose else logging.INFO)
@@ -382,7 +383,12 @@
device_ota_file = os.path.join(OTA_PACKAGE_PATH, 'debug.zip')
payload_url = 'file://' + device_ota_file
if not args.no_push:
- cmds.append(['push', args.otafile, device_ota_file])
+ data_local_tmp_file = '/data/local/tmp/debug.zip'
+ cmds.append(['push', args.otafile, data_local_tmp_file])
+ cmds.append(['shell', 'su', '0', 'mv', data_local_tmp_file,
+ device_ota_file])
+ cmds.append(['shell', 'su', '0', 'chcon',
+ 'u:object_r:ota_package_file:s0', device_ota_file])
cmds.append(['shell', 'su', '0', 'chown', 'system:cache', device_ota_file])
cmds.append(['shell', 'su', '0', 'chmod', '0660', device_ota_file])
else:
@@ -418,7 +424,8 @@
update_cmd = \
OmahaUpdateCommand('http://127.0.0.1:%d/update' % DEVICE_PORT)
else:
- update_cmd = AndroidUpdateCommand(args.otafile, payload_url)
+ update_cmd = \
+ AndroidUpdateCommand(args.otafile, payload_url, args.extra_headers)
cmds.append(['shell', 'su', '0'] + update_cmd)
for cmd in cmds:
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index 22bb4c2..e716296 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -34,7 +34,7 @@
#include "update_engine/common/file_fetcher.h"
#include "update_engine/common/utils.h"
#include "update_engine/daemon_state_interface.h"
-#include "update_engine/metrics_reporter_android.h"
+#include "update_engine/metrics_reporter_interface.h"
#include "update_engine/metrics_utils.h"
#include "update_engine/network_selector.h"
#include "update_engine/payload_consumer/download_action.h"
@@ -80,6 +80,13 @@
return false;
}
+bool GetHeaderAsBool(const string& header, bool default_value) {
+ int value = 0;
+ if (base::StringToInt(header, &value) && (value == 0 || value == 1))
+ return value == 1;
+ return default_value;
+}
+
} // namespace
UpdateAttempterAndroid::UpdateAttempterAndroid(
@@ -92,8 +99,8 @@
boot_control_(boot_control),
hardware_(hardware),
processor_(new ActionProcessor()),
- clock_(new Clock()),
- metrics_reporter_(new MetricsReporterAndroid()) {
+ clock_(new Clock()) {
+ metrics_reporter_ = metrics::CreateMetricsReporter();
network_selector_ = network::CreateNetworkSelector();
}
@@ -192,10 +199,25 @@
install_plan_.source_slot = boot_control_->GetCurrentSlot();
install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0;
- int data_wipe = 0;
install_plan_.powerwash_required =
- base::StringToInt(headers[kPayloadPropertyPowerwash], &data_wipe) &&
- data_wipe != 0;
+ GetHeaderAsBool(headers[kPayloadPropertyPowerwash], false);
+
+ install_plan_.switch_slot_on_reboot =
+ GetHeaderAsBool(headers[kPayloadPropertySwitchSlotOnReboot], true);
+
+ install_plan_.run_post_install = true;
+ // Optionally skip post install if and only if:
+ // a) we're resuming
+ // b) post install has already succeeded before
+ // c) RUN_POST_INSTALL is set to 0.
+ if (install_plan_.is_resume && prefs_->Exists(kPrefsPostInstallSucceeded)) {
+ bool post_install_succeeded = false;
+ prefs_->GetBoolean(kPrefsPostInstallSucceeded, &post_install_succeeded);
+ if (post_install_succeeded) {
+ install_plan_.run_post_install =
+ GetHeaderAsBool(headers[kPayloadPropertyRunPostInstall], true);
+ }
+ }
NetworkId network_id = kDefaultNetworkId;
if (!headers[kPayloadPropertyNetworkId].empty()) {
@@ -313,7 +335,6 @@
// Update succeeded.
WriteUpdateCompletedMarker();
prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
- DeltaPerformer::ResetUpdateProgress(prefs_, false);
LOG(INFO) << "Update successfully applied, waiting to reboot.";
break;
@@ -351,6 +372,11 @@
if (type == DownloadAction::StaticType()) {
download_progress_ = 0;
}
+ if (type == PostinstallRunnerAction::StaticType()) {
+ bool succeeded =
+ code == ErrorCode::kSuccess || code == ErrorCode::kUpdatedButNotActive;
+ prefs_->SetBoolean(kPrefsPostInstallSucceeded, succeeded);
+ }
if (code != ErrorCode::kSuccess) {
// If an action failed, the ActionProcessor will cancel the whole thing.
return;
@@ -372,6 +398,16 @@
} else {
ProgressUpdate(progress);
}
+
+ // Update the bytes downloaded in prefs.
+ int64_t current_bytes_downloaded =
+ metrics_utils::GetPersistedValue(kPrefsCurrentBytesDownloaded, prefs_);
+ int64_t total_bytes_downloaded =
+ metrics_utils::GetPersistedValue(kPrefsTotalBytesDownloaded, prefs_);
+ prefs_->SetInt64(kPrefsCurrentBytesDownloaded,
+ current_bytes_downloaded + bytes_progressed);
+ prefs_->SetInt64(kPrefsTotalBytesDownloaded,
+ total_bytes_downloaded + bytes_progressed);
}
bool UpdateAttempterAndroid::ShouldCancel(ErrorCode* cancel_reason) {
@@ -446,6 +482,8 @@
ClearMetricsPrefs();
if (error_code == ErrorCode::kSuccess) {
metrics_utils::SetSystemUpdatedMarker(clock_.get(), prefs_);
+ // Clear the total bytes downloaded if and only if the update succeeds.
+ prefs_->SetInt64(kPrefsTotalBytesDownloaded, 0);
}
}
@@ -557,31 +595,57 @@
metrics_utils::GetAttemptResult(error_code);
Time attempt_start_time = Time::FromInternalValue(
metrics_utils::GetPersistedValue(kPrefsUpdateTimestampStart, prefs_));
+ TimeDelta duration = clock_->GetBootTime() - attempt_start_time;
TimeDelta duration_uptime = clock_->GetMonotonicTime() - attempt_start_time;
metrics_reporter_->ReportUpdateAttemptMetrics(
nullptr, // system_state
static_cast<int>(attempt_number),
payload_type,
- TimeDelta(),
+ duration,
duration_uptime,
payload_size,
attempt_result,
error_code);
+ int64_t current_bytes_downloaded =
+ metrics_utils::GetPersistedValue(kPrefsCurrentBytesDownloaded, prefs_);
+ metrics_reporter_->ReportUpdateAttemptDownloadMetrics(
+ current_bytes_downloaded,
+ 0,
+ DownloadSource::kNumDownloadSources,
+ metrics::DownloadErrorCode::kUnset,
+ metrics::ConnectionType::kUnset);
+
if (error_code == ErrorCode::kSuccess) {
int64_t reboot_count =
metrics_utils::GetPersistedValue(kPrefsNumReboots, prefs_);
string build_version;
prefs_->GetString(kPrefsPreviousVersion, &build_version);
+
+ // For android metrics, we only care about the total bytes downloaded
+ // for all sources; for now we assume the only download source is
+ // HttpsServer.
+ int64_t total_bytes_downloaded =
+ metrics_utils::GetPersistedValue(kPrefsTotalBytesDownloaded, prefs_);
+ int64_t num_bytes_downloaded[kNumDownloadSources] = {};
+ num_bytes_downloaded[DownloadSource::kDownloadSourceHttpsServer] =
+ total_bytes_downloaded;
+
+ int download_overhead_percentage = 0;
+ if (current_bytes_downloaded > 0) {
+ download_overhead_percentage =
+ (total_bytes_downloaded - current_bytes_downloaded) * 100ull /
+ current_bytes_downloaded;
+ }
metrics_reporter_->ReportSuccessfulUpdateMetrics(
static_cast<int>(attempt_number),
0, // update abandoned count
payload_type,
payload_size,
- nullptr, // num bytes downloaded
- 0, // download overhead percentage
- duration_uptime,
+ num_bytes_downloaded,
+ download_overhead_percentage,
+ duration,
static_cast<int>(reboot_count),
0); // url_switch_count
}
@@ -656,6 +720,7 @@
void UpdateAttempterAndroid::ClearMetricsPrefs() {
CHECK(prefs_);
+ prefs_->Delete(kPrefsCurrentBytesDownloaded);
prefs_->Delete(kPrefsNumReboots);
prefs_->Delete(kPrefsPayloadAttemptNumber);
prefs_->Delete(kPrefsSystemUpdatedMarker);
diff --git a/update_attempter_android.h b/update_attempter_android.h
index 911ab81..28bf90a 100644
--- a/update_attempter_android.h
+++ b/update_attempter_android.h
@@ -128,6 +128,10 @@
// |KprefsNumReboots|: number of reboots when applying the current update.
// |kPrefsSystemUpdatedMarker|: end timestamp of the last successful update.
// |kPrefsUpdateTimestampStart|: start timestamp of the current update.
+ // |kPrefsCurrentBytesDownloaded|: number of bytes downloaded for the current
+ // payload_id.
+ // |kPrefsTotalBytesDownloaded|: number of bytes downloaded in total since
+ // the last successful update.
// Metrics report function to call:
// |ReportUpdateAttemptMetrics|
@@ -149,7 +153,8 @@
// Prefs to delete:
// |kPrefsNumReboots|, |kPrefsPayloadAttemptNumber|,
- // |kPrefsSystemUpdatedMarker|, |kPrefsUpdateTimestampStart|
+ // |kPrefsSystemUpdatedMarker|, |kPrefsUpdateTimestampStart|,
+ // |kPrefsCurrentBytesDownloaded|
void ClearMetricsPrefs();
DaemonStateInterface* daemon_state_;
diff --git a/update_attempter_android_unittest.cc b/update_attempter_android_unittest.cc
index 6c0718a..94452df 100644
--- a/update_attempter_android_unittest.cc
+++ b/update_attempter_android_unittest.cc
@@ -28,6 +28,7 @@
#include "update_engine/common/fake_hardware.h"
#include "update_engine/common/fake_prefs.h"
#include "update_engine/common/mock_action_processor.h"
+#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
#include "update_engine/daemon_state_android.h"
#include "update_engine/mock_metrics_reporter.h"
@@ -38,6 +39,7 @@
using update_engine::UpdateStatus;
namespace chromeos_update_engine {
+
class UpdateAttempterAndroidTest : public ::testing::Test {
protected:
UpdateAttempterAndroidTest() = default;
@@ -120,16 +122,19 @@
prefs_.SetString(kPrefsPreviousVersion, "56789");
prefs_.SetInt64(kPrefsUpdateTimestampStart, 12345);
- Time now = Time::FromInternalValue(22345);
- clock_->SetMonotonicTime(now);
- TimeDelta duration = now - Time::FromInternalValue(12345);
+ Time boot_time = Time::FromInternalValue(22345);
+ Time up_time = Time::FromInternalValue(21345);
+ clock_->SetBootTime(boot_time);
+ clock_->SetMonotonicTime(up_time);
+ TimeDelta duration = boot_time - Time::FromInternalValue(12345);
+ TimeDelta duration_uptime = up_time - Time::FromInternalValue(12345);
EXPECT_CALL(
*metrics_reporter_,
ReportUpdateAttemptMetrics(_,
2,
_,
- _,
duration,
+ duration_uptime,
_,
metrics::AttemptResult::kUpdateSucceeded,
ErrorCode::kSuccess))
@@ -147,4 +152,58 @@
EXPECT_TRUE(prefs_.Exists(kPrefsSystemUpdatedMarker));
}
+TEST_F(UpdateAttempterAndroidTest, ReportMetricsForBytesDownloaded) {
+ // Check both prefs are updated correctly.
+ update_attempter_android_.BytesReceived(20, 50, 200);
+ EXPECT_EQ(
+ 20,
+ metrics_utils::GetPersistedValue(kPrefsCurrentBytesDownloaded, &prefs_));
+ EXPECT_EQ(
+ 20,
+ metrics_utils::GetPersistedValue(kPrefsTotalBytesDownloaded, &prefs_));
+
+ EXPECT_CALL(*metrics_reporter_,
+ ReportUpdateAttemptDownloadMetrics(50, _, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*metrics_reporter_,
+ ReportUpdateAttemptDownloadMetrics(40, _, _, _, _))
+ .Times(1);
+
+ int64_t total_bytes[kNumDownloadSources] = {};
+ total_bytes[kDownloadSourceHttpsServer] = 90;
+ EXPECT_CALL(*metrics_reporter_,
+ ReportSuccessfulUpdateMetrics(
+ _,
+ _,
+ _,
+ _,
+ test_utils::DownloadSourceMatcher(total_bytes),
+ 125,
+ _,
+ _,
+ _))
+ .Times(1);
+
+ // The first update fails after receving 50 bytes in total.
+ update_attempter_android_.BytesReceived(30, 50, 200);
+ update_attempter_android_.ProcessingDone(nullptr, ErrorCode::kError);
+ EXPECT_EQ(
+ 0,
+ metrics_utils::GetPersistedValue(kPrefsCurrentBytesDownloaded, &prefs_));
+ EXPECT_EQ(
+ 50,
+ metrics_utils::GetPersistedValue(kPrefsTotalBytesDownloaded, &prefs_));
+
+ // The second update succeeds after receiving 40 bytes, which leads to a
+ // overhead of 50 / 40 = 125%.
+ update_attempter_android_.BytesReceived(40, 40, 50);
+ update_attempter_android_.ProcessingDone(nullptr, ErrorCode::kSuccess);
+ // Both prefs should be cleared.
+ EXPECT_EQ(
+ 0,
+ metrics_utils::GetPersistedValue(kPrefsCurrentBytesDownloaded, &prefs_));
+ EXPECT_EQ(
+ 0, metrics_utils::GetPersistedValue(kPrefsTotalBytesDownloaded, &prefs_));
+}
+
} // namespace chromeos_update_engine
diff --git a/update_engine_client_android.cc b/update_engine_client_android.cc
index 989a97e..267f6e9 100644
--- a/update_engine_client_android.cc
+++ b/update_engine_client_android.cc
@@ -97,7 +97,10 @@
ErrorCode code = static_cast<ErrorCode>(error_code);
LOG(INFO) << "onPayloadApplicationComplete(" << utils::ErrorCodeToString(code)
<< " (" << error_code << "))";
- client_->ExitWhenIdle(code == ErrorCode::kSuccess ? EX_OK : 1);
+ client_->ExitWhenIdle(
+ (code == ErrorCode::kSuccess || code == ErrorCode::kUpdatedButNotActive)
+ ? EX_OK
+ : 1);
return Status::ok();
}
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
index ffd378c..44f8821 100644
--- a/update_manager/chromeos_policy.cc
+++ b/update_manager/chromeos_policy.cc
@@ -134,6 +134,7 @@
case ErrorCode::kOmahaRequestXMLHasEntityDecl:
case ErrorCode::kFilesystemVerifierError:
case ErrorCode::kUserCanceled:
+ case ErrorCode::kUpdatedButNotActive:
LOG(INFO) << "Not changing URL index or failure count due to error "
<< chromeos_update_engine::utils::ErrorCodeToString(err_code)
<< " (" << static_cast<int>(err_code) << ")";