aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Android.bp367
-rw-r--r--BUILD.gn609
-rw-r--r--OWNERS3
-rw-r--r--README.md312
-rw-r--r--TEST_MAPPING10
-rw-r--r--aosp/apex_handler_android_unittest.cc2
-rw-r--r--aosp/binder_service_android.cc18
-rw-r--r--aosp/binder_service_android.h3
-rw-r--r--aosp/boot_control_android.cc13
-rw-r--r--aosp/boot_control_android.h5
-rw-r--r--aosp/cleanup_previous_update_action.cc10
-rw-r--r--aosp/cow_converter.cc36
-rw-r--r--aosp/dynamic_partition_control_android.cc28
-rw-r--r--aosp/dynamic_partition_control_android.h22
-rw-r--r--aosp/mock_dynamic_partition_control_android.h6
-rw-r--r--aosp/ota_extractor.cc280
-rw-r--r--aosp/service_delegate_android_interface.h11
-rw-r--r--aosp/update_attempter_android.cc320
-rw-r--r--aosp/update_attempter_android.h43
-rw-r--r--aosp/update_attempter_android_integration_test.cc457
-rw-r--r--aosp/update_attempter_android_unittest.cc49
-rw-r--r--aosp/update_engine_client_android.cc75
-rw-r--r--binder_bindings/android/os/IUpdateEngine.aidl5
-rw-r--r--client_library/client_dbus.cc255
-rw-r--r--client_library/client_dbus.h105
-rw-r--r--common/action.h2
-rw-r--r--common/action_processor.h13
-rw-r--r--common/boot_control_interface.h5
-rw-r--r--common/boot_control_stub.h1
-rw-r--r--common/connection_utils.cc72
-rw-r--r--common/constants.cc131
-rw-r--r--common/constants.h250
-rw-r--r--common/cow_operation_convert.cc28
-rw-r--r--common/cow_operation_convert.h5
-rw-r--r--common/cow_operation_convert_unittest.cc84
-rw-r--r--common/dlcservice_stub.cc43
-rw-r--r--common/download_action.h15
-rw-r--r--common/dynamic_partition_control_interface.h4
-rw-r--r--common/dynamic_partition_control_stub.cc4
-rw-r--r--common/dynamic_partition_control_stub.h10
-rw-r--r--common/fake_boot_control.h1
-rw-r--r--common/fake_prefs.cc47
-rw-r--r--common/fake_prefs.h39
-rw-r--r--common/file_fetcher.h1
-rw-r--r--common/hash_calculator.cc14
-rw-r--r--common/hash_calculator.h4
-rw-r--r--common/http_fetcher.h2
-rw-r--r--common/http_fetcher_unittest.cc72
-rw-r--r--common/mock_dynamic_partition_control.h16
-rw-r--r--common/mock_http_fetcher.h2
-rw-r--r--common/mock_prefs.h27
-rw-r--r--common/prefs.cc67
-rw-r--r--common/prefs.h65
-rw-r--r--common/prefs_interface.h28
-rw-r--r--common/prefs_unittest.cc4
-rw-r--r--common/subprocess.cc39
-rw-r--r--common/subprocess.h14
-rw-r--r--common/test_utils.h7
-rw-r--r--common/testing_constants.h38
-rw-r--r--common/utils.cc126
-rw-r--r--common/utils.h184
-rw-r--r--common/utils_unittest.cc4
-rw-r--r--cros/boot_control_chromeos.cc378
-rw-r--r--cros/boot_control_chromeos.h104
-rw-r--r--cros/boot_control_chromeos_unittest.cc90
-rw-r--r--cros/chrome_browser_proxy_resolver.cc67
-rw-r--r--cros/chrome_browser_proxy_resolver.h66
-rw-r--r--cros/common_service.cc411
-rw-r--r--cros/common_service.h166
-rw-r--r--cros/common_service_unittest.cc182
-rw-r--r--cros/connection_manager.cc211
-rw-r--r--cros/connection_manager.h65
-rw-r--r--cros/connection_manager_interface.h65
-rw-r--r--cros/connection_manager_unittest.cc360
-rw-r--r--cros/daemon_chromeos.cc79
-rw-r--r--cros/daemon_chromeos.h63
-rw-r--r--cros/dbus_connection.cc55
-rw-r--r--cros/dbus_connection.h44
-rw-r--r--cros/dbus_service.cc223
-rw-r--r--cros/dbus_service.h194
-rw-r--r--cros/dbus_test_utils.h91
-rw-r--r--cros/dlcservice_chromeos.cc77
-rw-r--r--cros/dlcservice_chromeos.h55
-rw-r--r--cros/download_action_chromeos.cc469
-rw-r--r--cros/download_action_chromeos.h174
-rw-r--r--cros/download_action_chromeos_unittest.cc697
-rw-r--r--cros/excluder_chromeos.cc63
-rw-r--r--cros/excluder_chromeos.h49
-rw-r--r--cros/excluder_chromeos_unittest.cc54
-rw-r--r--cros/fake_p2p_manager.h112
-rw-r--r--cros/fake_p2p_manager_configuration.h102
-rw-r--r--cros/fake_shill_proxy.cc49
-rw-r--r--cros/fake_shill_proxy.h66
-rw-r--r--cros/fake_system_state.cc41
-rw-r--r--cros/fake_system_state.h308
-rw-r--r--cros/hardware_chromeos.cc371
-rw-r--r--cros/hardware_chromeos.h91
-rw-r--r--cros/hardware_chromeos_unittest.cc90
-rw-r--r--cros/image_properties.h99
-rw-r--r--cros/image_properties_chromeos.cc167
-rw-r--r--cros/image_properties_chromeos_unittest.cc169
-rw-r--r--cros/logging.cc91
-rw-r--r--cros/metrics_reporter_omaha.cc593
-rw-r--r--cros/metrics_reporter_omaha.h202
-rw-r--r--cros/metrics_reporter_omaha_unittest.cc607
-rw-r--r--cros/mock_connection_manager.h44
-rw-r--r--cros/mock_omaha_request_params.h81
-rw-r--r--cros/mock_p2p_manager.h102
-rw-r--r--cros/mock_payload_state.h83
-rw-r--r--cros/mock_power_manager.h35
-rw-r--r--cros/mock_update_attempter.h68
-rw-r--r--cros/omaha_request_action.cc1783
-rw-r--r--cros/omaha_request_action.h312
-rw-r--r--cros/omaha_request_action_fuzzer.cc53
-rw-r--r--cros/omaha_request_action_unittest.cc3189
-rw-r--r--cros/omaha_request_builder_xml.cc462
-rw-r--r--cros/omaha_request_builder_xml.h192
-rw-r--r--cros/omaha_request_builder_xml_unittest.cc421
-rw-r--r--cros/omaha_request_params.cc294
-rw-r--r--cros/omaha_request_params.h418
-rw-r--r--cros/omaha_request_params_unittest.cc294
-rw-r--r--cros/omaha_response.h123
-rw-r--r--cros/omaha_response_handler_action.cc339
-rw-r--r--cros/omaha_response_handler_action.h89
-rw-r--r--cros/omaha_response_handler_action_unittest.cc1022
-rw-r--r--cros/omaha_utils.cc37
-rw-r--r--cros/omaha_utils.h39
-rw-r--r--cros/omaha_utils_unittest.cc39
-rw-r--r--cros/p2p_manager.cc732
-rw-r--r--cros/p2p_manager.h184
-rw-r--r--cros/p2p_manager_unittest.cc536
-rw-r--r--cros/payload_state.cc1438
-rw-r--r--cros/payload_state.h598
-rw-r--r--cros/payload_state_interface.h215
-rw-r--r--cros/payload_state_unittest.cc1758
-rw-r--r--cros/platform_constants_chromeos.cc37
-rw-r--r--cros/power_manager_chromeos.cc47
-rw-r--r--cros/power_manager_chromeos.h44
-rw-r--r--cros/power_manager_interface.h47
-rw-r--r--cros/real_system_state.cc182
-rw-r--r--cros/real_system_state.h181
-rw-r--r--cros/requisition_util.cc69
-rw-r--r--cros/requisition_util.h32
-rw-r--r--cros/requisition_util_unittest.cc94
-rw-r--r--cros/shill_proxy.cc42
-rw-r--r--cros/shill_proxy.h54
-rw-r--r--cros/shill_proxy_interface.h56
-rw-r--r--cros/update_attempter.cc1858
-rw-r--r--cros/update_attempter.h581
-rw-r--r--cros/update_attempter_unittest.cc2479
-rw-r--r--cros/update_engine_client.cc601
-rw-r--r--dbus_bindings/dbus-service-config.json3
-rw-r--r--dbus_bindings/org.chromium.KioskAppService.dbus-xml10
-rw-r--r--dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml136
-rw-r--r--download_action.cc25
-rw-r--r--download_action_android_unittest.cc4
-rw-r--r--libcurl_http_fetcher_unittest.cc4
-rw-r--r--lz4diff/lz4diff.cc247
-rw-r--r--lz4diff/lz4diff.h45
-rw-r--r--lz4diff/lz4diff.proto59
-rw-r--r--lz4diff/lz4diff_compress.cc257
-rw-r--r--lz4diff/lz4diff_compress.h59
-rw-r--r--lz4diff/lz4diff_compress_unittest.cc117
-rw-r--r--lz4diff/lz4diff_format.h72
-rw-r--r--lz4diff/lz4diff_main.cc197
-rw-r--r--lz4diff/lz4diff_unittest.cc110
-rw-r--r--lz4diff/lz4patch.cc370
-rw-r--r--lz4diff/lz4patch.h59
-rw-r--r--metrics_utils.cc10
-rw-r--r--metrics_utils.h2
-rw-r--r--payload_consumer/block_extent_writer.cc116
-rw-r--r--payload_consumer/block_extent_writer.h60
-rw-r--r--payload_consumer/bzip_extent_writer.cc3
-rw-r--r--payload_consumer/bzip_extent_writer_unittest.cc5
-rw-r--r--payload_consumer/cached_file_descriptor.cc19
-rw-r--r--payload_consumer/cached_file_descriptor.h48
-rw-r--r--payload_consumer/certificate_parser_android_unittest.cc2
-rw-r--r--payload_consumer/cow_writer_file_descriptor.cc8
-rw-r--r--payload_consumer/cow_writer_file_descriptor.h5
-rw-r--r--payload_consumer/delta_performer.cc203
-rw-r--r--payload_consumer/delta_performer.h42
-rw-r--r--payload_consumer/delta_performer_integration_test.cc197
-rw-r--r--payload_consumer/delta_performer_unittest.cc17
-rw-r--r--payload_consumer/extent_map.h97
-rw-r--r--payload_consumer/extent_map_unittest.cc151
-rw-r--r--payload_consumer/file_descriptor_utils.cc9
-rw-r--r--payload_consumer/file_descriptor_utils.h8
-rw-r--r--payload_consumer/file_writer.h3
-rw-r--r--payload_consumer/filesystem_verifier_action.cc26
-rw-r--r--payload_consumer/filesystem_verifier_action.h8
-rw-r--r--payload_consumer/filesystem_verifier_action_unittest.cc8
-rw-r--r--payload_consumer/install_operation_executor.cc385
-rw-r--r--payload_consumer/install_operation_executor.h76
-rw-r--r--payload_consumer/install_operation_executor_unittest.cc283
-rw-r--r--payload_consumer/install_plan.cc117
-rw-r--r--payload_consumer/install_plan.h22
-rw-r--r--payload_consumer/mock_partition_writer.h6
-rw-r--r--payload_consumer/mount_history.cc2
-rw-r--r--payload_consumer/partition_writer.cc505
-rw-r--r--payload_consumer/partition_writer.h92
-rw-r--r--payload_consumer/partition_writer_factory_android.cc9
-rw-r--r--payload_consumer/partition_writer_factory_chromeos.cc2
-rw-r--r--payload_consumer/partition_writer_interface.h78
-rw-r--r--payload_consumer/partition_writer_unittest.cc62
-rw-r--r--payload_consumer/payload_constants.cc11
-rw-r--r--payload_consumer/payload_constants.h6
-rw-r--r--payload_consumer/postinstall_runner_action.cc145
-rw-r--r--payload_consumer/postinstall_runner_action.h3
-rw-r--r--payload_consumer/postinstall_runner_action_unittest.cc8
-rw-r--r--payload_consumer/snapshot_extent_writer.cc98
-rw-r--r--payload_consumer/snapshot_extent_writer.h29
-rw-r--r--payload_consumer/snapshot_extent_writer_unittest.cc11
-rw-r--r--payload_consumer/vabc_partition_writer.cc214
-rw-r--r--payload_consumer/vabc_partition_writer.h51
-rw-r--r--payload_consumer/vabc_partition_writer_unittest.cc248
-rw-r--r--payload_consumer/verified_source_fd.cc124
-rw-r--r--payload_consumer/verified_source_fd.h61
-rw-r--r--payload_consumer/verity_writer_android.cc49
-rw-r--r--payload_consumer/verity_writer_android.h6
-rw-r--r--payload_consumer/verity_writer_android_unittest.cc30
-rw-r--r--payload_consumer/verity_writer_interface.h3
-rw-r--r--payload_consumer/xor_extent_writer.cc121
-rw-r--r--payload_consumer/xor_extent_writer.h68
-rw-r--r--payload_consumer/xor_extent_writer_unittest.cc134
-rw-r--r--payload_consumer/xz_extent_writer.cc6
-rw-r--r--payload_consumer/xz_extent_writer.h6
-rw-r--r--payload_generator/ab_generator.cc2
-rw-r--r--payload_generator/annotated_operation.h6
-rw-r--r--payload_generator/boot_img_filesystem.cc17
-rw-r--r--payload_generator/boot_img_filesystem.h7
-rw-r--r--payload_generator/cow_size_estimator.cc224
-rw-r--r--payload_generator/cow_size_estimator.h13
-rw-r--r--payload_generator/deflate_utils.cc66
-rw-r--r--payload_generator/deflate_utils.h12
-rw-r--r--payload_generator/delta_diff_generator.cc22
-rw-r--r--payload_generator/delta_diff_generator.h3
-rw-r--r--payload_generator/delta_diff_utils.cc692
-rw-r--r--payload_generator/delta_diff_utils.h121
-rw-r--r--payload_generator/delta_diff_utils_unittest.cc494
-rw-r--r--payload_generator/erofs_filesystem.cc241
-rw-r--r--payload_generator/erofs_filesystem.h76
-rw-r--r--payload_generator/erofs_filesystem_unittest.cc127
-rw-r--r--payload_generator/erofs_iterate.h76
-rw-r--r--payload_generator/ext2_filesystem_unittest.cc4
-rw-r--r--payload_generator/extent_ranges.cc49
-rw-r--r--payload_generator/extent_ranges.h30
-rw-r--r--payload_generator/extent_ranges_unittest.cc249
-rw-r--r--payload_generator/extent_utils.cc45
-rw-r--r--payload_generator/extent_utils.h29
-rw-r--r--payload_generator/filesystem_interface.h8
-rw-r--r--payload_generator/generate_delta_main.cc31
-rw-r--r--payload_generator/merge_sequence_generator.cc177
-rw-r--r--payload_generator/merge_sequence_generator.h6
-rw-r--r--payload_generator/merge_sequence_generator_unittest.cc185
-rw-r--r--payload_generator/payload_file.cc51
-rw-r--r--payload_generator/payload_file.h7
-rw-r--r--payload_generator/payload_generation_config.cc95
-rw-r--r--payload_generator/payload_generation_config.h30
-rw-r--r--payload_generator/payload_signer_unittest.cc10
-rw-r--r--payload_generator/squashfs_filesystem.cc12
-rw-r--r--payload_generator/xz_android.cc1
-rw-r--r--payload_generator/zip_unittest.cc5
-rwxr-xr-xrun_unittests35
-rwxr-xr-xsample_images/generate_test_erofs_images.sh44
-rwxr-xr-xscripts/brillo_update_payload50
-rw-r--r--scripts/scan_lz4.py82
-rw-r--r--scripts/simulate_ota.py69
-rw-r--r--scripts/trim_ota_package.py38
-rwxr-xr-xscripts/update_device.py22
-rw-r--r--scripts/update_payload/common.py4
-rw-r--r--scripts/update_payload/payload.py19
-rw-r--r--scripts/update_payload/update_metadata_pb2.py64
-rw-r--r--stable/Android.bp2
-rw-r--r--test_http_server.cc6
-rw-r--r--update_engine.conf2
-rw-r--r--update_engine.rc2
-rw-r--r--update_manager/api_restricted_downloads_policy_impl.cc47
-rw-r--r--update_manager/api_restricted_downloads_policy_impl.h51
-rw-r--r--update_manager/boxed_value.cc264
-rw-r--r--update_manager/boxed_value.h126
-rw-r--r--update_manager/boxed_value_unittest.cc292
-rw-r--r--update_manager/chromeos_policy.cc794
-rw-r--r--update_manager/chromeos_policy.h175
-rw-r--r--update_manager/chromeos_policy_unittest.cc1554
-rw-r--r--update_manager/config_provider.h43
-rw-r--r--update_manager/default_policy.cc112
-rw-r--r--update_manager/default_policy.h108
-rw-r--r--update_manager/device_policy_provider.h113
-rw-r--r--update_manager/enough_slots_ab_updates_policy_impl.cc38
-rw-r--r--update_manager/enough_slots_ab_updates_policy_impl.h49
-rw-r--r--update_manager/enterprise_device_policy_impl.cc178
-rw-r--r--update_manager/enterprise_device_policy_impl.h48
-rw-r--r--update_manager/enterprise_device_policy_impl_unittest.cc170
-rw-r--r--update_manager/enterprise_rollback_policy_impl.cc40
-rw-r--r--update_manager/enterprise_rollback_policy_impl.h56
-rw-r--r--update_manager/enterprise_rollback_policy_impl_unittest.cc56
-rw-r--r--update_manager/evaluation_context-inl.h54
-rw-r--r--update_manager/evaluation_context.cc254
-rw-r--r--update_manager/evaluation_context.h213
-rw-r--r--update_manager/evaluation_context_unittest.cc496
-rw-r--r--update_manager/fake_config_provider.h43
-rw-r--r--update_manager/fake_device_policy_provider.h154
-rw-r--r--update_manager/fake_random_provider.h40
-rw-r--r--update_manager/fake_shill_provider.h60
-rw-r--r--update_manager/fake_state.h81
-rw-r--r--update_manager/fake_system_provider.h75
-rw-r--r--update_manager/fake_time_provider.h44
-rw-r--r--update_manager/fake_update_manager.h50
-rw-r--r--update_manager/fake_updater_provider.h123
-rw-r--r--update_manager/fake_variable.h70
-rw-r--r--update_manager/generic_variables.h229
-rw-r--r--update_manager/generic_variables_unittest.cc214
-rw-r--r--update_manager/interactive_update_policy_impl.cc77
-rw-r--r--update_manager/interactive_update_policy_impl.h66
-rw-r--r--update_manager/minimum_version_policy_impl.cc56
-rw-r--r--update_manager/minimum_version_policy_impl.h54
-rw-r--r--update_manager/minimum_version_policy_impl_unittest.cc111
-rw-r--r--update_manager/mock_policy.h101
-rw-r--r--update_manager/mock_update_manager.h44
-rw-r--r--update_manager/mock_variable.h42
-rw-r--r--update_manager/next_update_check_policy_impl.cc163
-rw-r--r--update_manager/next_update_check_policy_impl.h98
-rw-r--r--update_manager/next_update_check_policy_impl_unittest.cc163
-rw-r--r--update_manager/official_build_check_policy_impl.cc44
-rw-r--r--update_manager/official_build_check_policy_impl.h49
-rw-r--r--update_manager/out_of_box_experience_policy_impl.cc43
-rw-r--r--update_manager/out_of_box_experience_policy_impl.h46
-rw-r--r--update_manager/policy.cc39
-rw-r--r--update_manager/policy.h314
-rw-r--r--update_manager/policy_test_utils.cc126
-rw-r--r--update_manager/policy_test_utils.h102
-rw-r--r--update_manager/policy_utils.h113
-rw-r--r--update_manager/prng.h51
-rw-r--r--update_manager/prng_unittest.cc79
-rw-r--r--update_manager/provider.h38
-rw-r--r--update_manager/random_provider.h45
-rw-r--r--update_manager/real_config_provider.cc30
-rw-r--r--update_manager/real_config_provider.h52
-rw-r--r--update_manager/real_device_policy_provider.cc273
-rw-r--r--update_manager/real_device_policy_provider.h249
-rw-r--r--update_manager/real_device_policy_provider_unittest.cc462
-rw-r--r--update_manager/real_random_provider.cc89
-rw-r--r--update_manager/real_random_provider.h45
-rw-r--r--update_manager/real_random_provider_unittest.cc66
-rw-r--r--update_manager/real_shill_provider.cc169
-rw-r--r--update_manager/real_shill_provider.h97
-rw-r--r--update_manager/real_shill_provider_unittest.cc511
-rw-r--r--update_manager/real_state.h72
-rw-r--r--update_manager/real_system_provider.cc144
-rw-r--r--update_manager/real_system_provider.h87
-rw-r--r--update_manager/real_system_provider_unittest.cc138
-rw-r--r--update_manager/real_time_provider.cc97
-rw-r--r--update_manager/real_time_provider.h54
-rw-r--r--update_manager/real_time_provider_unittest.cc96
-rw-r--r--update_manager/real_updater_provider.cc503
-rw-r--r--update_manager/real_updater_provider.h123
-rw-r--r--update_manager/real_updater_provider_unittest.cc474
-rw-r--r--update_manager/rollback_prefs.h53
-rw-r--r--update_manager/shill_provider.h58
-rw-r--r--update_manager/staging_utils.cc140
-rw-r--r--update_manager/staging_utils.h70
-rw-r--r--update_manager/staging_utils_unittest.cc174
-rw-r--r--update_manager/state.h54
-rw-r--r--update_manager/state_factory.cc89
-rw-r--r--update_manager/state_factory.h41
-rw-r--r--update_manager/system_provider.h65
-rw-r--r--update_manager/time_provider.h51
-rw-r--r--update_manager/umtest_utils.cc29
-rw-r--r--update_manager/umtest_utils.h68
-rw-r--r--update_manager/update_manager-inl.h166
-rw-r--r--update_manager/update_manager.cc56
-rw-r--r--update_manager/update_manager.conf.example18
-rw-r--r--update_manager/update_manager.h187
-rw-r--r--update_manager/update_manager_unittest.cc333
-rw-r--r--update_manager/update_time_restrictions_monitor.cc132
-rw-r--r--update_manager/update_time_restrictions_monitor.h105
-rw-r--r--update_manager/update_time_restrictions_monitor_unittest.cc279
-rw-r--r--update_manager/update_time_restrictions_policy_impl.cc74
-rw-r--r--update_manager/update_time_restrictions_policy_impl.h61
-rw-r--r--update_manager/update_time_restrictions_policy_impl_unittest.cc120
-rw-r--r--update_manager/updater_provider.h132
-rw-r--r--update_manager/variable.h230
-rw-r--r--update_manager/variable_unittest.cc176
-rw-r--r--update_manager/weekly_time.cc75
-rw-r--r--update_manager/weekly_time.h97
-rw-r--r--update_manager/weekly_time_unittest.cc212
-rw-r--r--update_metadata.proto54
-rw-r--r--update_status_utils.cc22
389 files changed, 10091 insertions, 48900 deletions
diff --git a/.gitignore b/.gitignore
index db4c370c..84f29a3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@
/update_engine_client
/update_engine_unittests
*.pyc
+.vscode
diff --git a/Android.bp b/Android.bp
index d74e78f3..cace5b61 100644
--- a/Android.bp
+++ b/Android.bp
@@ -59,6 +59,7 @@ cc_defaults {
"-ffunction-sections",
"-fstack-protector-strong",
"-fvisibility=hidden",
+ "-g3",
],
cppflags: [
"-Wnon-virtual-dtor",
@@ -147,6 +148,7 @@ cc_defaults {
cc_library_static {
name: "update_metadata-protos",
host_supported: true,
+ ramdisk_available: true,
recovery_available: true,
srcs: ["update_engine/update_metadata.proto"],
@@ -183,11 +185,14 @@ cc_defaults {
"libpayload_extent_ranges",
"libpayload_extent_utils",
"libcow_operation_convert",
+ "lz4diff-protos",
+ "liblz4patch",
],
shared_libs: [
"libbase",
"libcrypto",
"libfec",
+ "liblz4",
"libziparchive",
],
}
@@ -232,6 +237,7 @@ cc_library_static {
"payload_consumer/file_descriptor_utils.cc",
"payload_consumer/file_writer.cc",
"payload_consumer/filesystem_verifier_action.cc",
+ "payload_consumer/install_operation_executor.cc",
"payload_consumer/install_plan.cc",
"payload_consumer/mount_history.cc",
"payload_consumer/payload_constants.cc",
@@ -240,12 +246,16 @@ cc_library_static {
"payload_consumer/partition_writer.cc",
"payload_consumer/partition_writer_factory_android.cc",
"payload_consumer/vabc_partition_writer.cc",
+ "payload_consumer/xor_extent_writer.cc",
+ "payload_consumer/block_extent_writer.cc",
"payload_consumer/snapshot_extent_writer.cc",
"payload_consumer/postinstall_runner_action.cc",
+ "payload_consumer/verified_source_fd.cc",
"payload_consumer/verity_writer_android.cc",
"payload_consumer/xz_extent_writer.cc",
"payload_consumer/fec_file_descriptor.cc",
"payload_consumer/partition_update_generator_android.cc",
+ "update_status_utils.cc",
],
}
@@ -274,6 +284,7 @@ cc_defaults {
"libutils",
"android.hardware.boot@1.0",
"android.hardware.boot@1.1",
+ "android.hardware.boot@1.2",
],
header_libs: [
"avb_headers",
@@ -386,7 +397,6 @@ cc_library_static {
"libcurl_http_fetcher.cc",
"metrics_utils.cc",
"update_boot_flags_action.cc",
- "update_status_utils.cc",
],
}
@@ -452,6 +462,7 @@ cc_binary {
shared_libs: [
"libbase",
"liblog",
+ "liblz4",
],
static_libs: [
"libpayload_consumer",
@@ -524,6 +535,7 @@ cc_defaults {
defaults: [
"libpayload_consumer_exports",
"update_metadata-protos_exports",
+ "erofs-utils_export_defaults",
],
header_libs: [
@@ -538,14 +550,21 @@ cc_defaults {
"liblzma",
"libpayload_consumer",
"libpuffdiff",
+ "libzucchini",
"libverity_tree",
"update_metadata-protos",
"libpayload_extent_utils",
"libcow_size_estimator",
+ "liberofs",
+ "lz4diff-protos",
+ "liblz4diff",
],
shared_libs: [
"libbase",
"libext2fs",
+ // LZ4 has to be a shared lib, as we want to override it with
+ // LD_LIBRARY_PRELOAD later
+ "liblz4",
],
}
@@ -583,6 +602,67 @@ cc_library_static {
],
}
+cc_defaults {
+ name: "liblz4diff_defaults",
+ static_libs: [
+ "lz4diff-protos",
+ "update_metadata-protos",
+ "libssl",
+ "libbsdiff",
+ "libpuffdiff",
+ ],
+ shared_libs: [
+ "liblz4",
+ ],
+}
+
+cc_library_static {
+ name: "liblz4diff",
+ host_supported: true,
+ defaults: ["ue_defaults", "liblz4diff_defaults"],
+ srcs: [
+ "lz4diff/lz4diff.cc",
+ "lz4diff/lz4diff_compress.cc",
+ ],
+}
+
+cc_library_static {
+ name: "liblz4patch",
+ host_supported: true,
+ recovery_available: true,
+ defaults: ["ue_defaults"],
+ static_libs: [
+ "lz4diff-protos",
+ "update_metadata-protos",
+ "libssl",
+ "libbspatch",
+ "libpuffpatch",
+ ],
+ shared_libs: [
+ "liblz4",
+ ],
+ srcs: [
+ "lz4diff/lz4patch.cc",
+ "lz4diff/lz4diff_compress.cc",
+ ],
+}
+
+cc_binary_host {
+ name: "lz4diff",
+ defaults: [
+ "ue_defaults",
+ "libpayload_generator_exports",
+ ],
+ static_libs: [
+ "libpayload_generator",
+ "liblz4diff",
+ "liblz4patch",
+ ],
+ srcs: [
+ "lz4diff/lz4diff_main.cc",
+ ],
+}
+
cc_library_static {
name: "libpayload_generator",
defaults: [
@@ -604,6 +684,7 @@ cc_library_static {
"payload_generator/delta_diff_generator.cc",
"payload_generator/delta_diff_utils.cc",
"payload_generator/ext2_filesystem.cc",
+ "payload_generator/erofs_filesystem.cc",
"payload_generator/extent_ranges.cc",
"payload_generator/full_update_generator.cc",
"payload_generator/mapfile_filesystem.cc",
@@ -640,6 +721,7 @@ cc_binary_host {
}
cc_test {
+ host_supported: true,
name: "ue_unittest_delta_generator",
defaults: [
"ue_defaults",
@@ -721,6 +803,186 @@ genrule {
],
}
+genrule {
+ name: "ue_unittest_erofs_imgs",
+ cmd: "$(in) $(location mkfs.erofs) $(location gen/erofs_empty.img) && " +
+ "$(in) $(location mkfs.erofs) $(location gen/erofs.img) $(location delta_generator) && " +
+ "$(in) $(location mkfs.erofs) $(location gen/erofs_new.img) $(location delta_generator) lz4hc,7",
+ srcs: ["sample_images/generate_test_erofs_images.sh"],
+ out: [
+ "gen/erofs.img",
+ "gen/erofs_new.img",
+ "gen/erofs_empty.img",
+ ],
+ tools: [
+ "mkfs.erofs",
+ "delta_generator",
+ ],
+}
+
+filegroup {
+ name: "update_engine_host_unittest_timeout_srcs",
+ srcs: [
+ "common/action_processor_unittest.cc",
+ "common/file_fetcher_unittest.cc",
+ "payload_generator/delta_diff_utils_unittest.cc",
+ ],
+}
+
+filegroup {
+ name: "update_engine_host_unittest_srcs",
+ srcs: [
+ "common/action_pipe_unittest.cc",
+ "common/action_processor_unittest.cc",
+ "common/action_unittest.cc",
+ "common/cow_operation_convert_unittest.cc",
+ "common/cpu_limiter_unittest.cc",
+ "common/fake_prefs.cc",
+ "common/file_fetcher_unittest.cc",
+ "common/hash_calculator_unittest.cc",
+ "common/hwid_override_unittest.cc",
+ "common/metrics_reporter_stub.cc",
+ "common/mock_http_fetcher.cc",
+ "common/prefs_unittest.cc",
+ "common/terminator_unittest.cc",
+ "common/test_utils.cc",
+ "lz4diff/lz4diff_compress_unittest.cc",
+ "lz4diff/lz4diff_unittest.cc",
+ "payload_generator/ab_generator_unittest.cc",
+ "payload_generator/blob_file_writer_unittest.cc",
+ "payload_generator/block_mapping_unittest.cc",
+ "payload_generator/boot_img_filesystem_unittest.cc",
+ "payload_generator/deflate_utils_unittest.cc",
+ "payload_generator/delta_diff_utils_unittest.cc",
+ "payload_generator/erofs_filesystem_unittest.cc",
+ "payload_generator/ext2_filesystem_unittest.cc",
+ "payload_generator/extent_ranges_unittest.cc",
+ "payload_generator/extent_utils_unittest.cc",
+ "payload_generator/fake_filesystem.cc",
+ "payload_generator/full_update_generator_unittest.cc",
+ "payload_generator/mapfile_filesystem_unittest.cc",
+ "payload_generator/merge_sequence_generator_unittest.cc",
+ "payload_generator/payload_file_unittest.cc",
+ "payload_generator/payload_generation_config_android_unittest.cc",
+ "payload_generator/payload_generation_config_unittest.cc",
+ "payload_generator/payload_properties_unittest.cc",
+ "payload_generator/payload_signer_unittest.cc",
+ "payload_generator/squashfs_filesystem_unittest.cc",
+ "payload_generator/zip_unittest.cc",
+ "payload_consumer/verity_writer_android_unittest.cc",
+ "payload_consumer/xz_extent_writer_unittest.cc",
+ "testrunner.cc",
+ ],
+}
+
+cc_test_host {
+ name: "update_engine_host_unittests",
+ defaults: [
+ "ue_defaults",
+ "libpayload_generator_exports",
+ ],
+ strip: {
+ none: true,
+ },
+ cflags: [
+ "-g3",
+ ],
+ tidy_timeout_srcs: [":update_engine_host_unittest_timeout_srcs"],
+ srcs: [":update_engine_host_unittest_srcs"],
+ data: [
+ ":ue_unittest_delta_generator",
+ ":ue_unittest_disk_imgs",
+ ":ue_unittest_erofs_imgs",
+ ":ue_unittest_keys",
+ "otacerts.zip",
+ "unittest_key.pem",
+ "unittest_key2.pem",
+ "unittest_key_RSA4096.pem",
+ "unittest_key_EC.pem",
+ "update_engine.conf",
+ ],
+ static_libs: [
+ "libgmock",
+ "libpayload_generator",
+ ],
+}
+
+// update_engine_unittests (type: executable)
+// ========================================================
+// Main unittest file.
+cc_test {
+ name: "update_engine_http_unittests",
+ defaults: [
+ "ue_defaults",
+ "liblz4diff_defaults",
+ "update_metadata-protos_exports",
+ ],
+ require_root: true,
+ static_libs: [
+ "libbase",
+ "libbrillo-test-helpers",
+ "libchrome_test_helpers",
+ "libcurl",
+ "libcutils",
+ "libdm",
+ "libgmock",
+ "libz",
+ ],
+ shared_libs: [
+ "libssl",
+ "libcrypto",
+ "libziparchive",
+ "liblog",
+ ],
+
+ data: [
+ ":test_http_server",
+ ":test_subprocess",
+ ":ue_unittest_keys",
+ "otacerts.zip",
+ "unittest_key.pem",
+ "unittest_key2.pem",
+ "unittest_key_RSA4096.pem",
+ "unittest_key_EC.pem",
+ ],
+
+ // We cannot use the default generated AndroidTest.xml because of the use of helper modules
+ // (i.e. test_http_server, test_subprocess, ue_unittest_delta_generator).
+ // test_config: "test_config.xml",
+ test_suites: ["device-tests"],
+
+ srcs: [
+ "aosp/platform_constants_android.cc",
+ "certificate_checker.cc",
+ "common/action_processor.cc",
+ "common/boot_control_stub.cc",
+ "common/error_code_utils.cc",
+ "common/file_fetcher.cc",
+ "common/hash_calculator.cc",
+ "common/http_fetcher.cc",
+ "common/multi_range_http_fetcher.cc",
+ "common/http_common.cc",
+ "common/subprocess.cc",
+ "common/test_utils.cc",
+ "common/utils.cc",
+ "common/proxy_resolver.cc",
+ "libcurl_http_fetcher.cc",
+ "payload_consumer/certificate_parser_android.cc",
+ "payload_consumer/payload_verifier.cc",
+ "payload_generator/payload_signer.cc",
+ "update_status_utils.cc",
+
+ "certificate_checker_unittest.cc",
+ "common/http_fetcher_unittest.cc",
+ "common/mock_http_fetcher.cc",
+ "common/proxy_resolver_unittest.cc",
+ "common/subprocess_unittest.cc",
+ "libcurl_http_fetcher_unittest.cc",
+ "payload_consumer/certificate_parser_android_unittest.cc",
+ "update_status_utils_unittest.cc",
+ ],
+}
+
// update_engine_unittests (type: executable)
// ========================================================
// Main unittest file.
@@ -746,10 +1008,9 @@ cc_test {
],
data: [
- ":test_http_server",
- ":test_subprocess",
":ue_unittest_delta_generator",
":ue_unittest_disk_imgs",
+ ":ue_unittest_erofs_imgs",
":ue_unittest_keys",
"otacerts.zip",
"unittest_key.pem",
@@ -764,73 +1025,42 @@ cc_test {
test_config: "test_config.xml",
test_suites: ["device-tests"],
+ tidy_timeout_srcs: [
+ ":update_engine_host_unittest_timeout_srcs",
+ "aosp/dynamic_partition_control_android_unittest.cc",
+ "common/http_fetcher_unittest.cc",
+ "payload_consumer/delta_performer_integration_test.cc",
+ "payload_consumer/delta_performer_unittest.cc",
+ ],
srcs: [
+ ":update_engine_host_unittest_srcs",
"aosp/apex_handler_android_unittest.cc",
"aosp/cleanup_previous_update_action_unittest.cc",
"aosp/dynamic_partition_control_android_unittest.cc",
+ "aosp/update_attempter_android_integration_test.cc",
"aosp/update_attempter_android_unittest.cc",
- "certificate_checker_unittest.cc",
- "common/action_pipe_unittest.cc",
- "common/action_processor_unittest.cc",
- "common/action_unittest.cc",
- "common/cow_operation_convert_unittest.cc",
- "common/cpu_limiter_unittest.cc",
- "common/fake_prefs.cc",
- "common/file_fetcher_unittest.cc",
- "common/hash_calculator_unittest.cc",
- "common/http_fetcher_unittest.cc",
- "common/hwid_override_unittest.cc",
- "common/metrics_reporter_stub.cc",
- "common/mock_http_fetcher.cc",
- "common/prefs_unittest.cc",
- "common/proxy_resolver_unittest.cc",
- "common/subprocess_unittest.cc",
- "common/terminator_unittest.cc",
- "common/test_utils.cc",
"common/utils_unittest.cc",
"download_action_android_unittest.cc",
- "libcurl_http_fetcher_unittest.cc",
"payload_consumer/bzip_extent_writer_unittest.cc",
"payload_consumer/cached_file_descriptor_unittest.cc",
"payload_consumer/cow_writer_file_descriptor_unittest.cc",
- "payload_consumer/certificate_parser_android_unittest.cc",
"payload_consumer/delta_performer_integration_test.cc",
"payload_consumer/delta_performer_unittest.cc",
- "payload_consumer/partition_writer_unittest.cc",
"payload_consumer/extent_reader_unittest.cc",
"payload_consumer/extent_writer_unittest.cc",
- "payload_consumer/snapshot_extent_writer_unittest.cc",
+ "payload_consumer/extent_map_unittest.cc",
"payload_consumer/fake_file_descriptor.cc",
"payload_consumer/file_descriptor_utils_unittest.cc",
"payload_consumer/file_writer_unittest.cc",
"payload_consumer/filesystem_verifier_action_unittest.cc",
"payload_consumer/install_plan_unittest.cc",
+ "payload_consumer/install_operation_executor_unittest.cc",
"payload_consumer/partition_update_generator_android_unittest.cc",
+ "payload_consumer/partition_writer_unittest.cc",
"payload_consumer/postinstall_runner_action_unittest.cc",
- "payload_consumer/verity_writer_android_unittest.cc",
- "payload_consumer/xz_extent_writer_unittest.cc",
- "payload_generator/ab_generator_unittest.cc",
- "payload_generator/blob_file_writer_unittest.cc",
- "payload_generator/block_mapping_unittest.cc",
- "payload_generator/boot_img_filesystem_unittest.cc",
- "payload_generator/deflate_utils_unittest.cc",
- "payload_generator/delta_diff_utils_unittest.cc",
- "payload_generator/ext2_filesystem_unittest.cc",
- "payload_generator/extent_ranges_unittest.cc",
- "payload_generator/extent_utils_unittest.cc",
- "payload_generator/fake_filesystem.cc",
- "payload_generator/full_update_generator_unittest.cc",
- "payload_generator/mapfile_filesystem_unittest.cc",
- "payload_generator/merge_sequence_generator_unittest.cc",
- "payload_generator/payload_file_unittest.cc",
- "payload_generator/payload_generation_config_android_unittest.cc",
- "payload_generator/payload_generation_config_unittest.cc",
- "payload_generator/payload_properties_unittest.cc",
- "payload_generator/payload_signer_unittest.cc",
- "payload_generator/squashfs_filesystem_unittest.cc",
- "payload_generator/zip_unittest.cc",
- "testrunner.cc",
- "update_status_utils_unittest.cc",
+ "payload_consumer/snapshot_extent_writer_unittest.cc",
+ "payload_consumer/vabc_partition_writer_unittest.cc",
+ "payload_consumer/xor_extent_writer_unittest.cc",
],
}
@@ -901,3 +1131,42 @@ cc_binary_host {
"update_metadata-protos",
],
}
+
+cc_library_static {
+ name: "lz4diff-protos",
+ host_supported: true,
+ ramdisk_available: true,
+ recovery_available: true,
+
+ srcs: ["lz4diff/lz4diff.proto"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ proto: {
+ canonical_path_from_root: false,
+ export_proto_headers: true,
+ },
+}
+
+cc_binary_host {
+ name: "ota_extractor",
+ defaults: [
+ "ue_defaults",
+ "libpayload_consumer_exports",
+ ],
+ srcs: [
+ "aosp/ota_extractor.cc",
+ ],
+ static_libs: [
+ "liblog",
+ "libbrotli",
+ "libbase",
+ "libpayload_consumer",
+ "libpayload_extent_ranges",
+ "libpayload_extent_utils",
+ "libz",
+ "libgflags",
+ "update_metadata-protos",
+ ],
+}
diff --git a/BUILD.gn b/BUILD.gn
deleted file mode 100644
index e60d33bd..00000000
--- a/BUILD.gn
+++ /dev/null
@@ -1,609 +0,0 @@
-#
-# Copyright (C) 2019 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.
-#
-
-# Stop linter from complaining XXX_unittest.cc naming.
-# gnlint: disable=GnLintSourceFileNames
-
-import("//common-mk/generate-dbus-adaptors.gni")
-import("//common-mk/generate-dbus-proxies.gni")
-import("//common-mk/openssl_pem.gni")
-import("//common-mk/pkg_config.gni")
-import("//common-mk/proto_library.gni")
-import("//update_engine/tar_bunzip2.gni")
-
-group("all") {
- deps = [
- ":delta_generator",
- ":libpayload_consumer",
- ":libpayload_generator",
- ":libupdate_engine",
- ":libupdate_engine_client",
- ":update_engine",
- ":update_engine-dbus-adaptor",
- ":update_engine-dbus-kiosk-app-client",
- ":update_engine_client",
- ":update_metadata-protos",
- ]
-
- if (use.test) {
- deps += [
- ":test_http_server",
- ":test_subprocess",
- ":update_engine-test_images",
- ":update_engine-testkeys",
- ":update_engine-testkeys-ec",
- ":update_engine_test_libs",
- ":update_engine_unittests",
- ]
- }
-
- if (use.fuzzer) {
- deps += [
- ":update_engine_delta_performer_fuzzer",
- ":update_engine_omaha_request_action_fuzzer",
- ]
- }
-}
-
-pkg_config("target_defaults") {
- cflags_cc = [
- "-fno-strict-aliasing",
- "-Wnon-virtual-dtor",
- ]
- cflags = [ "-ffunction-sections" ]
- ldflags = [ "-Wl,--gc-sections" ]
- defines = [
- "__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}",
- ]
- include_dirs = [
- # We need this include dir because we include all the local code as
- # "update_engine/...".
- "${platform2_root}",
- "${platform2_root}/update_engine/client_library/include",
- ]
-
- # NOSORT
- pkg_deps = [
- "libbrillo",
- "libchrome",
-
- # system_api depends on protobuf (or protobuf-lite). It must appear
- # before protobuf here or the linker flags won't be in the right
- # order.
- "system_api",
- ]
- if (use.fuzzer) {
- pkg_deps += [ "protobuf" ]
- } else {
- pkg_deps += [ "protobuf-lite" ]
- }
-}
-
-# Protobufs.
-proto_library("update_metadata-protos") {
- proto_in_dir = "."
- proto_out_dir = "include/update_engine"
- sources = [ "update_metadata.proto" ]
-}
-
-# Chrome D-Bus bindings.
-generate_dbus_adaptors("update_engine-dbus-adaptor") {
- dbus_adaptors_out_dir = "include/dbus_bindings"
- sources = [ "dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml" ]
-}
-
-generate_dbus_proxies("update_engine-dbus-kiosk-app-client") {
- mock_output_file = "include/kiosk-app/dbus-proxy-mocks.h"
- proxy_output_file = "include/kiosk-app/dbus-proxies.h"
- sources = [ "dbus_bindings/org.chromium.KioskAppService.dbus-xml" ]
-}
-
-# The payload application component and common dependencies.
-static_library("libpayload_consumer") {
- sources = [
- "common/action_processor.cc",
- "common/boot_control_stub.cc",
- "common/clock.cc",
- "common/constants.cc",
- "common/cpu_limiter.cc",
- "common/dynamic_partition_control_stub.cc",
- "common/error_code_utils.cc",
- "common/hash_calculator.cc",
- "common/http_common.cc",
- "common/http_fetcher.cc",
- "common/hwid_override.cc",
- "common/multi_range_http_fetcher.cc",
- "common/prefs.cc",
- "common/proxy_resolver.cc",
- "common/subprocess.cc",
- "common/terminator.cc",
- "common/utils.cc",
- "cros/platform_constants_chromeos.cc",
- "payload_consumer/bzip_extent_writer.cc",
- "payload_consumer/cached_file_descriptor.cc",
- "payload_consumer/certificate_parser_stub.cc",
- "payload_consumer/delta_performer.cc",
- "payload_consumer/extent_reader.cc",
- "payload_consumer/extent_writer.cc",
- "payload_consumer/file_descriptor.cc",
- "payload_consumer/file_descriptor_utils.cc",
- "payload_consumer/file_writer.cc",
- "payload_consumer/filesystem_verifier_action.cc",
- "payload_consumer/install_plan.cc",
- "payload_consumer/mount_history.cc",
- "payload_consumer/partition_update_generator_stub.cc",
- "payload_consumer/partition_writer_factory_chromeos.cc",
- "payload_consumer/partition_writer.cc",
- "payload_consumer/payload_constants.cc",
- "payload_consumer/payload_metadata.cc",
- "payload_consumer/payload_verifier.cc",
- "payload_consumer/postinstall_runner_action.cc",
- "payload_consumer/verity_writer_stub.cc",
- "payload_consumer/xz_extent_writer.cc",
- ]
- configs += [ ":target_defaults" ]
- libs = [
- "bz2",
- "rt",
- ]
-
- # TODO(crbug.com/1082873): Remove after fixing usage of deprecated
- # declarations.
- cflags_cc = [ "-Wno-error=deprecated-declarations" ]
-
- # TODO(deymo): Remove unused dependencies once we stop including files
- # from the root directory.
- all_dependent_pkg_deps = [
- "libbspatch",
- "libcrypto",
- "libpuffpatch",
- "xz-embedded",
- ]
- public_deps = [ ":update_metadata-protos" ]
-}
-
-# The main daemon static_library with all the code used to check for updates
-# with Omaha and expose a DBus daemon.
-static_library("libupdate_engine") {
- sources = [
- "certificate_checker.cc",
- "common/connection_utils.cc",
- "common/system_state.cc",
- "cros/boot_control_chromeos.cc",
- "cros/common_service.cc",
- "cros/connection_manager.cc",
- "cros/daemon_chromeos.cc",
- "cros/dbus_connection.cc",
- "cros/dbus_service.cc",
- "cros/hardware_chromeos.cc",
- "cros/image_properties_chromeos.cc",
- "cros/logging.cc",
- "cros/metrics_reporter_omaha.cc",
- "cros/omaha_request_action.cc",
- "cros/omaha_request_builder_xml.cc",
- "cros/omaha_request_params.cc",
- "cros/omaha_response_handler_action.cc",
- "cros/omaha_utils.cc",
- "cros/p2p_manager.cc",
- "cros/payload_state.cc",
- "cros/power_manager_chromeos.cc",
- "cros/real_system_state.cc",
- "cros/requisition_util.cc",
- "cros/shill_proxy.cc",
- "cros/update_attempter.cc",
- "cros/download_action_chromeos.cc",
- "libcurl_http_fetcher.cc",
- "metrics_utils.cc",
- "update_boot_flags_action.cc",
- "update_manager/boxed_value.cc",
- "update_manager/chromeos_policy.cc",
- "update_manager/default_policy.cc",
- "update_manager/enough_slots_ab_updates_policy_impl.cc",
- "update_manager/enterprise_device_policy_impl.cc",
- "update_manager/enterprise_rollback_policy_impl.cc",
- "update_manager/evaluation_context.cc",
- "update_manager/interactive_update_policy_impl.cc",
- "update_manager/minimum_version_policy_impl.cc",
- "update_manager/next_update_check_policy_impl.cc",
- "update_manager/official_build_check_policy_impl.cc",
- "update_manager/out_of_box_experience_policy_impl.cc",
- "update_manager/policy.cc",
- "update_manager/policy_test_utils.cc",
- "update_manager/real_config_provider.cc",
- "update_manager/real_device_policy_provider.cc",
- "update_manager/real_random_provider.cc",
- "update_manager/real_shill_provider.cc",
- "update_manager/real_system_provider.cc",
- "update_manager/real_time_provider.cc",
- "update_manager/real_updater_provider.cc",
- "update_manager/staging_utils.cc",
- "update_manager/state_factory.cc",
- "update_manager/update_manager.cc",
- "update_manager/update_time_restrictions_monitor.cc",
- "update_manager/update_time_restrictions_policy_impl.cc",
- "update_manager/weekly_time.cc",
- "update_status_utils.cc",
- ]
- configs += [ ":target_defaults" ]
- libs = [
- "bz2",
- "policy",
- "rootdev",
- "rt",
- ]
- all_dependent_pkg_deps = [
- "dbus-1",
- "expat",
- "libcurl",
- "libdebugd-client",
- "libmetrics",
- "libpower_manager-client",
- "libsession_manager-client",
- "libshill-client",
- "libssl",
- "libupdate_engine-client",
- "vboot_host",
- ]
- deps = [
- ":libpayload_consumer",
- ":update_engine-dbus-adaptor",
- ":update_engine-dbus-kiosk-app-client",
- ":update_metadata-protos",
- ]
-
- if (use.dlc) {
- all_dependent_pkg_deps += [ "libdlcservice-client" ]
- }
-
- if (use.chrome_network_proxy) {
- sources += [ "cros/chrome_browser_proxy_resolver.cc" ]
- }
-
- if (use.dlc) {
- sources += [
- "cros/dlcservice_chromeos.cc",
- "cros/excluder_chromeos.cc",
- ]
- } else {
- sources += [
- "common/dlcservice_stub.cc",
- "common/excluder_stub.cc",
- ]
- }
-}
-
-# update_engine daemon.
-executable("update_engine") {
- sources = [ "main.cc" ]
- configs += [ ":target_defaults" ]
- deps = [ ":libupdate_engine" ]
-}
-
-# update_engine client library.
-static_library("libupdate_engine_client") {
- sources = [
- "client_library/client_dbus.cc",
- "update_status_utils.cc",
- ]
- include_dirs = [ "client_library/include" ]
- configs += [ ":target_defaults" ]
- pkg_deps = [
- "dbus-1",
- "libupdate_engine-client",
- ]
-}
-
-# update_engine console client.
-executable("update_engine_client") {
- sources = [
- "common/error_code_utils.cc",
- "cros/omaha_utils.cc",
- "cros/update_engine_client.cc",
- ]
- configs += [ ":target_defaults" ]
- deps = [ ":libupdate_engine_client" ]
-}
-
-# server-side code. This is used for delta_generator and unittests but not
-# for any client code.
-static_library("libpayload_generator") {
- sources = [
- "common/file_fetcher.cc",
- "common/system_state.cc",
- "cros/real_system_state.cc",
- "download_action.cc",
- "payload_generator/ab_generator.cc",
- "payload_generator/annotated_operation.cc",
- "payload_generator/blob_file_writer.cc",
- "payload_generator/block_mapping.cc",
- "payload_generator/boot_img_filesystem_stub.cc",
- "payload_generator/bzip.cc",
- "payload_generator/cow_size_estimator_stub.cc",
- "payload_generator/deflate_utils.cc",
- "payload_generator/delta_diff_generator.cc",
- "payload_generator/delta_diff_utils.cc",
- "payload_generator/ext2_filesystem.cc",
- "payload_generator/extent_ranges.cc",
- "payload_generator/extent_utils.cc",
- "payload_generator/full_update_generator.cc",
- "payload_generator/mapfile_filesystem.cc",
- "payload_generator/merge_sequence_generator.cc",
- "payload_generator/payload_file.cc",
- "payload_generator/payload_generation_config.cc",
- "payload_generator/payload_generation_config_chromeos.cc",
- "payload_generator/payload_properties.cc",
- "payload_generator/payload_signer.cc",
- "payload_generator/raw_filesystem.cc",
- "payload_generator/squashfs_filesystem.cc",
- "payload_generator/xz_chromeos.cc",
- ]
- configs += [ ":target_defaults" ]
- all_dependent_pkg_deps = [
- "ext2fs",
- "libbsdiff",
- "liblzma",
- "libpuffdiff",
- ]
- deps = [
- ":libpayload_consumer",
- ":update_metadata-protos",
- ]
-
- # TODO(crbug.com/1082873): Remove after fixing usage of deprecated
- # declarations.
- cflags_cc = [ "-Wno-error=deprecated-declarations" ]
-}
-
-# server-side delta generator.
-executable("delta_generator") {
- sources = [ "payload_generator/generate_delta_main.cc" ]
- configs += [ ":target_defaults" ]
- configs -= [ "//common-mk:pie" ]
- deps = [
- ":libpayload_consumer",
- ":libpayload_generator",
- ]
-}
-
-if (use.test || use.fuzzer) {
- static_library("update_engine_test_libs") {
- sources = [
- "common/fake_prefs.cc",
- "common/mock_http_fetcher.cc",
- "common/test_utils.cc",
- "cros/fake_shill_proxy.cc",
- "cros/fake_system_state.cc",
- "payload_consumer/fake_file_descriptor.cc",
- "payload_generator/fake_filesystem.cc",
- "update_manager/umtest_utils.cc",
- ]
-
- # TODO(crbug.com/887845): After library odering issue is fixed,
- # //common-mk:test can be moved in all_dependent_configs and
- # //common-mk:test in each test configs can be removed.
- configs += [
- "//common-mk:test",
- ":target_defaults",
- ]
- pkg_deps = [ "libshill-client-test" ]
- deps = [ ":libupdate_engine" ]
- }
-}
-
-if (use.test) {
- # Public keys used for unit testing.
- genopenssl_key("update_engine-testkeys") {
- openssl_pem_in_dir = "."
- openssl_pem_out_dir = "include/update_engine"
- sources = [
- "unittest_key.pem",
- "unittest_key2.pem",
- "unittest_key_RSA4096.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 = "."
- sources = [ "sample_images/sample_images.tar.bz2" ]
- }
-
- # Test HTTP Server.
- executable("test_http_server") {
- sources = [
- "common/http_common.cc",
- "test_http_server.cc",
- ]
-
- # //common-mk:test should be on the top.
- # TODO(crbug.com/887845): Remove this after library odering issue is fixed.
- configs += [
- "//common-mk:test",
- ":target_defaults",
- ]
- }
-
- # Test subprocess helper.
- executable("test_subprocess") {
- sources = [ "test_subprocess.cc" ]
-
- # //common-mk:test should be on the top.
- # TODO(crbug.com/887845): Remove this after library odering issue is fixed.
- configs += [
- "//common-mk:test",
- ":target_defaults",
- ]
- }
-
- # Main unittest file.
- executable("update_engine_unittests") {
- sources = [
- "certificate_checker_unittest.cc",
- "common/action_pipe_unittest.cc",
- "common/action_processor_unittest.cc",
- "common/action_unittest.cc",
- "common/cpu_limiter_unittest.cc",
- "common/hash_calculator_unittest.cc",
- "common/http_fetcher_unittest.cc",
- "common/hwid_override_unittest.cc",
- "common/prefs_unittest.cc",
- "common/proxy_resolver_unittest.cc",
- "common/subprocess_unittest.cc",
- "common/terminator_unittest.cc",
- "common/utils_unittest.cc",
- "cros/boot_control_chromeos_unittest.cc",
- "cros/common_service_unittest.cc",
- "cros/connection_manager_unittest.cc",
- "cros/hardware_chromeos_unittest.cc",
- "cros/image_properties_chromeos_unittest.cc",
- "cros/metrics_reporter_omaha_unittest.cc",
- "cros/omaha_request_action_unittest.cc",
- "cros/omaha_request_builder_xml_unittest.cc",
- "cros/omaha_request_params_unittest.cc",
- "cros/omaha_response_handler_action_unittest.cc",
- "cros/omaha_utils_unittest.cc",
- "cros/p2p_manager_unittest.cc",
- "cros/payload_state_unittest.cc",
- "cros/requisition_util_unittest.cc",
- "cros/update_attempter_unittest.cc",
- "cros/download_action_chromeos_unittest.cc",
- "libcurl_http_fetcher_unittest.cc",
- "metrics_utils_unittest.cc",
- "payload_consumer/bzip_extent_writer_unittest.cc",
- "payload_consumer/cached_file_descriptor_unittest.cc",
- "payload_consumer/delta_performer_integration_test.cc",
- "payload_consumer/delta_performer_unittest.cc",
- "payload_consumer/extent_reader_unittest.cc",
- "payload_consumer/extent_writer_unittest.cc",
- "payload_consumer/file_descriptor_utils_unittest.cc",
- "payload_consumer/file_writer_unittest.cc",
- "payload_consumer/filesystem_verifier_action_unittest.cc",
- "payload_consumer/install_plan_unittest.cc",
- "payload_consumer/postinstall_runner_action_unittest.cc",
- "payload_consumer/xz_extent_writer_unittest.cc",
- "payload_generator/ab_generator_unittest.cc",
- "payload_generator/blob_file_writer_unittest.cc",
- "payload_generator/block_mapping_unittest.cc",
- "payload_generator/deflate_utils_unittest.cc",
- "payload_generator/delta_diff_utils_unittest.cc",
- "payload_generator/ext2_filesystem_unittest.cc",
- "payload_generator/extent_ranges_unittest.cc",
- "payload_generator/extent_utils_unittest.cc",
- "payload_generator/full_update_generator_unittest.cc",
- "payload_generator/mapfile_filesystem_unittest.cc",
- "payload_generator/merge_sequence_generator_unittest.cc",
- "payload_generator/payload_file_unittest.cc",
- "payload_generator/payload_generation_config_unittest.cc",
- "payload_generator/payload_properties_unittest.cc",
- "payload_generator/payload_signer_unittest.cc",
- "payload_generator/squashfs_filesystem_unittest.cc",
- "payload_generator/zip_unittest.cc",
- "testrunner.cc",
- "update_boot_flags_action_unittest.cc",
- "update_manager/boxed_value_unittest.cc",
- "update_manager/chromeos_policy_unittest.cc",
- "update_manager/enterprise_device_policy_impl_unittest.cc",
- "update_manager/enterprise_rollback_policy_impl_unittest.cc",
- "update_manager/evaluation_context_unittest.cc",
- "update_manager/generic_variables_unittest.cc",
- "update_manager/minimum_version_policy_impl_unittest.cc",
- "update_manager/prng_unittest.cc",
- "update_manager/real_device_policy_provider_unittest.cc",
- "update_manager/real_random_provider_unittest.cc",
- "update_manager/real_shill_provider_unittest.cc",
- "update_manager/real_system_provider_unittest.cc",
- "update_manager/real_time_provider_unittest.cc",
- "update_manager/real_updater_provider_unittest.cc",
- "update_manager/staging_utils_unittest.cc",
- "update_manager/update_manager_unittest.cc",
- "update_manager/update_time_restrictions_monitor_unittest.cc",
- "update_manager/update_time_restrictions_policy_impl_unittest.cc",
- "update_manager/variable_unittest.cc",
- "update_manager/weekly_time_unittest.cc",
- "update_status_utils_unittest.cc",
- ]
- if (use.dlc) {
- sources += [ "cros/excluder_chromeos_unittest.cc" ]
- }
-
- # //common-mk:test should be on the top.
- # TODO(crbug.com/887845): Remove this after library odering issue is fixed.
- configs += [
- "//common-mk:test",
- ":target_defaults",
- ]
- pkg_deps = [
- "libbrillo-test",
- "libchrome-test",
- "libdebugd-client-test",
- "libpower_manager-client-test",
- "libsession_manager-client-test",
- "libshill-client-test",
- ]
- deps = [
- ":libpayload_generator",
- ":libupdate_engine",
- ":update_engine_test_libs",
- ]
- }
-}
-
-# Fuzzer target.
-if (use.fuzzer) {
- executable("update_engine_delta_performer_fuzzer") {
- sources = [ "payload_consumer/delta_performer_fuzzer.cc" ]
- configs += [
- "//common-mk/common_fuzzer",
- ":target_defaults",
- ]
- pkg_deps = [
- "libbrillo-test",
- "libchrome-test",
- ]
- deps = [
- ":libupdate_engine",
- ":update_engine_test_libs",
- ]
- }
- executable("update_engine_omaha_request_action_fuzzer") {
- sources = [ "cros/omaha_request_action_fuzzer.cc" ]
- configs += [
- "//common-mk/common_fuzzer",
- ":target_defaults",
- ]
- pkg_deps = [
- "libbrillo-test",
- "libchrome-test",
- ]
- deps = [
- ":libupdate_engine",
- ":update_engine_test_libs",
- ]
- }
-}
diff --git a/OWNERS b/OWNERS
index 938752f6..58ecfe1a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -5,10 +5,11 @@ deymo@google.com
elsk@google.com
senj@google.com
xunchang@google.com
+zhangkelvin@google.com
# Chromium OS maintainers:
-ahassani@google.com
kimjae@google.com
+
# Chromium OS only:
# COMPONENT: Internals>Installer
diff --git a/README.md b/README.md
index 71f271b2..fad6eaa4 100644
--- a/README.md
+++ b/README.md
@@ -41,11 +41,23 @@ available, it is written into the inactive partition. After a successful reboot,
the previously inactive partition becomes active and the old active partition
becomes inactive.
-But everything starts with generating update payloads in (Google) servers for
-each new system image. Once the update payloads are generated, they are signed
-with specific keys and stored in a location known to an update server (Omaha).
-
-When the updater client initiates an update (either periodically or user
+### Generation
+
+But everything starts with generating OTA packages on (Google) servers for
+each new system image. This is done by calling
+[ota_from_target_files](https://cs.android.com/android/platform/superproject/+/master:build/make/tools/releasetools/ota_from_target_files.py)
+with source and destination builds. This script requires target_file.zip to work,
+image files are not sufficient.
+
+### Distribution/Configuration
+Once the OTA packages are generated, they are signed with specific keys
+and stored in a location known to an update server (GOTA).
+GOTA will then make this OTA package accessible via a public URL. Optionally,
+operators an choose to make this OTA update available only to a specific
+subset of devices.
+
+### Installation
+When the device's updater client initiates an update (either periodically or user
initiated), it first consults different device policies to see if the update
check is allowed. For example, device policies can prevent an update check
during certain times of a day or they require the update check time to be
@@ -53,14 +65,23 @@ scattered throughout the day randomly, etc.
Once policies allow for the update check, the updater client sends a request to
the update server (all this communication happens over HTTPS) and identifies its
-parameters like its Application ID, hardware ID, version, board, etc. Then if
-the update server decides to serve an update payload, it will respond with all
-the parameters needed to perform an update like the URLs to download the
+parameters like its Application ID, hardware ID, version, board, etc.
+
+Some policities on the server might prevent the device from getting specific
+OTA updates, these server side policities are often set by operators. For
+example, the operator might want to deliver a beta version of software to only
+a subset of devices.
+
+But if the update server decides to serve an update payload, it will respond
+with all the parameters needed to perform an update like the URLs to download the
payloads, the metadata signatures, the payload size and hash, etc. The updater
client continues communicating with the update server after different state
changes, like reporting that it started to download the payload or it finished
the update, or reports that the update failed with specific error codes, etc.
+The device will then proceed to actually installing the OTA update. This consists
+of roughly 3 steps.
+#### Download & Install
Each payload consists of two main sections: metadata and extra data. The
metadata is basically a list of operations that should be performed for an
update. The extra data contains the data blobs needed by some or all of these
@@ -86,15 +107,26 @@ During the download, the updater client hashes the downloaded bytes and when the
download finishes, it checks the payload signature (located at the end of the
payload). If the signature cannot be verified, the update is rejected.
-After the inactive partition is updated, the entire partition is re-read, hashed
-and compared to a hash value passed in the metadata to make sure the update was
-successfully written into the partition.
+#### Hash Verification & Verity Computation
+
+After the inactive partition is updated, the updater client will compute
+Forward-Error-Correction(also known as FEC, Verity) code for each partition,
+and wriee the computed verity data to inactive partitions. In some updates,
+verity data is included in the extra data, so this step will be skipped.
+
+Then, the entire partition is re-read, hashed and compared to a hash value
+passed in the metadata to make sure the update was successfully written into
+the partition. Hash computed in this step includes the verity code written in
+last step.
+
+#### Postintall
+
+In the next step, the [Postinstall] scripts (if any) is called. From OTA's perspective,
+these postinstall scripts are just blackboxes. Usually postinstall scripts will optimize
+existings apps on the phone and run file system garbage collection, so that device can boot
+fast after OTA. But these are managed by other teams.
-In the next step, the [Postinstall] process (if any) is called. The postinstall
-reconstructs the dm-verity tree hash of the ROOT partition and writes it at the
-end of the partition (after the last block of the file system). The postinstall
-can also perform any board specific or firmware update tasks necessary. If
-postinstall fails, the entire update is considered failed.
+#### Finishing Touches
Then the updater client goes into a state that identifies the update has
completed and the user needs to reboot the system. At this point, until the user
@@ -106,21 +138,24 @@ in the field.
After the update proved successful, the inactive partition is marked to have a
higher priority (on a boot, a partition with higher priority is booted
first). Once the user reboots the system, it will boot into the updated
-partition and it is marked as active. At this point, after the reboot, The
-updater client calls into the [`chromeos-setgoodkernel`] program. The program
-verifies the integrity of the system partitions using the dm-verity and marks
-the active partition as healthy. At this point the system is basically updated
-successfully.
+partition and it is marked as active. At this point, after the reboot, the
+[update_verifier](https://cs.android.com/android/platform/superproject/+/master:bootable/recovery/update_verifier/)
+program runs, read all dm-verity devices to make sure the partitions aren't corrupted,
+then mark the update as successful.
+
+A/B updates are considered completed at this point. Virtual A/B updates will have an
+additional step after this, called "merging". Merging usually takes few minutes, after that
+Virtual A/B updates are considered complete.
## Update Engine Daemon
The `update_engine` is a single-threaded daemon process that runs all the
times. This process is the heart of the auto updates. It runs with lower
priorities in the background and is one of the last processes to start after a
-system boot. Different clients (like Chrome or other services) can send requests
+system boot. Different clients (like GMS Core or other services) can send requests
for update checks to the update engine. The details of how requests are passed
to the update engine is system dependent, but in Chrome OS it is D-Bus. Look at
-the [D-Bus interface] for a list of all available methods.
+the [D-Bus interface] for a list of all available methods. On Android it is binder.
There are many resiliency features embedded in the update engine that makes auto
updates robust including but not limited to:
@@ -134,52 +169,11 @@ updates robust including but not limited to:
partition) for a few times, it switches to full payload.
The updater clients writes its active preferences in
-`/var/lib/update_engine/prefs`. These preferences help with tracking changes
+`/data/misc/update_engine/prefs`. These preferences help with tracking changes
during the lifetime of the updater client and allows properly continuing the
update process after failed attempts or crashes.
-The core update engine code base in a Chromium OS checkout is located in
-`src/aosp/system/update_engine` fetching [this repository].
-
-### Policy Management
-
-In Chrome OS, devices are allowed to accept different policies from their
-managing organizations. Some of these policies affect how/when updates should be
-performed. For example, an organization may want to scatter the update checks
-during certain times of the day so as not to interfere with normal
-business. Within the update engine daemon, [UpdateManager] has the
-responsibility of loading such policies and making different decisions based on
-them. For example, some policies may allow the act of checking for updates to
-happen, while they prevent downloading the update payload. Or some policies
-don’t allow the update check within certain time frames, etc. Anything that
-relates to the Chrome OS update policies should be contained within the
-[update_manager] directory in the source code.
-
-### Rollback vs. Enterprise Rollback
-
-Chrome OS defines a concept for Rollback: Whenever a newly updated system does
-not work as it is intended, under certain circumstances the device can be rolled
-back to a previously working version. There are two types of rollback supported
-in Chrome OS: A (legacy, original) rollback and an enterprise rollback (I know,
-naming is confusing).
-
-A normal rollback, which has existed for as long as Chrome OS had auto updater,
-is performed by switching the currently inactive partition into the active
-partition and rebooting into it. It is as simple as running a successful
-postinstall on the inactive partition, and rebooting the device. It is a feature
-used by Chrome that happens under certain circumstances. Of course rollback
-can’t happen if the inactive partition has been tampered with or has been nuked
-by the updater client to install an even newer update. Normally a rollback is
-followed by a Powerwash which clobbers the stateful partition.
-
-Enterprise rollback is a new feature added to allow enterprise users to
-downgrade the installed image to an older version. It is very similar to a
-normal system update, except that an older update payload is downloaded and
-installed. There is no direct API for entering into the enterprise rollback. It
-is managed by the enterprise device policies only.
-
-Developers should be careful when touching any rollback related feature and make
-sure they know exactly which of these two features they are trying to adapt.
+
### Interactive vs Non-Interactive vs. Forced Updates
@@ -203,19 +197,6 @@ time. We can call a forced non-interactive update with:
update_engine_client --interactive=false --check_for_update
```
-### P2P Updates
-
-Many organizations might not have the external bandwidth requirements that
-system updates need for all their devices. To help with this, Chrome OS can act
-as a payload server to other client devices in the same network subnet. This is
-basically a peer-to-peer update system that allows the devices to download the
-update payloads from other devices in the network. This has to be enabled
-explicitly in the organization through device policies and specific network
-configurations to be enabled for P2P updates to work. Regardless of the location
-of update payloads, all update requests go through update servers in HTTPS.
-
-Check out the [P2P update related code] for both the server and the client side.
-
### Network
The updater client has the capability to download the payloads using Ethernet,
@@ -233,6 +214,8 @@ current data-time format in the log file’s name
system reboots. The latest active log is symlinked to
`/var/log/update_engine.log`.
+In Android the `update_engine` logs are located in `/data/misc/update_engine_log`.
+
## Update Payload Generation
The update payload generation is the process of converting a set of
@@ -242,18 +225,6 @@ process involves breaking the input partitions into smaller components and
compressing them in order to help with network bandwidth when downloading the
payloads.
-For each generated payload, there is a corresponding properties file which
-contains the metadata information of the payload in JSON format. Normally the
-file is located in the same location as the generated payload and its file name
-is the same as the payload file name plus `.json`
-postfix. e.g. `/path/to/payload.bin` and `/path/to/payload.bin.json`. This
-properties file is necessary in order to do any kind of auto update in [`cros
-flash`], AU autotests, etc. Similarly the updater server uses this file to
-dispatch the payload properties to the updater clients.
-
-Once update payloads are generated, their original images cannot be changed
-anymore otherwise the update payloads may not be able to be applied.
-
`delta_generator` is a tool with a wide range of options for generating
different types of update payloads. Its code is located in
`update_engine/payload_generator`. This directory contains all the source code
@@ -262,27 +233,25 @@ directory should be included or used in any other library/executable other than
the `delta_generator` which means this directory does not get compiled into the
rest of the update engine tools.
-However, it is not recommended to use `delta_generator` directly. To manually
-generate payloads easier, [`cros_generate_update_payloads`] should be used. Most
-of the higher level policies and tools for generating payloads reside as a
-library in [`chromite/lib/paygen`]. Whenever calls to the update payload
-generation API are needed, this library should be used instead.
+However, it is not recommended to use `delta_generator` directly, as it has way
+too many flags. Wrappers like [ota_from_target_files](https://cs.android.com/android/platform/superproject/+/master:build/make/tools/releasetools/ota_from_target_files.py)
+or [OTA Generator](https://github.com/google/ota-generator) should be used.
### Update Payload File Specification
Each update payload file has a specific structure defined in the table below:
-|Field|Size (bytes)|Type|Description|
-|-----|------------|----|-----------|
-|Magic Number|4|char[4]|Magic string "CrAU" identifying this is an update payload.|
-|Major Version|8|uint64|Payload major version number.|
-|Manifest Size|8|uint64|Manifest size in bytes.|
-|Manifest Signature Size|4|uint32|Manifest signature blob size in bytes (only in major version 2).|
-|Manifest|Varies|[DeltaArchiveManifest]|The list of operations to be performed.|
-|Manifest Signature|Varies|[Signatures]|The signature of the first five fields. There could be multiple signatures if the key has changed.|
-|Payload Data|Varies|List of raw or compressed data blobs|The list of binary blobs used by operations in the metadata.|
-|Payload Signature Size|Varies|uint64|The size of the payload signature.|
-|Payload Signature|Varies|[Signatures]|The signature of the entire payload except the metadata signature. There could be multiple signatures if the key has changed.|
+| Field | Size (bytes) | Type | Description |
+| ----------------------- | ------------ | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
+| Magic Number | 4 | char[4] | Magic string "CrAU" identifying this is an update payload. |
+| Major Version | 8 | uint64 | Payload major version number. |
+| Manifest Size | 8 | uint64 | Manifest size in bytes. |
+| Manifest Signature Size | 4 | uint32 | Manifest signature blob size in bytes (only in major version 2). |
+| Manifest | Varies | [DeltaArchiveManifest] | The list of operations to be performed. |
+| Manifest Signature | Varies | [Signatures] | The signature of the first five fields. There could be multiple signatures if the key has changed. |
+| Payload Data | Varies | List of raw or compressed data blobs | The list of binary blobs used by operations in the metadata. |
+| Payload Signature Size | Varies | uint64 | The size of the payload signature. |
+| Payload Signature | Varies | [Signatures] | The signature of the entire payload except the metadata signature. There could be multiple signatures if the key has changed. |
### Delta vs. Full Update Payloads
@@ -414,93 +383,27 @@ rebooted, should be implemented inside the postinstall.
You can build `update_engine` the same as other platform applications:
-```bash
-(chroot) $ emerge-${BOARD} update_engine
-```
-or to build without the source copy:
-
-```bash
-(chroot) $ cros_workon_make --board=${BOARD} update_engine
-```
-
-After a change in the `update_engine` daemon, either build an image and install
-the image on the device using cros flash, etc. or use `cros deploy` to only
-install the `update_engine` service on the device:
-
-```bash
-(chroot) $ cros deploy update_engine
-```
-
-You need to restart the `update_engine` daemon in order to see the affected
-changes:
-
-```bash
-# SSH into the device.
-restart update-engine # with a dash not underscore.
-```
-
-Other payload generation tools like `delta_generator` are board agnostic and
-only available in the SDK. So in order to make any changes to the
-`delta_generator`, you should build the SDK:
+### Setup
-```bash
-# Do it only once to start building the 9999 ebuild from ToT.
-(chroot) $ cros_workon --host start update_engine
+Run these commands at top of Android repository before building anything.
+You only need to do this once per shell.
-(chroot) $ sudo emerge update_engine
-```
+* `source build/envsetup.sh`
+* `lunch aosp_cf_x86_64_only_phone-userdebug` (Or replace aosp_cf_x86_64_only_phone-userdebug with your own target)
-If you make any changes to the D-Bus interface make sure `system_api`,
-`update_engine-client`, and `update_engine` packages are marked to build from
-9999 ebuild and then build both packages in that order:
-```bash
-(chroot) $ emerge-${BOARD} system_api update_engine-client update_engine
-```
+### Building
-If you make any changes to [`update_engine` protobufs] in the `system_api`,
-build the `system_api` package first.
+`m update_engine update_engine_client delta_generator`
## Running Unit Tests
[Running unit tests similar to other platforms]:
-```bash
-(chroot) $ FEATURES=test emerge-<board> update_engine
-```
-
-or
-
-```bash
-(chroot) $ cros_workon_make --board=<board> --test update_engine
-```
-
-or
-
-```bash
-(chroot) $ cros_run_unit_tests --board ${BOARD} --packages update_engine
-```
-
-The above commands run all the unit tests, but `update_engine` package is quite
-large and it takes a long time to run all the unit tests. To run all unit tests
-in a test class run:
-
-```bash
-(chroot) $ FEATURES=test \
- P2_TEST_FILTER="*OmahaRequestActionTest.*-*RunAsRoot*" \
- emerge-amd64-generic update_engine
-```
-
-To run one exact unit test fixture (e.g. `MultiAppUpdateTest`), run:
-
-```bash
-(chroot) $ FEATURES=test \
- P2_TEST_FILTER="*OmahaRequestActionTest.MultiAppUpdateTest-*RunAsRoot*" \
- emerge-amd64-generic update_engine
-```
-
-To run `update_payload` unit tests enter `update_engine/scripts` directory and
-run the desired `unittest.p`y files.
+* `atest update_engine_unittests` You will need a device connected to
+ your laptop and accessible via ADB to do this. Cuttlefish works as well.
+* `atest update_engine_host_unittests` Run a subset of tests on host, no device
+required.
## Initiating a Configured Update
@@ -508,37 +411,9 @@ There are different methods to initiate an update:
* Click on the “Check For Update” button in setting’s About page. There is no
way to configure this way of update check.
-* Use the [`update_engine_client`] program. There are a few configurations you
- can do.
-* Call `autest` in the crosh. Mainly used by the QA team and is not intended
- to be used by any other team.
-* Use [`cros flash`]. It internally uses the update_engine to flash a device
- with a given image.
-* Run one of many auto update autotests.
-* Start a [Dev Server] on your host machine and send a specific HTTP request
- (look at `cros_au` API in the Dev Server code), that has the information
- like the IP address of your Chromebook and where the update payloads are
- located to the Dev Server to start an update on your device (**Warning:**
- complicated to do, not recommended).
-
-`update_engine_client` is a client application that can help initiate an update
-or get more information about the status of the updater client. It has several
-options like initiating an interactive vs. non-interactive update, changing
-channels, getting the current status of update process, doing a rollback,
-changing the Omaha URL to download the payload (the most important one), etc.
-
-`update_engine` daemon reads the `/etc/lsb-release` file on the device to
-identify different update parameters like the updater server (Omaha) URL, the
-current channel, etc. However, to override any of these parameters, create the
-file `/mnt/stateful_partition/etc/lsb-release` with desired customized
-parameters. For example, this can be used to point to a developer version of the
-update server and allow the update_engine to schedule a periodic update from
-that specific server.
-
-If you have some changes in the protocol that communicates with Omaha, but you
-don’t have those changes in the update server, or you have some specific
-payloads that do not exist on the production update server you can use
-[Nebraska] to help with doing an update.
+* Use the [`scripts/update_device.py`] program and pass a path to your OTA zip file.
+
+
## Note to Developers and Maintainers
@@ -583,8 +458,11 @@ off greatly in the future.
### Be Respectful Of Other Code Bases
-The current update engine code base is used in many projects like Android. We
-sync the code base among these two projects frequently. Try to not break Android
+~~The current update engine code base is used in many projects like Android.~~~
+
+The Android and ChromeOS codebase have officially diverged.
+
+We sync the code base among these two projects frequently. Try to not break Android
or other systems that share the update engine code. Whenever landing a change,
always think about whether Android needs that change:
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 00000000..3a9a2389
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+ "presubmit": [
+ {
+ "name": "update_engine_unittests"
+ },
+ {
+ "name": "update_engine_http_unittests"
+ }
+ ]
+}
diff --git a/aosp/apex_handler_android_unittest.cc b/aosp/apex_handler_android_unittest.cc
index 847ccaad..8c58e47a 100644
--- a/aosp/apex_handler_android_unittest.cc
+++ b/aosp/apex_handler_android_unittest.cc
@@ -14,8 +14,8 @@
// limitations under the License.
//
-#include <utility>
#include <filesystem>
+#include <utility>
#include "update_engine/aosp/apex_handler_android.h"
diff --git a/aosp/binder_service_android.cc b/aosp/binder_service_android.cc
index ed76c4a8..84b5b7a9 100644
--- a/aosp/binder_service_android.cc
+++ b/aosp/binder_service_android.cc
@@ -157,6 +157,24 @@ Status BinderUpdateEngineAndroidService::resetStatus() {
return Status::ok();
}
+Status BinderUpdateEngineAndroidService::setShouldSwitchSlotOnReboot(
+ const android::String16& metadata_filename) {
+ brillo::ErrorPtr error;
+ if (!service_delegate_->setShouldSwitchSlotOnReboot(
+ android::String8(metadata_filename).string(), &error)) {
+ return ErrorPtrToStatus(error);
+ }
+ return Status::ok();
+}
+
+Status BinderUpdateEngineAndroidService::resetShouldSwitchSlotOnReboot() {
+ brillo::ErrorPtr error;
+ if (!service_delegate_->resetShouldSwitchSlotOnReboot(&error)) {
+ return ErrorPtrToStatus(error);
+ }
+ return Status::ok();
+}
+
Status BinderUpdateEngineAndroidService::verifyPayloadApplicable(
const android::String16& metadata_filename, bool* return_value) {
const std::string payload_metadata{
diff --git a/aosp/binder_service_android.h b/aosp/binder_service_android.h
index f41fbdf2..f1ce6b5d 100644
--- a/aosp/binder_service_android.h
+++ b/aosp/binder_service_android.h
@@ -68,6 +68,9 @@ class BinderUpdateEngineAndroidService : public android::os::BnUpdateEngine,
android::binder::Status resume() override;
android::binder::Status cancel() override;
android::binder::Status resetStatus() override;
+ android::binder::Status setShouldSwitchSlotOnReboot(
+ const android::String16& metadata_filename) override;
+ android::binder::Status resetShouldSwitchSlotOnReboot() override;
android::binder::Status verifyPayloadApplicable(
const android::String16& metadata_filename, bool* return_value) override;
android::binder::Status allocateSpaceForPayload(
diff --git a/aosp/boot_control_android.cc b/aosp/boot_control_android.cc
index c1ac0d42..88a9c176 100644
--- a/aosp/boot_control_android.cc
+++ b/aosp/boot_control_android.cc
@@ -20,6 +20,7 @@
#include <utility>
#include <vector>
+#include <android/hardware/boot/1.2/IBootControl.h>
#include <base/bind.h>
#include <base/logging.h>
#include <bootloader_message/bootloader_message.h>
@@ -177,6 +178,18 @@ bool BootControlAndroid::IsSlotMarkedSuccessful(
return ret == BoolResult::TRUE;
}
+Slot BootControlAndroid::GetActiveBootSlot() {
+ namespace V1_2 = android::hardware::boot::V1_2;
+ using android::sp;
+ sp<V1_2::IBootControl> v1_2_module = V1_2::IBootControl::castFrom(module_);
+ if (v1_2_module != nullptr) {
+ return v1_2_module->getActiveBootSlot();
+ }
+ LOG(WARNING) << "BootControl module version is lower than 1.2, "
+ << __FUNCTION__ << " failed";
+ return kInvalidSlot;
+}
+
DynamicPartitionControlInterface*
BootControlAndroid::GetDynamicPartitionControl() {
return dynamic_control_.get();
diff --git a/aosp/boot_control_android.h b/aosp/boot_control_android.h
index 926023a1..9012032a 100644
--- a/aosp/boot_control_android.h
+++ b/aosp/boot_control_android.h
@@ -23,6 +23,7 @@
#include <android/hardware/boot/1.0/IBootControl.h>
#include <liblp/builder.h>
+#include <gtest/gtest_prod.h>
#include "update_engine/aosp/dynamic_partition_control_android.h"
#include "update_engine/common/boot_control.h"
@@ -32,7 +33,7 @@ namespace chromeos_update_engine {
// The Android implementation of the BootControlInterface. This implementation
// uses the libhardware's boot_control HAL to access the bootloader.
-class BootControlAndroid : public BootControlInterface {
+class BootControlAndroid final : public BootControlInterface {
public:
BootControlAndroid() = default;
~BootControlAndroid() = default;
@@ -62,6 +63,7 @@ class BootControlAndroid : public BootControlInterface {
bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
bool IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const override;
+ Slot GetActiveBootSlot() override;
DynamicPartitionControlInterface* GetDynamicPartitionControl() override;
private:
@@ -69,6 +71,7 @@ class BootControlAndroid : public BootControlInterface {
std::unique_ptr<DynamicPartitionControlAndroid> dynamic_control_;
friend class BootControlAndroidTest;
+ friend class UpdateAttempterAndroidIntegrationTest;
DISALLOW_COPY_AND_ASSIGN(BootControlAndroid);
};
diff --git a/aosp/cleanup_previous_update_action.cc b/aosp/cleanup_previous_update_action.cc
index 53cb9933..55dba1e9 100644
--- a/aosp/cleanup_previous_update_action.cc
+++ b/aosp/cleanup_previous_update_action.cc
@@ -276,7 +276,17 @@ void CleanupPreviousUpdateAction::ScheduleWaitForMerge() {
void CleanupPreviousUpdateAction::WaitForMergeOrSchedule() {
AcknowledgeTaskExecuted();
TEST_AND_RETURN(running_);
+
auto update_uses_compression = snapshot_->UpdateUsesCompression();
+
+ // Propagate the merge failure code to the merge stats. If we wait until
+ // after ProcessUpdateState, then a successful merge could overwrite the
+ // state of the previous failure.
+ auto failure_code = snapshot_->ReadMergeFailureCode();
+ if (failure_code != android::snapshot::MergeFailureCode::Ok) {
+ merge_stats_->set_merge_failure_code(failure_code);
+ }
+
auto state = snapshot_->ProcessUpdateState(
std::bind(&CleanupPreviousUpdateAction::OnMergePercentageUpdate, this),
std::bind(&CleanupPreviousUpdateAction::BeforeCancel, this));
diff --git a/aosp/cow_converter.cc b/aosp/cow_converter.cc
index 8c641b8d..2f93e3ad 100644
--- a/aosp/cow_converter.cc
+++ b/aosp/cow_converter.cc
@@ -14,6 +14,7 @@
// limitations under the License.
//
+#include <fcntl.h>
#include <stdio.h>
#include <string.h>
@@ -21,7 +22,6 @@
#include <cstdio>
#include <memory>
-#include <sys/fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
@@ -60,11 +60,14 @@ bool ProcessPartition(const chromeos_update_engine::PartitionUpdate& partition,
android::snapshot::CowWriter cow_writer{
{.block_size = static_cast<uint32_t>(block_size), .compression = "gz"}};
TEST_AND_RETURN_FALSE(cow_writer.Initialize(output_fd));
- TEST_AND_RETURN_FALSE(CowDryRun(target_img_fd,
+ TEST_AND_RETURN_FALSE(CowDryRun(nullptr,
+ target_img_fd,
partition.operations(),
partition.merge_operations(),
block_size,
- &cow_writer));
+ &cow_writer,
+ partition.new_partition_info().size(),
+ false));
TEST_AND_RETURN_FALSE(cow_writer.Finalize());
return true;
}
@@ -121,11 +124,38 @@ int main(int argc, const char* argv[]) {
return 5;
}
+ size_t estimated_total_cow_size = 0;
+ size_t actual_total_cow_size = 0;
+
for (const auto& partition : manifest.partitions()) {
+ if (partition.estimate_cow_size() == 0) {
+ continue;
+ }
LOG(INFO) << partition.partition_name();
if (!ProcessPartition(partition, images_dir, manifest.block_size())) {
return 6;
}
+ base::FilePath img_dir{images_dir};
+ const auto output_cow =
+ img_dir.Append(partition.partition_name() + ".cow").value();
+ const auto actual_cow_size =
+ chromeos_update_engine::utils::FileSize(output_cow);
+ LOG(INFO) << partition.partition_name()
+ << ": estimated COW size is: " << partition.estimate_cow_size()
+ << ", actual COW size is: " << actual_cow_size
+ << ", estimated COW size is "
+ << (actual_cow_size - partition.estimate_cow_size()) * 100.0f /
+ actual_cow_size
+ << "% smaller";
+ estimated_total_cow_size += partition.estimate_cow_size();
+ actual_total_cow_size += actual_cow_size;
}
+
+ LOG(INFO) << "Total estimated COW size is: " << estimated_total_cow_size
+ << ", Total actual COW size is: " << actual_total_cow_size
+ << ", estimated COW size is "
+ << (actual_total_cow_size - estimated_total_cow_size) * 100.0f /
+ actual_total_cow_size
+ << "% smaller";
return 0;
}
diff --git a/aosp/dynamic_partition_control_android.cc b/aosp/dynamic_partition_control_android.cc
index 538b57ce..27d1d541 100644
--- a/aosp/dynamic_partition_control_android.cc
+++ b/aosp/dynamic_partition_control_android.cc
@@ -82,6 +82,8 @@ constexpr char kVirtualAbEnabled[] = "ro.virtual_ab.enabled";
constexpr char kVirtualAbRetrofit[] = "ro.virtual_ab.retrofit";
constexpr char kVirtualAbCompressionEnabled[] =
"ro.virtual_ab.compression.enabled";
+constexpr auto&& kVirtualAbCompressionXorEnabled =
+ "ro.virtual_ab.compression.xor.enabled";
// Currently, android doesn't have a retrofit prop for VAB Compression. However,
// struct FeatureFlag forces us to determine if a feature is 'retrofit'. So this
@@ -93,7 +95,7 @@ constexpr char kPostinstallFstabPrefix[] = "ro.postinstall.fstab.prefix";
constexpr std::chrono::milliseconds kMapTimeout{1000};
// Map timeout for dynamic partitions with snapshots. Since several devices
// needs to be mapped, this timeout is longer than |kMapTimeout|.
-constexpr std::chrono::milliseconds kMapSnapshotTimeout{5000};
+constexpr std::chrono::milliseconds kMapSnapshotTimeout{10000};
DynamicPartitionControlAndroid::~DynamicPartitionControlAndroid() {
Cleanup();
@@ -126,6 +128,8 @@ DynamicPartitionControlAndroid::DynamicPartitionControlAndroid(
virtual_ab_(GetFeatureFlag(kVirtualAbEnabled, kVirtualAbRetrofit)),
virtual_ab_compression_(GetFeatureFlag(kVirtualAbCompressionEnabled,
kVirtualAbCompressionRetrofit)),
+ virtual_ab_compression_xor_(
+ GetFeatureFlag(kVirtualAbCompressionXorEnabled, "")),
source_slot_(source_slot) {
if (GetVirtualAbFeatureFlag().IsEnabled()) {
snapshot_ = SnapshotManager::New();
@@ -152,6 +156,11 @@ DynamicPartitionControlAndroid::GetVirtualAbCompressionFeatureFlag() {
return virtual_ab_compression_;
}
+FeatureFlag
+DynamicPartitionControlAndroid::GetVirtualAbCompressionXorFeatureFlag() {
+ return virtual_ab_compression_xor_;
+}
+
bool DynamicPartitionControlAndroid::OptimizeOperation(
const std::string& partition_name,
const InstallOperation& operation,
@@ -465,6 +474,9 @@ bool DynamicPartitionControlAndroid::PreparePartitionsForUpdate(
if (!SetTargetBuildVars(manifest)) {
return false;
}
+ for (auto& list : dynamic_partition_list_) {
+ list.clear();
+ }
// Although the current build supports dynamic partitions, the given payload
// doesn't use it for target partitions. This could happen when applying a
@@ -1280,6 +1292,9 @@ bool DynamicPartitionControlAndroid::ResetUpdate(PrefsInterface* prefs) {
if (!GetVirtualAbFeatureFlag().IsEnabled()) {
return true;
}
+ for (auto& list : dynamic_partition_list_) {
+ list.clear();
+ }
LOG(INFO) << __func__ << " resetting update state and deleting snapshots.";
TEST_AND_RETURN_FALSE(prefs != nullptr);
@@ -1420,7 +1435,7 @@ DynamicPartitionControlAndroid::OpenCowWriter(
return snapshot_->OpenSnapshotWriter(params, std::move(source_path));
} // namespace chromeos_update_engine
-FileDescriptorPtr DynamicPartitionControlAndroid::OpenCowFd(
+std::unique_ptr<FileDescriptor> DynamicPartitionControlAndroid::OpenCowFd(
const std::string& unsuffixed_partition_name,
const std::optional<std::string>& source_path,
bool is_append) {
@@ -1430,9 +1445,16 @@ FileDescriptorPtr DynamicPartitionControlAndroid::OpenCowFd(
return nullptr;
}
if (!cow_writer->InitializeAppend(kEndOfInstallLabel)) {
+ LOG(ERROR) << "Failed to InitializeAppend(" << kEndOfInstallLabel << ")";
+ return nullptr;
+ }
+ auto reader = cow_writer->OpenReader();
+ if (reader == nullptr) {
+ LOG(ERROR) << "ICowWriter::OpenReader() failed.";
return nullptr;
}
- return std::make_shared<CowWriterFileDescriptor>(std::move(cow_writer));
+ return std::make_unique<CowWriterFileDescriptor>(std::move(cow_writer),
+ std::move(reader));
}
std::optional<base::FilePath> DynamicPartitionControlAndroid::GetSuperDevice() {
diff --git a/aosp/dynamic_partition_control_android.h b/aosp/dynamic_partition_control_android.h
index df914018..92761d22 100644
--- a/aosp/dynamic_partition_control_android.h
+++ b/aosp/dynamic_partition_control_android.h
@@ -21,7 +21,7 @@
#include <set>
#include <string>
#include <string_view>
-#include <vector>
+#include <array>
#include <base/files/file_util.h>
#include <libsnapshot/auto_device.h>
@@ -44,6 +44,7 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
FeatureFlag GetDynamicPartitionsFeatureFlag() override;
FeatureFlag GetVirtualAbFeatureFlag() override;
FeatureFlag GetVirtualAbCompressionFeatureFlag() override;
+ FeatureFlag GetVirtualAbCompressionXorFeatureFlag() override;
bool OptimizeOperation(const std::string& partition_name,
const InstallOperation& operation,
InstallOperation* optimized) override;
@@ -104,16 +105,20 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
const std::string& unsuffixed_partition_name,
const std::optional<std::string>& source_path,
bool is_append) override;
- FileDescriptorPtr OpenCowFd(const std::string& unsuffixed_partition_name,
- const std::optional<std::string>&,
- bool is_append = false) override;
+ std::unique_ptr<FileDescriptor> OpenCowFd(
+ const std::string& unsuffixed_partition_name,
+ const std::optional<std::string>&,
+ bool is_append = false) override;
+ bool MapAllPartitions() override;
bool UnmapAllPartitions() override;
bool IsDynamicPartition(const std::string& part_name, uint32_t slot) override;
bool UpdateUsesSnapshotCompression() override;
+ std::optional<base::FilePath> GetSuperDevice();
+
protected:
// These functions are exposed for testing.
@@ -225,8 +230,6 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
const DeltaArchiveManifest& manifest,
bool delete_source);
- bool MapAllPartitions() override;
-
void SetSourceSlot(uint32_t slot) { source_slot_ = slot; }
void SetTargetSlot(uint32_t slot) { target_slot_ = slot; }
@@ -234,8 +237,6 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
friend class DynamicPartitionControlAndroidTest;
friend class SnapshotPartitionTestP;
- std::optional<base::FilePath> GetSuperDevice();
-
bool MapPartitionInternal(const std::string& super_device,
const std::string& target_partition_name,
uint32_t slot,
@@ -339,6 +340,7 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
const FeatureFlag dynamic_partitions_;
const FeatureFlag virtual_ab_;
const FeatureFlag virtual_ab_compression_;
+ const FeatureFlag virtual_ab_compression_xor_;
std::unique_ptr<android::snapshot::ISnapshotManager> snapshot_;
std::unique_ptr<android::snapshot::AutoDevice> metadata_device_;
bool target_supports_snapshot_ = false;
@@ -348,7 +350,9 @@ class DynamicPartitionControlAndroid : public DynamicPartitionControlInterface {
uint32_t source_slot_ = UINT32_MAX;
uint32_t target_slot_ = UINT32_MAX;
- std::vector<std::vector<std::string>> dynamic_partition_list_{2UL};
+ // We assume that there's only 2 slots, A and B. This assumption is unlikely
+ // to change in the future. And certaintly won't change at runtime.
+ std::array<std::vector<std::string>, 2> dynamic_partition_list_{};
DISALLOW_COPY_AND_ASSIGN(DynamicPartitionControlAndroid);
};
diff --git a/aosp/mock_dynamic_partition_control_android.h b/aosp/mock_dynamic_partition_control_android.h
index 428b6c7a..f55cdf78 100644
--- a/aosp/mock_dynamic_partition_control_android.h
+++ b/aosp/mock_dynamic_partition_control_android.h
@@ -73,6 +73,10 @@ class MockDynamicPartitionControlAndroid
MOCK_METHOD(std::string, GetSuperPartitionName, (uint32_t), (override));
MOCK_METHOD(FeatureFlag, GetVirtualAbFeatureFlag, (), (override));
MOCK_METHOD(FeatureFlag, GetVirtualAbCompressionFeatureFlag, (), (override));
+ MOCK_METHOD(FeatureFlag,
+ GetVirtualAbCompressionXorFeatureFlag,
+ (),
+ (override));
MOCK_METHOD(bool, FinishUpdate, (bool), (override));
MOCK_METHOD(bool,
GetSystemOtherPath,
@@ -94,7 +98,7 @@ class MockDynamicPartitionControlAndroid
const std::optional<std::string>& source_path,
bool is_append),
(override));
- MOCK_METHOD(FileDescriptorPtr,
+ MOCK_METHOD(std::unique_ptr<FileDescriptor>,
OpenCowFd,
(const std::string& unsuffixed_partition_name,
const std::optional<std::string>& source_path,
diff --git a/aosp/ota_extractor.cc b/aosp/ota_extractor.cc
new file mode 100644
index 00000000..4a57370f
--- /dev/null
+++ b/aosp/ota_extractor.cc
@@ -0,0 +1,280 @@
+//
+// Copyright (C) 2022 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 <array>
+#include <cstdint>
+#include <cstdio>
+#include <iterator>
+#include <memory>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <android-base/strings.h>
+#include <base/files/file_path.h>
+#include <gflags/gflags.h>
+#include <unistd.h>
+#include <xz.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/file_descriptor_utils.h"
+#include "update_engine/payload_consumer/install_operation_executor.h"
+#include "update_engine/payload_consumer/payload_metadata.h"
+#include "update_engine/payload_consumer/verity_writer_android.h"
+#include "update_engine/update_metadata.pb.h"
+
+DEFINE_string(payload, "", "Path to payload.bin");
+DEFINE_string(
+ input_dir,
+ "",
+ "Directory to read input images. Only required for incremental OTAs");
+DEFINE_string(output_dir, "", "Directory to put output images");
+DEFINE_int64(payload_offset,
+ 0,
+ "Offset to start of payload.bin. Useful if payload path actually "
+ "points to a .zip file containing payload.bin");
+DEFINE_string(partitions,
+ "",
+ "Comma separated list of partitions to extract, leave empty for "
+ "extracting all partitions");
+
+using chromeos_update_engine::DeltaArchiveManifest;
+using chromeos_update_engine::PayloadMetadata;
+
+namespace chromeos_update_engine {
+
+void WriteVerity(const PartitionUpdate& partition,
+ FileDescriptorPtr fd,
+ const size_t block_size) {
+ // 512KB buffer, arbitrary value. Larger buffers may improve performance.
+ static constexpr size_t BUFFER_SIZE = 1024 * 512;
+ if (partition.hash_tree_extent().num_blocks() == 0 &&
+ partition.fec_extent().num_blocks() == 0) {
+ return;
+ }
+ InstallPlan::Partition install_part;
+ install_part.block_size = block_size;
+ CHECK(install_part.ParseVerityConfig(partition));
+ VerityWriterAndroid writer;
+ CHECK(writer.Init(install_part));
+ std::array<uint8_t, BUFFER_SIZE> buffer;
+ const auto data_size =
+ install_part.hash_tree_data_offset + install_part.hash_tree_data_size;
+ size_t offset = 0;
+ while (offset < data_size) {
+ const auto bytes_to_read =
+ static_cast<ssize_t>(std::min(BUFFER_SIZE, data_size - offset));
+ ssize_t bytes_read;
+ CHECK(
+ utils::ReadAll(fd, buffer.data(), bytes_to_read, offset, &bytes_read));
+ CHECK_EQ(bytes_read, bytes_to_read)
+ << " Failed to read at offset " << offset << " "
+ << android::base::ErrnoNumberAsString(errno);
+ writer.Update(offset, buffer.data(), bytes_read);
+ offset += bytes_read;
+ }
+ CHECK(writer.Finalize(fd.get(), fd.get()));
+ return;
+}
+
+bool ExtractImagesFromOTA(const DeltaArchiveManifest& manifest,
+ const PayloadMetadata& metadata,
+ int payload_fd,
+ size_t payload_offset,
+ std::string_view input_dir,
+ std::string_view output_dir,
+ const std::set<std::string>& partitions) {
+ InstallOperationExecutor executor(manifest.block_size());
+ const size_t data_begin = metadata.GetMetadataSize() +
+ metadata.GetMetadataSignatureSize() +
+ payload_offset;
+ const base::FilePath output_dir_path(
+ base::StringPiece(output_dir.data(), output_dir.size()));
+ const base::FilePath input_dir_path(
+ base::StringPiece(input_dir.data(), input_dir.size()));
+ std::vector<unsigned char> blob;
+ for (const auto& partition : manifest.partitions()) {
+ if (!partitions.empty() &&
+ partitions.count(partition.partition_name()) == 0) {
+ continue;
+ }
+ LOG(INFO) << "Extracting partition " << partition.partition_name()
+ << " size: " << partition.new_partition_info().size();
+ const auto output_path =
+ output_dir_path.Append(partition.partition_name() + ".img").value();
+ auto out_fd =
+ std::make_shared<chromeos_update_engine::EintrSafeFileDescriptor>();
+ TEST_AND_RETURN_FALSE_ERRNO(
+ out_fd->Open(output_path.c_str(), O_RDWR | O_CREAT, 0644));
+ auto in_fd =
+ std::make_shared<chromeos_update_engine::EintrSafeFileDescriptor>();
+ if (partition.has_old_partition_info()) {
+ const auto input_path =
+ input_dir_path.Append(partition.partition_name() + ".img").value();
+ LOG(INFO) << "Incremental OTA detected for partition "
+ << partition.partition_name() << " opening source image "
+ << input_path;
+ CHECK(in_fd->Open(input_path.c_str(), O_RDONLY))
+ << " failed to open " << input_path;
+ }
+
+ for (const auto& op : partition.operations()) {
+ if (op.has_src_sha256_hash()) {
+ brillo::Blob actual_hash;
+ TEST_AND_RETURN_FALSE(fd_utils::ReadAndHashExtents(
+ in_fd, op.src_extents(), manifest.block_size(), &actual_hash));
+ CHECK_EQ(HexEncode(ToStringView(actual_hash)),
+ HexEncode(op.src_sha256_hash()));
+ }
+
+ blob.resize(op.data_length());
+ const auto op_data_offset = data_begin + op.data_offset();
+ ssize_t bytes_read = 0;
+ TEST_AND_RETURN_FALSE(utils::PReadAll(
+ payload_fd, blob.data(), blob.size(), op_data_offset, &bytes_read));
+ if (op.has_data_sha256_hash()) {
+ brillo::Blob actual_hash;
+ TEST_AND_RETURN_FALSE(
+ HashCalculator::RawHashOfData(blob, &actual_hash));
+ CHECK_EQ(HexEncode(ToStringView(actual_hash)),
+ HexEncode(op.data_sha256_hash()));
+ }
+ auto direct_writer = std::make_unique<DirectExtentWriter>(out_fd);
+ if (op.type() == InstallOperation::ZERO) {
+ TEST_AND_RETURN_FALSE(executor.ExecuteZeroOrDiscardOperation(
+ op, std::move(direct_writer)));
+ } else if (op.type() == InstallOperation::REPLACE ||
+ op.type() == InstallOperation::REPLACE_BZ ||
+ op.type() == InstallOperation::REPLACE_XZ) {
+ TEST_AND_RETURN_FALSE(executor.ExecuteReplaceOperation(
+ op, std::move(direct_writer), blob.data(), blob.size()));
+ } else if (op.type() == InstallOperation::SOURCE_COPY) {
+ CHECK(in_fd->IsOpen());
+ TEST_AND_RETURN_FALSE(executor.ExecuteSourceCopyOperation(
+ op, std::move(direct_writer), in_fd));
+ } else {
+ CHECK(in_fd->IsOpen());
+ TEST_AND_RETURN_FALSE(executor.ExecuteDiffOperation(
+ op, std::move(direct_writer), in_fd, blob.data(), blob.size()));
+ }
+ }
+ WriteVerity(partition, out_fd, manifest.block_size());
+ int err =
+ truncate64(output_path.c_str(), partition.new_partition_info().size());
+ if (err) {
+ PLOG(ERROR) << "Failed to truncate " << output_path << " to "
+ << partition.new_partition_info().size();
+ }
+ brillo::Blob actual_hash;
+ TEST_AND_RETURN_FALSE(
+ HashCalculator::RawHashOfFile(output_path, &actual_hash));
+ CHECK_EQ(HexEncode(ToStringView(actual_hash)),
+ HexEncode(partition.new_partition_info().hash()))
+ << " Partition " << partition.partition_name()
+ << " hash mismatches. Either the source image or OTA package is "
+ "corrupted.";
+ }
+ return true;
+}
+
+} // namespace chromeos_update_engine
+
+namespace {
+
+bool IsIncrementalOTA(const DeltaArchiveManifest& manifest) {
+ for (const auto& part : manifest.partitions()) {
+ if (part.has_old_partition_info()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ gflags::SetUsageMessage(
+ "A tool to extract device images from Android OTA packages");
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
+ xz_crc32_init();
+ auto tokens = android::base::Tokenize(FLAGS_partitions, ",");
+ const std::set<std::string> partitions(
+ std::make_move_iterator(tokens.begin()),
+ std::make_move_iterator(tokens.end()));
+ if (FLAGS_payload.empty()) {
+ LOG(ERROR) << "--payload <payload path> is required";
+ return 1;
+ }
+ if (!partitions.empty()) {
+ LOG(INFO) << "Extracting " << android::base::Join(partitions, ", ");
+ }
+ int payload_fd = open(FLAGS_payload.c_str(), O_RDONLY | O_CLOEXEC);
+ if (payload_fd < 0) {
+ PLOG(ERROR) << "Failed to open payload file";
+ return 1;
+ }
+ chromeos_update_engine::ScopedFdCloser closer{&payload_fd};
+ auto payload_size = chromeos_update_engine::utils::FileSize(payload_fd);
+ if (payload_size <= 0) {
+ PLOG(ERROR)
+ << "Couldn't determine size of payload file, or payload file is empty";
+ return 1;
+ }
+
+ PayloadMetadata payload_metadata;
+ auto payload = static_cast<unsigned char*>(
+ mmap(nullptr, payload_size, PROT_READ, MAP_PRIVATE, payload_fd, 0));
+
+ if (payload == MAP_FAILED) {
+ PLOG(ERROR) << "Failed to mmap() payload file";
+ return 1;
+ }
+
+ auto munmap_deleter = [payload_size](auto payload) {
+ munmap(payload, payload_size);
+ };
+ std::unique_ptr<unsigned char, decltype(munmap_deleter)> munmapper{
+ payload, munmap_deleter};
+ if (payload_metadata.ParsePayloadHeader(payload + FLAGS_payload_offset,
+ payload_size - FLAGS_payload_offset,
+ nullptr) !=
+ chromeos_update_engine::MetadataParseResult::kSuccess) {
+ LOG(ERROR) << "Payload header parse failed!";
+ return 1;
+ }
+ DeltaArchiveManifest manifest;
+ if (!payload_metadata.GetManifest(payload + FLAGS_payload_offset,
+ payload_size - FLAGS_payload_offset,
+ &manifest)) {
+ LOG(ERROR) << "Failed to parse manifest!";
+ return 1;
+ }
+ if (IsIncrementalOTA(manifest) && FLAGS_input_dir.empty()) {
+ LOG(ERROR) << FLAGS_payload
+ << " is an incremental OTA, --input_dir parameter is required.";
+ return 1;
+ }
+ return !ExtractImagesFromOTA(manifest,
+ payload_metadata,
+ payload_fd,
+ FLAGS_payload_offset,
+ FLAGS_input_dir,
+ FLAGS_output_dir,
+ partitions);
+}
diff --git a/aosp/service_delegate_android_interface.h b/aosp/service_delegate_android_interface.h
index 3c287940..b3660ab3 100644
--- a/aosp/service_delegate_android_interface.h
+++ b/aosp/service_delegate_android_interface.h
@@ -95,6 +95,17 @@ class ServiceDelegateAndroidInterface {
// In case of error, returns false and sets |error| accordingly.
virtual bool VerifyPayloadApplicable(const std::string& metadata_filename,
brillo::ErrorPtr* error) = 0;
+ // Sets the A/B slot switch for the next boot after applying an ota update.
+ // If applyPayload hasn't switched the slot by itself, the client can call
+ // this API to switch the slot and apply the update on next boot. Returns
+ // true on success.
+ virtual bool setShouldSwitchSlotOnReboot(const std::string& metadata_filename,
+ brillo::ErrorPtr* error) = 0;
+
+ // Resets the boot slot to the source/current slot, without cancelling the
+ // update progress. This can be called after the update is installed, and to
+ // prevent the device from accidentally taking the update when it reboots.
+ virtual bool resetShouldSwitchSlotOnReboot(brillo::ErrorPtr* error) = 0;
// Allocates space for a payload.
// Returns 0 if space is successfully preallocated.
diff --git a/aosp/update_attempter_android.cc b/aosp/update_attempter_android.cc
index 4636c430..a3485eac 100644
--- a/aosp/update_attempter_android.cc
+++ b/aosp/update_attempter_android.cc
@@ -19,6 +19,7 @@
#include <algorithm>
#include <map>
#include <memory>
+#include <ostream>
#include <utility>
#include <android-base/properties.h>
@@ -152,14 +153,50 @@ UpdateAttempterAndroid::~UpdateAttempterAndroid() {
processor_->set_delegate(nullptr);
}
+[[nodiscard]] static bool DidSystemReboot(PrefsInterface* prefs) {
+ string boot_id;
+ TEST_AND_RETURN_FALSE(utils::GetBootId(&boot_id));
+ string old_boot_id;
+ // If no previous boot id found, treat as a reboot and write boot ID.
+ if (!prefs->GetString(kPrefsBootId, &old_boot_id)) {
+ return true;
+ }
+ return old_boot_id != boot_id;
+}
+
+std::ostream& operator<<(std::ostream& out, OTAResult result) {
+ switch (result) {
+ case OTAResult::NOT_ATTEMPTED:
+ out << "OTAResult::NOT_ATTEMPTED";
+ break;
+ case OTAResult::ROLLED_BACK:
+ out << "OTAResult::ROLLED_BACK";
+ break;
+ case OTAResult::UPDATED_NEED_REBOOT:
+ out << "OTAResult::UPDATED_NEED_REBOOT";
+ break;
+ case OTAResult::OTA_SUCCESSFUL:
+ out << "OTAResult::OTA_SUCCESSFUL";
+ break;
+ }
+ return out;
+}
+
void UpdateAttempterAndroid::Init() {
// In case of update_engine restart without a reboot we need to restore the
// reboot needed state.
if (UpdateCompletedOnThisBoot()) {
+ LOG(INFO) << "Updated installed but update_engine is restarted without "
+ "device reboot. Resuming old state.";
SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
} else {
+ const auto result = GetOTAUpdateResult();
+ LOG(INFO) << result;
SetStatusAndNotify(UpdateStatus::IDLE);
- UpdatePrefsAndReportUpdateMetricsOnReboot();
+ if (DidSystemReboot(prefs_)) {
+ UpdateStateAfterReboot(result);
+ }
+
#ifdef _UE_SIDELOAD
LOG(INFO) << "Skip ScheduleCleanupPreviousUpdate in sideload because "
<< "ApplyPayload will call it later.";
@@ -363,60 +400,41 @@ bool UpdateAttempterAndroid::CancelUpdate(brillo::ErrorPtr* error) {
bool UpdateAttempterAndroid::ResetStatus(brillo::ErrorPtr* error) {
LOG(INFO) << "Attempting to reset state from "
<< UpdateStatusToString(status_) << " to UpdateStatus::IDLE";
+ if (processor_->IsRunning()) {
+ return LogAndSetError(
+ error, FROM_HERE, "Already processing an update, cancel it first.");
+ }
if (apex_handler_android_ != nullptr) {
LOG(INFO) << "Cleaning up reserved space for compressed APEX (if any)";
std::vector<ApexInfo> apex_infos_blank;
apex_handler_android_->AllocateSpace(apex_infos_blank);
}
+ // Remove the reboot marker so that if the machine is rebooted
+ // after resetting to idle state, it doesn't go back to
+ // UpdateStatus::UPDATED_NEED_REBOOT state.
+ if (!ClearUpdateCompletedMarker()) {
+ return LogAndSetError(error,
+ FROM_HERE,
+ "Failed to reset the status because "
+ "ClearUpdateCompletedMarker() failed");
+ }
+ if (!boot_control_->GetDynamicPartitionControl()->ResetUpdate(prefs_)) {
+ LOG(WARNING) << "Failed to reset snapshots. UpdateStatus is IDLE but"
+ << "space might not be freed.";
+ }
switch (status_) {
case UpdateStatus::IDLE: {
- if (!boot_control_->GetDynamicPartitionControl()->ResetUpdate(prefs_)) {
- LOG(WARNING) << "Failed to reset snapshots. UpdateStatus is IDLE but"
- << "space might not be freed.";
- }
return true;
}
case UpdateStatus::UPDATED_NEED_REBOOT: {
- bool ret_value = true;
-
- // Update the boot flags so the current slot has higher priority.
- if (!boot_control_->SetActiveBootSlot(GetCurrentSlot()))
- ret_value = false;
-
- // Mark the current slot as successful again, since marking it as active
- // may reset the successful bit. We ignore the result of whether marking
- // the current slot as successful worked.
- if (!boot_control_->MarkBootSuccessfulAsync(Bind([](bool successful) {})))
- ret_value = false;
-
- // Resets the warm reset property since we won't switch the slot.
- hardware_->SetWarmReset(false);
-
- // Resets the vbmeta digest.
- hardware_->SetVbmetaDigestForInactiveSlot(true /* reset */);
-
- // Remove update progress for DeltaPerformer and remove snapshots.
- if (!boot_control_->GetDynamicPartitionControl()->ResetUpdate(prefs_))
- ret_value = false;
-
- // Remove the reboot marker so that if the machine is rebooted
- // after resetting to idle state, it doesn't go back to
- // UpdateStatus::UPDATED_NEED_REBOOT state.
- if (!prefs_->Delete(kPrefsUpdateCompletedOnBootId))
- ret_value = false;
- ClearMetricsPrefs();
-
- if (!ret_value) {
- return LogAndSetError(
- error, FROM_HERE, "Failed to reset the status to ");
+ const bool ret_value = resetShouldSwitchSlotOnReboot(error);
+ if (ret_value) {
+ LOG(INFO) << "Reset status successful";
}
-
- SetStatusAndNotify(UpdateStatus::IDLE);
- LOG(INFO) << "Reset status successful";
- return true;
+ return ret_value;
}
default:
@@ -553,7 +571,9 @@ void UpdateAttempterAndroid::ProcessingDone(const ActionProcessor* processor,
switch (code) {
case ErrorCode::kSuccess:
// Update succeeded.
- WriteUpdateCompletedMarker();
+ if (!WriteUpdateCompletedMarker()) {
+ LOG(ERROR) << "Failed to write update completion marker";
+ }
prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
LOG(INFO) << "Update successfully applied, waiting to reboot.";
@@ -678,6 +698,7 @@ void UpdateAttempterAndroid::OnVerifyProgressUpdate(double progress) {
void UpdateAttempterAndroid::ScheduleProcessingStart() {
LOG(INFO) << "Scheduling an action processor start.";
+ processor_->set_delegate(this);
brillo::MessageLoop::current()->PostTask(
FROM_HERE,
Bind([](ActionProcessor* processor) { processor->StartProcessing(); },
@@ -691,6 +712,7 @@ void UpdateAttempterAndroid::TerminateUpdateAndNotify(ErrorCode error_code) {
}
if (status_ == UpdateStatus::CLEANUP_PREVIOUS_UPDATE) {
+ ClearUpdateCompletedMarker();
LOG(INFO) << "Terminating cleanup previous update.";
SetStatusAndNotify(UpdateStatus::IDLE);
for (auto observer : daemon_state_->service_observers())
@@ -744,7 +766,6 @@ void UpdateAttempterAndroid::SetStatusAndNotify(UpdateStatus status) {
void UpdateAttempterAndroid::BuildUpdateActions(HttpFetcher* fetcher) {
CHECK(!processor_->IsRunning());
- processor_->set_delegate(this);
// Actions:
auto update_boot_flags_action =
@@ -758,7 +779,8 @@ void UpdateAttempterAndroid::BuildUpdateActions(HttpFetcher* fetcher) {
boot_control_,
hardware_,
fetcher, // passes ownership
- true /* interactive */);
+ true /* interactive */,
+ update_certificates_path_);
download_action->set_delegate(this);
download_action->set_base_offset(base_offset_);
auto filesystem_verifier_action = std::make_unique<FilesystemVerifierAction>(
@@ -784,9 +806,20 @@ void UpdateAttempterAndroid::BuildUpdateActions(HttpFetcher* fetcher) {
}
bool UpdateAttempterAndroid::WriteUpdateCompletedMarker() {
+ LOG(INFO) << "Writing update complete marker.";
string boot_id;
TEST_AND_RETURN_FALSE(utils::GetBootId(&boot_id));
- prefs_->SetString(kPrefsUpdateCompletedOnBootId, boot_id);
+ TEST_AND_RETURN_FALSE(
+ prefs_->SetString(kPrefsUpdateCompletedOnBootId, boot_id));
+ TEST_AND_RETURN_FALSE(
+ prefs_->SetInt64(kPrefsPreviousSlot, boot_control_->GetCurrentSlot()));
+ return true;
+}
+
+bool UpdateAttempterAndroid::ClearUpdateCompletedMarker() {
+ LOG(INFO) << "Clearing update complete marker.";
+ TEST_AND_RETURN_FALSE(prefs_->Delete(kPrefsUpdateCompletedOnBootId));
+ TEST_AND_RETURN_FALSE(prefs_->Delete(kPrefsPreviousSlot));
return true;
}
@@ -816,6 +849,12 @@ void UpdateAttempterAndroid::CollectAndReportUpdateMetricsOnUpdateFinished(
payload_type = kPayloadTypeDelta;
payload_size += p.size;
}
+ // In some cases, e.g. after calling |setShouldSwitchSlotOnReboot()|, this
+ // function will be triggered, but payload_size in this case might be 0, if so
+ // skip reporting any metrics.
+ if (payload_size == 0) {
+ return;
+ }
metrics::AttemptResult attempt_result =
metrics_utils::GetAttemptResult(error_code);
@@ -883,53 +922,105 @@ void UpdateAttempterAndroid::CollectAndReportUpdateMetricsOnUpdateFinished(
}
}
-void UpdateAttempterAndroid::UpdatePrefsAndReportUpdateMetricsOnReboot() {
- string current_boot_id;
- TEST_AND_RETURN(utils::GetBootId(&current_boot_id));
+bool UpdateAttempterAndroid::OTARebootSucceeded() const {
+ const auto current_slot = boot_control_->GetCurrentSlot();
+ const string current_version =
+ android::base::GetProperty("ro.build.version.incremental", "");
+ int64_t previous_slot = -1;
+ TEST_AND_RETURN_FALSE(prefs_->GetInt64(kPrefsPreviousSlot, &previous_slot));
+ string previous_version;
+ TEST_AND_RETURN_FALSE(
+ prefs_->GetString(kPrefsPreviousVersion, &previous_version));
+ if (previous_slot != current_slot) {
+ LOG(INFO) << "Detected a slot switch, OTA succeeded, device updated from "
+ << previous_version << " to " << current_version;
+ if (previous_version == current_version) {
+ LOG(INFO) << "Previous version is the same as current version, this is "
+ "possibly a self-OTA.";
+ }
+ return true;
+ } else {
+ LOG(INFO) << "Slot didn't switch, either the OTA is rolled back, or slot "
+ "switch never happened, or system not rebooted at all.";
+ if (previous_version != current_version) {
+ LOG(INFO) << "Slot didn't change, but version changed from "
+ << previous_version << " to " << current_version
+ << " device could be flashed.";
+ }
+ return false;
+ }
+}
+
+OTAResult UpdateAttempterAndroid::GetOTAUpdateResult() const {
+ // We only set |kPrefsSystemUpdatedMarker| if slot is actually switched, so
+ // existence of this pref is sufficient indicator. Given that we have to
+ // delete this pref after checking it. This is done in
+ // |DeltaPerformer::ResetUpdateProgress|
+ auto slot_switch_attempted = prefs_->Exists(kPrefsUpdateCompletedOnBootId);
+ auto system_rebooted = DidSystemReboot(prefs_);
+ auto ota_successful = OTARebootSucceeded();
+ if (ota_successful) {
+ return OTAResult::OTA_SUCCESSFUL;
+ }
+ if (slot_switch_attempted) {
+ if (system_rebooted) {
+ // If we attempted slot switch, but still end up on the same slot, we
+ // probably rolled back.
+ return OTAResult::ROLLED_BACK;
+ } else {
+ return OTAResult::UPDATED_NEED_REBOOT;
+ }
+ }
+ return OTAResult::NOT_ATTEMPTED;
+}
+
+void UpdateAttempterAndroid::UpdateStateAfterReboot(const OTAResult result) {
// Example: [ro.build.version.incremental]: [4292972]
string current_version =
android::base::GetProperty("ro.build.version.incremental", "");
TEST_AND_RETURN(!current_version.empty());
- const auto current_slot = boot_control_->GetCurrentSlot();
+
+ // |UpdateStateAfterReboot()| is only called after system reboot, so record
+ // boot id unconditionally
+ string current_boot_id;
+ TEST_AND_RETURN(utils::GetBootId(&current_boot_id));
+ prefs_->SetString(kPrefsBootId, current_boot_id);
// If there's no record of previous version (e.g. due to a data wipe), we
// save the info of current boot and skip the metrics report.
if (!prefs_->Exists(kPrefsPreviousVersion)) {
- prefs_->SetString(kPrefsBootId, current_boot_id);
prefs_->SetString(kPrefsPreviousVersion, current_version);
- prefs_->SetInt64(std::string{kPrefsPreviousSlot},
- boot_control_->GetCurrentSlot());
+ prefs_->SetInt64(kPrefsPreviousSlot, boot_control_->GetCurrentSlot());
ClearMetricsPrefs();
return;
}
- int64_t previous_slot = -1;
- prefs_->GetInt64(kPrefsPreviousSlot, &previous_slot);
- string previous_version;
// update_engine restarted under the same build and same slot.
- // TODO(xunchang) identify and report rollback by checking UpdateMarker.
- if (prefs_->GetString(kPrefsPreviousVersion, &previous_version) &&
- previous_version == current_version && previous_slot == current_slot) {
- string last_boot_id;
- bool is_reboot = prefs_->Exists(kPrefsBootId) &&
- (prefs_->GetString(kPrefsBootId, &last_boot_id) &&
- last_boot_id != current_boot_id);
+ if (result != OTAResult::OTA_SUCCESSFUL) {
// Increment the reboot number if |kPrefsNumReboots| exists. That pref is
// set when we start a new update.
- if (is_reboot && prefs_->Exists(kPrefsNumReboots)) {
- prefs_->SetString(kPrefsBootId, current_boot_id);
+ if (prefs_->Exists(kPrefsNumReboots)) {
int64_t reboot_count =
metrics_utils::GetPersistedValue(kPrefsNumReboots, prefs_);
metrics_utils::SetNumReboots(reboot_count + 1, prefs_);
}
+
+ if (result == OTAResult::ROLLED_BACK) {
+ // This will release all space previously allocated for apex
+ // decompression. If we detect a rollback, we should release space and
+ // return the space to user. Any subsequent attempt to install OTA will
+ // allocate space again anyway.
+ LOG(INFO) << "Detected a rollback, releasing space allocated for apex "
+ "deompression.";
+ apex_handler_android_->AllocateSpace({});
+ DeltaPerformer::ResetUpdateProgress(prefs_, false);
+ }
return;
}
// Now that the build version changes, report the update metrics.
// TODO(xunchang) check the build version is larger than the previous one.
- prefs_->SetString(kPrefsBootId, current_boot_id);
prefs_->SetString(kPrefsPreviousVersion, current_version);
- prefs_->SetInt64(std::string{kPrefsPreviousSlot},
- boot_control_->GetCurrentSlot());
+ prefs_->SetInt64(kPrefsPreviousSlot, boot_control_->GetCurrentSlot());
bool previous_attempt_exists = prefs_->Exists(kPrefsPayloadAttemptNumber);
// |kPrefsPayloadAttemptNumber| should be cleared upon successful update.
@@ -960,6 +1051,7 @@ void UpdateAttempterAndroid::UpdatePrefsOnUpdateStart(bool is_resume) {
}
metrics_utils::SetUpdateTimestampStart(clock_->GetMonotonicTime(), prefs_);
metrics_utils::SetUpdateBootTimestampStart(clock_->GetBootTime(), prefs_);
+ ClearUpdateCompletedMarker();
}
void UpdateAttempterAndroid::ClearMetricsPrefs() {
@@ -1059,6 +1151,100 @@ void UpdateAttempterAndroid::CleanupSuccessfulUpdate(
ScheduleCleanupPreviousUpdate();
}
+bool UpdateAttempterAndroid::setShouldSwitchSlotOnReboot(
+ const std::string& metadata_filename, brillo::ErrorPtr* error) {
+ LOG(INFO) << "setShouldSwitchSlotOnReboot(" << metadata_filename << ")";
+ if (processor_->IsRunning()) {
+ return LogAndSetError(
+ error, FROM_HERE, "Already processing an update, cancel it first.");
+ }
+ DeltaArchiveManifest manifest;
+ TEST_AND_RETURN_FALSE(
+ VerifyPayloadParseManifest(metadata_filename, &manifest, error));
+
+ if (!boot_control_->GetDynamicPartitionControl()->PreparePartitionsForUpdate(
+ GetCurrentSlot(),
+ GetTargetSlot(),
+ manifest,
+ false /* should update */,
+ nullptr)) {
+ return LogAndSetError(
+ error, FROM_HERE, "Failed to PreparePartitionsForUpdate");
+ }
+ InstallPlan install_plan_;
+ install_plan_.source_slot = GetCurrentSlot();
+ install_plan_.target_slot = GetTargetSlot();
+ // Don't do verity computation, just hash the partitions
+ install_plan_.write_verity = false;
+ // Don't run postinstall, we just need PostinstallAction to switch the slots.
+ install_plan_.run_post_install = false;
+ install_plan_.is_resume = true;
+
+ CHECK_NE(install_plan_.source_slot, UINT32_MAX);
+ CHECK_NE(install_plan_.target_slot, UINT32_MAX);
+
+ ErrorCode error_code;
+ if (!install_plan_.ParsePartitions(manifest.partitions(),
+ boot_control_,
+ manifest.block_size(),
+ &error_code)) {
+ return LogAndSetError(error,
+ FROM_HERE,
+ "Failed to LoadPartitionsFromSlots " +
+ utils::ErrorCodeToString(error_code));
+ }
+
+ auto install_plan_action = std::make_unique<InstallPlanAction>(install_plan_);
+ auto filesystem_verifier_action = std::make_unique<FilesystemVerifierAction>(
+ boot_control_->GetDynamicPartitionControl());
+ auto postinstall_runner_action =
+ std::make_unique<PostinstallRunnerAction>(boot_control_, hardware_);
+ SetStatusAndNotify(UpdateStatus::VERIFYING);
+ filesystem_verifier_action->set_delegate(this);
+ postinstall_runner_action->set_delegate(this);
+
+ // Bond them together. We have to use the leaf-types when calling
+ // BondActions().
+ BondActions(install_plan_action.get(), filesystem_verifier_action.get());
+ BondActions(filesystem_verifier_action.get(),
+ postinstall_runner_action.get());
+
+ processor_->EnqueueAction(std::move(install_plan_action));
+ processor_->EnqueueAction(std::move(filesystem_verifier_action));
+ processor_->EnqueueAction(std::move(postinstall_runner_action));
+ ScheduleProcessingStart();
+ return true;
+}
+
+bool UpdateAttempterAndroid::resetShouldSwitchSlotOnReboot(
+ brillo::ErrorPtr* error) {
+ if (processor_->IsRunning()) {
+ return LogAndSetError(
+ error, FROM_HERE, "Already processing an update, cancel it first.");
+ }
+ // Update the boot flags so the current slot has higher priority.
+ if (!boot_control_->SetActiveBootSlot(GetCurrentSlot())) {
+ return LogAndSetError(error, FROM_HERE, "Failed to SetActiveBootSlot");
+ }
+
+ // Mark the current slot as successful again, since marking it as active
+ // may reset the successful bit. We ignore the result of whether marking
+ // the current slot as successful worked.
+ if (!boot_control_->MarkBootSuccessfulAsync(Bind([](bool successful) {}))) {
+ return LogAndSetError(
+ error, FROM_HERE, "Failed to MarkBootSuccessfulAsync");
+ }
+
+ // Resets the warm reset property since we won't switch the slot.
+ hardware_->SetWarmReset(false);
+
+ // Resets the vbmeta digest.
+ hardware_->SetVbmetaDigestForInactiveSlot(true /* reset */);
+ LOG(INFO) << "Slot switch cancelled.";
+ SetStatusAndNotify(UpdateStatus::IDLE);
+ return true;
+}
+
void UpdateAttempterAndroid::ScheduleCleanupPreviousUpdate() {
// If a previous CleanupSuccessfulUpdate call has not finished, or an update
// is in progress, skip enqueueing the action.
diff --git a/aosp/update_attempter_android.h b/aosp/update_attempter_android.h
index 70938bcd..5d832e0a 100644
--- a/aosp/update_attempter_android.h
+++ b/aosp/update_attempter_android.h
@@ -45,6 +45,13 @@
namespace chromeos_update_engine {
+enum class OTAResult {
+ NOT_ATTEMPTED,
+ ROLLED_BACK,
+ UPDATED_NEED_REBOOT,
+ OTA_SUCCESSFUL,
+};
+
class UpdateAttempterAndroid
: public ServiceDelegateAndroidInterface,
public ActionProcessorDelegate,
@@ -89,6 +96,9 @@ class UpdateAttempterAndroid
void CleanupSuccessfulUpdate(
std::unique_ptr<CleanupSuccessfulUpdateCallbackInterface> callback,
brillo::ErrorPtr* error) override;
+ bool setShouldSwitchSlotOnReboot(const std::string& metadata_filename,
+ brillo::ErrorPtr* error) override;
+ bool resetShouldSwitchSlotOnReboot(brillo::ErrorPtr* error) override;
// ActionProcessorDelegate methods:
void ProcessingDone(const ActionProcessor* processor,
@@ -114,9 +124,29 @@ class UpdateAttempterAndroid
// CleanupPreviousUpdateActionDelegateInterface
void OnCleanupProgressUpdate(double progress) override;
+ // Check the result of an OTA update. Intended to be called after reboot, this
+ // will use prefs on disk to determine if OTA was installed, or rolledback.
+ [[nodiscard]] OTAResult GetOTAUpdateResult() const;
+ // Intended to be called:
+ // 1. When system rebooted and slot switch is attempted
+ // 2. When a new update is started
+ // 3. When user called |ResetStatus()|
+ bool ClearUpdateCompletedMarker();
+
+ void set_update_certificates_path(
+ const std::string& update_certificates_path) {
+ update_certificates_path_ = update_certificates_path;
+ }
+
private:
friend class UpdateAttempterAndroidTest;
+ // Return |true| only if slot switched successfully after an OTA reboot.
+ // This will return |false| if an downgrade OTA is applied. Because after a
+ // downgrade OTA, we wipe /data, and there's no way for update_engine to
+ // "remember" that a downgrade OTA took place.
+ [[nodiscard]] bool OTARebootSucceeded() const;
+
// Schedules an event loop callback to start the action processor. This is
// scheduled asynchronously to unblock the event loop.
void ScheduleProcessingStart();
@@ -136,10 +166,10 @@ class UpdateAttempterAndroid
// Writes to the processing completed marker. Does nothing if
// |update_completed_marker_| is empty.
- bool WriteUpdateCompletedMarker();
+ [[nodiscard]] bool WriteUpdateCompletedMarker();
// Returns whether an update was completed in the current boot.
- bool UpdateCompletedOnThisBoot();
+ [[nodiscard]] bool UpdateCompletedOnThisBoot();
// Prefs to use for metrics report
// |kPrefsPayloadAttemptNumber|: number of update attempts for the current
@@ -162,12 +192,16 @@ class UpdateAttempterAndroid
// |kPrefsSystemUpdatedMarker|
void CollectAndReportUpdateMetricsOnUpdateFinished(ErrorCode error_code);
+ // This function is called after update_engine is started after device
+ // reboots. If update_engine is restarted w/o device reboot, this function
+ // would not be called.
+
// Metrics report function to call:
// |ReportAbnormallyTerminatedUpdateAttemptMetrics|
// |ReportTimeToRebootMetrics|
// Prefs to update:
// |kPrefsBootId|, |kPrefsPreviousVersion|
- void UpdatePrefsAndReportUpdateMetricsOnReboot();
+ void UpdateStateAfterReboot(OTAResult result);
// Prefs to update:
// |kPrefsPayloadAttemptNumber|, |kPrefsUpdateTimestampStart|,
@@ -245,6 +279,9 @@ class UpdateAttempterAndroid
// CleanupPreviousUpdateAction has not been executed.
std::optional<ErrorCode> cleanup_previous_update_code_{std::nullopt};
+ // The path to the zip file with X509 certificates.
+ std::string update_certificates_path_{constants::kUpdateCertificatesPath};
+
DISALLOW_COPY_AND_ASSIGN(UpdateAttempterAndroid);
};
diff --git a/aosp/update_attempter_android_integration_test.cc b/aosp/update_attempter_android_integration_test.cc
new file mode 100644
index 00000000..909aa3cb
--- /dev/null
+++ b/aosp/update_attempter_android_integration_test.cc
@@ -0,0 +1,457 @@
+//
+// Copyright (C) 2021 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 <algorithm>
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <fcntl.h>
+#include <sys/sendfile.h>
+#include <unistd.h>
+
+#include <android-base/strings.h>
+#include <brillo/data_encoding.h>
+#include <brillo/message_loops/fake_message_loop.h>
+#include <bsdiff/bsdiff.h>
+#include <gtest/gtest.h>
+#include <liblp/builder.h>
+#include <fs_mgr.h>
+#include <liblp/liblp.h>
+
+#include "update_engine/aosp/boot_control_android.h"
+#include "update_engine/aosp/daemon_state_android.h"
+#include "update_engine/aosp/update_attempter_android.h"
+#include "update_engine/common/constants.h"
+#include "update_engine/common/fake_boot_control.h"
+#include "update_engine/common/fake_hardware.h"
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/common/prefs.h"
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/testing_constants.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/payload_file.h"
+#include "update_engine/payload_generator/payload_signer.h"
+#include "update_engine/update_metadata.pb.h"
+#include "update_engine/update_status_utils.h"
+
+namespace chromeos_update_engine {
+
+class UpdateAttempterAndroidIntegrationTest : public ::testing::Test,
+ public ServiceObserverInterface {
+ void AddFakePartitionGroup() {
+ dynamic_control_ = boot_control_.dynamic_control_.get();
+ auto super_device = dynamic_control_->GetSuperDevice();
+ ASSERT_TRUE(super_device.has_value());
+ super_device_ = super_device->value();
+ builder_ = android::fs_mgr::MetadataBuilder::New(
+ super_device->value(), boot_control_.GetCurrentSlot());
+ ASSERT_NE(builder_, nullptr);
+
+ // Remove dangling fake partitions, if test crashed before they might not
+ // get cleaned up properly.
+ RemoveFakePartitionGroup();
+ ASSERT_TRUE(builder_->AddGroup("fake_group", kFakePartitionSize * 2));
+ ExportPartitionTable();
+ }
+ void RemoveFakePartitionGroup() {
+ builder_->RemovePartition("fake_a");
+ builder_->RemovePartition("fake_b");
+ builder_->RemoveGroupAndPartitions("fake_group");
+ }
+
+ // Fill partition |path| with arbitrary data.
+ void FillPartition(const std::string& path, const bool is_source) {
+ std::array<uint8_t, kBlockSize> data;
+ EintrSafeFileDescriptor fd;
+ fd.Open(path.c_str(), O_RDWR);
+ for (size_t i = 0; i < kFakePartitionSize / kBlockSize; i++) {
+ if (is_source) {
+ std::fill(data.begin(), data.end(), i);
+ } else {
+ std::fill(
+ data.begin(), data.end(), kFakePartitionSize / kBlockSize - i - 1);
+ }
+ fd.Write(data.data(), kBlockSize);
+ }
+ }
+
+ void SetUp() override {
+ FillPartition(old_part_.path(), true);
+ FillPartition(new_part_.path(), false);
+ ASSERT_TRUE(boot_control_.Init());
+ if (!DynamicPartitionEnabled()) {
+ return;
+ }
+ ASSERT_NO_FATAL_FAILURE(AddFakePartitionGroup());
+ message_loop_.SetAsCurrent();
+ // Set official build to false so that hash checks are non-mandatory
+ hardware_.SetIsOfficialBuild(false);
+ truncate64(blob_file_.path().c_str(), 0);
+
+ update_attempter_android_.set_update_certificates_path(
+ test_utils::GetBuildArtifactsPath(kUnittestOTACertsPath));
+
+ // Basic setup to create VABC OTA
+ manifest_.set_partial_update(true);
+ manifest_.set_minor_version(kPartialUpdateMinorPayloadVersion);
+ auto dap_group =
+ manifest_.mutable_dynamic_partition_metadata()->add_groups();
+ dap_group->set_name("fake_group");
+ dap_group->add_partition_names("fake");
+
+ manifest_.mutable_dynamic_partition_metadata()->set_snapshot_enabled(true);
+ manifest_.mutable_dynamic_partition_metadata()->set_vabc_enabled(true);
+ manifest_.mutable_dynamic_partition_metadata()->set_cow_version(
+ android::snapshot::kCowVersionMajor);
+ }
+
+ void TearDown() override {
+ if (!builder_ || !DynamicPartitionEnabled()) {
+ return;
+ }
+ auto dynamic_control = boot_control_.GetDynamicPartitionControl();
+ if (dynamic_control) {
+ dynamic_control->UnmapAllPartitions();
+ dynamic_control->ResetUpdate(&prefs_);
+ }
+ RemoveFakePartitionGroup();
+ ExportPartitionTable();
+ }
+
+ void CreateFakePartition() {
+ // Create a fake partition for testing purposes
+ auto partition_a = builder_->AddPartition(
+ boot_control_.GetCurrentSlot() == 0 ? "fake_a" : "fake_b",
+ "fake_group",
+ 0);
+ ASSERT_NE(partition_a, nullptr);
+ ASSERT_TRUE(builder_->ResizePartition(partition_a, kFakePartitionSize));
+ ExportPartitionTable();
+ std::string source_part;
+ ASSERT_TRUE(
+ dynamic_control_->GetPartitionDevice("fake",
+ boot_control_.GetCurrentSlot(),
+ boot_control_.GetCurrentSlot(),
+ &source_part));
+ int out_fd = open(source_part.c_str(), O_RDWR);
+ ScopedFdCloser closer{&out_fd};
+ ASSERT_GE(out_fd, 0) << android::base::ErrnoNumberAsString(errno);
+ ASSERT_TRUE(utils::SendFile(out_fd, old_part_.fd(), kFakePartitionSize));
+ }
+
+ void SendStatusUpdate(
+ const update_engine::UpdateEngineStatus& update_engine_status) override {
+ LOG(INFO) << UpdateStatusToString(update_engine_status.status) << ", "
+ << update_engine_status.progress;
+ }
+
+ // Called whenever an update attempt is completed.
+ void SendPayloadApplicationComplete(ErrorCode error_code) override {
+ completion_code_ = error_code;
+ }
+
+ void ExportPartitionTable() {
+ auto metadata = builder_->Export();
+ ASSERT_NE(metadata, nullptr);
+ android::fs_mgr::UpdatePartitionTable(
+ super_device_, *metadata, boot_control_.GetCurrentSlot());
+ }
+
+ public:
+ bool DynamicPartitionEnabled() {
+ auto dynamic_control = boot_control_.GetDynamicPartitionControl();
+ return dynamic_control &&
+ dynamic_control->GetDynamicPartitionsFeatureFlag().IsEnabled();
+ }
+ void AddSignatureInfoToPayload(DeltaArchiveManifest* manifest,
+ const std::string& private_key_path) {
+ size_t total_blob_size = 0;
+ for (const auto& part : manifest->partitions()) {
+ for (const auto& op : part.operations()) {
+ if (!op.has_data_offset())
+ continue;
+ ASSERT_EQ(total_blob_size, op.data_offset())
+ << "Ops not ordered by blob isze";
+ total_blob_size += op.data_length();
+ }
+ }
+ // Signatures appear at the end of the blobs. Note the offset in the
+ // |manifest_|.
+ uint64_t signature_blob_length = 0;
+ if (!private_key_path.empty()) {
+ ASSERT_TRUE(PayloadSigner::SignatureBlobLength({private_key_path},
+ &signature_blob_length));
+ PayloadSigner::AddSignatureToManifest(
+ total_blob_size, signature_blob_length, manifest);
+ }
+ }
+
+ // Generate blob data according to ops specified in the manifest.
+ // Also update |new_part_|'s content to match expectation of ops.
+ void HydratePayload(DeltaArchiveManifest* manifest) {
+ for (auto& partition : *manifest->mutable_partitions()) {
+ for (auto& op : *partition.mutable_operations()) {
+ if (op.type() == InstallOperation::REPLACE) {
+ ASSERT_GE(lseek64(blob_file_.fd(), op.data_offset(), SEEK_SET), 0);
+ ASSERT_TRUE(utils::SendFile(
+ new_part_.fd(), blob_file_.fd(), op.data_length()));
+ } else if (op.type() == InstallOperation::BROTLI_BSDIFF) {
+ brillo::Blob old_data;
+ ASSERT_TRUE(utils::ReadExtents(
+ old_part_.path(), op.src_extents(), &old_data, kBlockSize))
+ << "Failed to read source data: "
+ << android::base::ErrnoNumberAsString(errno);
+ brillo::Blob new_data;
+ ASSERT_TRUE(utils::ReadExtents(
+ new_part_.path(), op.dst_extents(), &new_data, kBlockSize))
+ << "Failed to read target data: "
+ << android::base::ErrnoNumberAsString(errno);
+ ScopedTempFile patch_file{"bspatch.XXXXXX", true};
+ ASSERT_EQ(bsdiff::bsdiff(old_data.data(),
+ old_data.size(),
+ new_data.data(),
+ new_data.size(),
+ patch_file.path().c_str(),
+ nullptr),
+ 0);
+ op.set_data_length(utils::FileSize(patch_file.fd()));
+ const auto offset = lseek64(blob_file_.fd(), 0, SEEK_CUR);
+ ASSERT_GE(offset, 0);
+ op.set_data_offset(offset);
+ brillo::Blob src_data_hash;
+ HashCalculator::RawHashOfData(old_data, &src_data_hash);
+ op.set_src_sha256_hash(src_data_hash.data(), src_data_hash.size());
+ utils::SendFile(blob_file_.fd(), patch_file.fd(), op.data_length());
+
+ } else if (op.type() == InstallOperation::ZERO) {
+ auto zero = utils::GetReadonlyZeroString(
+ utils::BlocksInExtents(op.dst_extents()) * kBlockSize);
+ for (const auto& ext : op.dst_extents()) {
+ utils::PWriteAll(new_part_.fd(),
+ zero.data(),
+ ext.num_blocks() * kBlockSize,
+ ext.start_block() * kBlockSize);
+ }
+ } else if (op.type() == InstallOperation::SOURCE_COPY) {
+ brillo::Blob data;
+ ASSERT_TRUE(utils::ReadExtents(
+ old_part_.path(), op.src_extents(), &data, kBlockSize));
+ ASSERT_TRUE(utils::WriteExtents(
+ new_part_.path(), op.dst_extents(), data, kBlockSize));
+ } else {
+ FAIL() << "Unsupported install op type: " << op.type();
+ }
+ }
+ }
+ }
+
+ void ApplyPayload(DeltaArchiveManifest* manifest) {
+ ASSERT_FALSE(manifest->partitions().empty());
+ ASSERT_NO_FATAL_FAILURE(HydratePayload(manifest));
+ const auto private_key_path =
+ test_utils::GetBuildArtifactsPath(kUnittestPrivateKeyPath);
+ ASSERT_NO_FATAL_FAILURE(
+ AddSignatureInfoToPayload(manifest, private_key_path));
+
+ brillo::Blob hash;
+ HashCalculator::RawHashOfFile(new_part_.path(), &hash);
+ auto partition = &manifest->mutable_partitions()->at(0);
+ partition->mutable_new_partition_info()->set_size(kFakePartitionSize);
+ partition->mutable_new_partition_info()->set_hash(hash.data(), hash.size());
+ const bool source_exist =
+ std::any_of(partition->operations().begin(),
+ partition->operations().end(),
+ [](const auto& op) { return op.src_extents_size() > 0; });
+ if (source_exist) {
+ HashCalculator::RawHashOfFile(old_part_.path(), &hash);
+ partition->mutable_old_partition_info()->set_size(kFakePartitionSize);
+ partition->mutable_old_partition_info()->set_hash(hash.data(),
+ hash.size());
+ // Only create fake partition if the update is incremental
+ LOG(INFO) << "Creating fake partition";
+ ASSERT_NO_FATAL_FAILURE(CreateFakePartition());
+ }
+ uint64_t metadata_size = 0;
+ ASSERT_TRUE(PayloadFile::WritePayload(payload_file_.path(),
+ blob_file_.path(),
+ private_key_path,
+ kBrilloMajorPayloadVersion,
+ *manifest,
+ &metadata_size));
+ LOG(INFO) << "Signature offset: " << manifest->signatures_offset()
+ << ", Signature size: " << manifest->signatures_size();
+ brillo::ErrorPtr error;
+ HashCalculator::RawHashOfFile(payload_file_.path(), &hash);
+ daemon_state_.AddObserver(this);
+ ASSERT_TRUE(update_attempter_android_.ApplyPayload(
+ "file://" + payload_file_.path(),
+ 0,
+ utils::FileSize(payload_file_.path()),
+ {kPayloadPropertyMetadataSize + ("=" + std::to_string(metadata_size)),
+ kPayloadPropertyFileHash +
+ ("=" + brillo::data_encoding::Base64Encode(hash))},
+ &error));
+ brillo::MessageLoop::current()->Run();
+ if (error) {
+ LOG(ERROR) << error->GetMessage();
+ }
+ ASSERT_EQ(error, nullptr);
+ ASSERT_EQ(completion_code_, ErrorCode::kSuccess);
+ }
+
+ // Compare contents of fake_b partition to |new_part_| and print difference
+ void DumpTargetPartitionDiff() {
+ dynamic_control_->MapAllPartitions();
+ auto partition_device =
+ dynamic_control_->GetPartitionDevice("fake",
+ 1 - boot_control_.GetCurrentSlot(),
+ boot_control_.GetCurrentSlot(),
+ false);
+ if (!partition_device.has_value()) {
+ LOG(INFO) << "Failed to get target fake partition, skip diff report";
+ return;
+ }
+
+ EintrSafeFileDescriptor actual_part;
+ CHECK(actual_part.Open(partition_device->readonly_device_path.c_str(),
+ O_RDONLY));
+ EintrSafeFileDescriptor expected_part;
+ CHECK(expected_part.Open(new_part_.path().c_str(), O_RDONLY));
+
+ std::array<uint8_t, kBlockSize> actual_block;
+ std::array<uint8_t, kBlockSize> expected_block;
+ for (size_t i = 0; i < kFakePartitionSize / kBlockSize; i++) {
+ actual_part.Read(actual_block.data(), actual_block.size());
+ expected_part.Read(expected_block.data(), expected_block.size());
+ if (actual_block != expected_block) {
+ LOG(ERROR) << "Block " << i << " differs.";
+ }
+ }
+ }
+ // use 25MB max to avoid super not having enough space
+ static constexpr size_t kFakePartitionSize = 1024 * 1024 * 25;
+ static_assert(kFakePartitionSize % kBlockSize == 0);
+ BootControlAndroid boot_control_;
+
+ std::unique_ptr<android::fs_mgr::MetadataBuilder> builder_;
+ std::string super_device_;
+ FakeHardware hardware_;
+ ScopedTempFile payload_file_;
+ ScopedTempFile blob_file_{"blob_file.XXXXXX", true};
+ // Contains expected data for old partition. Will be copied to fake_a on test
+ // start.
+ ScopedTempFile old_part_{"old_part.XXXXXX", true, kFakePartitionSize};
+ // Expected data for new partition, will be compared against actual data in
+ // fake_b once test finishes.
+ ScopedTempFile new_part_{"new_part.XXXXXX", true, kFakePartitionSize};
+ DaemonStateAndroid daemon_state_;
+ MemoryPrefs prefs_;
+ ErrorCode completion_code_;
+ DynamicPartitionControlAndroid* dynamic_control_{nullptr};
+ brillo::FakeMessageLoop message_loop_{nullptr};
+
+ DeltaArchiveManifest manifest_;
+ UpdateAttempterAndroid update_attempter_android_{
+ &daemon_state_, &prefs_, &boot_control_, &hardware_, nullptr};
+};
+
+namespace {
+
+TEST_F(UpdateAttempterAndroidIntegrationTest, NewPartitionTest) {
+ if (!DynamicPartitionEnabled()) {
+ return;
+ }
+ auto partition = manifest_.add_partitions();
+ partition->set_partition_name("fake");
+ partition->set_estimate_cow_size(kFakePartitionSize);
+ {
+ auto op = partition->add_operations();
+ op->set_type(InstallOperation::REPLACE);
+ *op->add_dst_extents() = ExtentForRange(0, 1);
+ op->set_data_offset(0);
+ op->set_data_length(kBlockSize);
+ truncate(blob_file_.path().c_str(), kBlockSize);
+ }
+ {
+ auto op = partition->add_operations();
+ op->set_type(InstallOperation::ZERO);
+ *op->add_dst_extents() =
+ ExtentForRange(1, kFakePartitionSize / kBlockSize - 1);
+ }
+
+ ApplyPayload(&manifest_);
+ if (completion_code_ == ErrorCode::kNewRootfsVerificationError) {
+ DumpTargetPartitionDiff();
+ }
+}
+
+TEST_F(UpdateAttempterAndroidIntegrationTest, XorOpsTest) {
+ if (!DynamicPartitionEnabled()) {
+ return;
+ }
+ auto partition = manifest_.add_partitions();
+ partition->set_partition_name("fake");
+ partition->set_estimate_cow_size(kFakePartitionSize);
+ {
+ auto op = partition->add_operations();
+ op->set_type(InstallOperation::BROTLI_BSDIFF);
+ *op->add_src_extents() = ExtentForRange(0, 10);
+ *op->add_dst_extents() = ExtentForRange(0, 10);
+ }
+ {
+ auto op = partition->add_operations();
+ op->set_type(InstallOperation::BROTLI_BSDIFF);
+ *op->add_src_extents() = ExtentForRange(10, 10);
+ *op->add_dst_extents() = ExtentForRange(10, 10);
+ }
+ {
+ auto op = partition->add_operations();
+ op->set_type(InstallOperation::SOURCE_COPY);
+ *op->add_src_extents() =
+ ExtentForRange(20, kFakePartitionSize / kBlockSize - 20);
+ *op->add_dst_extents() =
+ ExtentForRange(20, kFakePartitionSize / kBlockSize - 20);
+ }
+ {
+ auto op = partition->add_merge_operations();
+ op->set_type(CowMergeOperation::COW_XOR);
+ op->set_src_offset(123);
+ *op->mutable_src_extent() = ExtentForRange(2, 8);
+ *op->mutable_dst_extent() = ExtentForRange(0, 8);
+ }
+ {
+ auto op = partition->add_merge_operations();
+ op->set_type(CowMergeOperation::COW_XOR);
+ op->set_src_offset(456);
+ *op->mutable_src_extent() = ExtentForRange(10, 8);
+ *op->mutable_dst_extent() = ExtentForRange(12, 8);
+ }
+
+ ApplyPayload(&manifest_);
+ if (completion_code_ == ErrorCode::kNewRootfsVerificationError) {
+ DumpTargetPartitionDiff();
+ }
+}
+
+} // namespace
+
+} // namespace chromeos_update_engine
diff --git a/aosp/update_attempter_android_unittest.cc b/aosp/update_attempter_android_unittest.cc
index f73df168..458c2240 100644
--- a/aosp/update_attempter_android_unittest.cc
+++ b/aosp/update_attempter_android_unittest.cc
@@ -20,20 +20,41 @@
#include <string>
#include <utility>
+#include <fcntl.h>
+#include <sys/sendfile.h>
+#include <unistd.h>
+
#include <android-base/properties.h>
#include <base/time/time.h>
+#include <brillo/data_encoding.h>
+#include <brillo/message_loops/fake_message_loop.h>
#include <gtest/gtest.h>
+#include <liblp/builder.h>
+#include <fs_mgr.h>
+#include <liblp/liblp.h>
-#include "common/constants.h"
+#include "update_engine/aosp/boot_control_android.h"
#include "update_engine/aosp/daemon_state_android.h"
+#include "update_engine/common/constants.h"
#include "update_engine/common/fake_boot_control.h"
#include "update_engine/common/fake_clock.h"
#include "update_engine/common/fake_hardware.h"
#include "update_engine/common/fake_prefs.h"
+#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/mock_action_processor.h"
#include "update_engine/common/mock_metrics_reporter.h"
+#include "update_engine/common/prefs.h"
#include "update_engine/common/test_utils.h"
+#include "update_engine/common/testing_constants.h"
#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/payload_file.h"
+#include "update_engine/payload_generator/payload_signer.h"
+#include "update_engine/update_metadata.pb.h"
+#include "update_engine/update_status_utils.h"
using base::Time;
using base::TimeDelta;
@@ -42,6 +63,11 @@ using update_engine::UpdateStatus;
namespace chromeos_update_engine {
+// Compare the value of builtin array for download source parameter.
+MATCHER_P(DownloadSourceMatcher, source_array, "") {
+ return std::equal(source_array, source_array + kNumDownloadSources, arg);
+}
+
class UpdateAttempterAndroidTest : public ::testing::Test {
protected:
UpdateAttempterAndroidTest() = default;
@@ -76,6 +102,8 @@ class UpdateAttempterAndroidTest : public ::testing::Test {
testing::NiceMock<MockMetricsReporter>* metrics_reporter_;
};
+namespace {
+
TEST_F(UpdateAttempterAndroidTest, UpdatePrefsSameBuildVersionOnInit) {
std::string build_version =
android::base::GetProperty("ro.build.version.incremental", "");
@@ -106,6 +134,7 @@ TEST_F(UpdateAttempterAndroidTest, UpdatePrefsBuildVersionChangeOnInit) {
prefs_.SetString(kPrefsPreviousVersion, "00001"); // Set the fake version
prefs_.SetInt64(kPrefsPayloadAttemptNumber, 1);
prefs_.SetInt64(kPrefsSystemUpdatedMarker, 23456);
+ prefs_.SetInt64(kPrefsPreviousSlot, 1);
EXPECT_CALL(*metrics_reporter_,
ReportAbnormallyTerminatedUpdateAttemptMetrics())
@@ -186,18 +215,10 @@ TEST_F(UpdateAttempterAndroidTest, ReportMetricsForBytesDownloaded) {
int64_t total_bytes[kNumDownloadSources] = {};
total_bytes[kDownloadSourceHttpsServer] = 90;
- EXPECT_CALL(*metrics_reporter_,
- ReportSuccessfulUpdateMetrics(
- _,
- _,
- _,
- 50,
- test_utils::DownloadSourceMatcher(total_bytes),
- 80,
- _,
- _,
- _,
- _))
+ EXPECT_CALL(
+ *metrics_reporter_,
+ ReportSuccessfulUpdateMetrics(
+ _, _, _, 50, DownloadSourceMatcher(total_bytes), 80, _, _, _, _))
.Times(1);
// Adds a payload of 50 bytes to the InstallPlan.
@@ -227,4 +248,6 @@ TEST_F(UpdateAttempterAndroidTest, ReportMetricsForBytesDownloaded) {
0, metrics_utils::GetPersistedValue(kPrefsTotalBytesDownloaded, &prefs_));
}
+} // namespace
+
} // namespace chromeos_update_engine
diff --git a/aosp/update_engine_client_android.cc b/aosp/update_engine_client_android.cc
index 1a68cf49..c00e9f58 100644
--- a/aosp/update_engine_client_android.cc
+++ b/aosp/update_engine_client_android.cc
@@ -41,6 +41,7 @@
#include "update_engine/common/error_code.h"
#include "update_engine/common/error_code_utils.h"
#include "update_engine/update_status_utils.h"
+#include "utils/String8.h"
using android::binder::Status;
@@ -71,6 +72,8 @@ class UpdateEngineClientAndroid : public brillo::Daemon {
// Called whenever the UpdateEngine daemon dies.
void UpdateEngineServiceDied();
+ // Register callback to watch for death notification from update_engine.
+ void RegisterDeathNotification();
static std::vector<android::String16> ParseHeaders(const std::string& arg);
@@ -106,6 +109,18 @@ Status UpdateEngineClientAndroid::UECallback::onPayloadApplicationComplete(
return Status::ok();
}
+constexpr auto&& UNSPECIFIED_FLAG = "unspecified";
+
+void UpdateEngineClientAndroid::RegisterDeathNotification() {
+ // When following updates status changes, exit if the update_engine daemon
+ // dies.
+ android::BinderWrapper::Create();
+ android::BinderWrapper::Get()->RegisterForDeathNotifications(
+ android::os::IUpdateEngine::asBinder(service_),
+ base::Bind(&UpdateEngineClientAndroid::UpdateEngineServiceDied,
+ base::Unretained(this)));
+}
+
int UpdateEngineClientAndroid::OnInit() {
int ret = Daemon::OnInit();
if (ret != EX_OK)
@@ -137,6 +152,11 @@ int UpdateEngineClientAndroid::OnInit() {
"The path to the update payload metadata. "
"Used when --verify or --allocate is passed.");
+ DEFINE_string(switch_slot,
+ UNSPECIFIED_FLAG,
+ "Perform just the slow switching part of OTA. "
+ "Used to revert a slot switch or re-do slot switch. Valid "
+ "values are 'true' and 'false'");
DEFINE_bool(suspend, false, "Suspend an ongoing update and exit.");
DEFINE_bool(resume, false, "Resume a suspended update.");
DEFINE_bool(cancel, false, "Cancel the ongoing update and exit.");
@@ -182,6 +202,19 @@ int UpdateEngineClientAndroid::OnInit() {
return ExitWhenIdle(1);
}
+ // Other commands, such as |setShouldSwitchSlotOnReboot|, might rely on the
+ // follow behavior, so created callback before running these commands.
+ if (FLAGS_follow) {
+ // Register a callback object with the service.
+ callback_ = new UECallback(this);
+ bool bound;
+ if (!service_->bind(callback_, &bound).isOk() || !bound) {
+ LOG(ERROR) << "Failed to bind() the UpdateEngine daemon.";
+ return 1;
+ }
+ keep_running = true;
+ }
+
if (FLAGS_suspend) {
return ExitWhenIdle(service_->suspend());
}
@@ -198,6 +231,28 @@ int UpdateEngineClientAndroid::OnInit() {
return ExitWhenIdle(service_->resetStatus());
}
+ if (FLAGS_switch_slot != UNSPECIFIED_FLAG) {
+ if (FLAGS_switch_slot != "true" && FLAGS_switch_slot != "false") {
+ LOG(ERROR) << "--switch_slot should be either true or false, got "
+ << FLAGS_switch_slot;
+ return 1;
+ }
+ const bool should_switch = FLAGS_switch_slot == "true";
+ ::android::binder::Status status;
+ if (should_switch) {
+ status = service_->setShouldSwitchSlotOnReboot(
+ android::String16(FLAGS_metadata.c_str(), FLAGS_metadata.size()));
+ if (!FLAGS_follow) {
+ return ExitWhenIdle(status);
+ }
+ } else {
+ // resetShouldSwitchSlotOnReboot() is a synchronous call, no need to
+ // follow
+ status = service_->resetShouldSwitchSlotOnReboot();
+ return ExitWhenIdle(status);
+ }
+ }
+
if (FLAGS_verify) {
bool applicable = false;
Status status = service_->verifyPayloadApplicable(
@@ -237,17 +292,6 @@ int UpdateEngineClientAndroid::OnInit() {
keep_running = true;
}
- if (FLAGS_follow) {
- // Register a callback object with the service.
- callback_ = new UECallback(this);
- bool bound;
- if (!service_->bind(callback_, &bound).isOk() || !bound) {
- LOG(ERROR) << "Failed to bind() the UpdateEngine daemon.";
- return 1;
- }
- keep_running = true;
- }
-
if (FLAGS_update) {
auto and_headers = ParseHeaders(FLAGS_headers);
Status status = service_->applyPayload(
@@ -262,14 +306,7 @@ int UpdateEngineClientAndroid::OnInit() {
if (!keep_running)
return ExitWhenIdle(EX_OK);
- // When following updates status changes, exit if the update_engine daemon
- // dies.
- android::BinderWrapper::Create();
- android::BinderWrapper::Get()->RegisterForDeathNotifications(
- android::os::IUpdateEngine::asBinder(service_),
- base::Bind(&UpdateEngineClientAndroid::UpdateEngineServiceDied,
- base::Unretained(this)));
-
+ RegisterDeathNotification();
return EX_OK;
}
diff --git a/binder_bindings/android/os/IUpdateEngine.aidl b/binder_bindings/android/os/IUpdateEngine.aidl
index c9580da4..4043b1a5 100644
--- a/binder_bindings/android/os/IUpdateEngine.aidl
+++ b/binder_bindings/android/os/IUpdateEngine.aidl
@@ -44,6 +44,11 @@ interface IUpdateEngine {
/** @hide */
void resetStatus();
/** @hide */
+ void setShouldSwitchSlotOnReboot(in String metadataFilename);
+ /** @hide */
+ void resetShouldSwitchSlotOnReboot();
+
+ /** @hide */
boolean verifyPayloadApplicable(in String metadataFilename);
/**
* Allocate space on userdata partition.
diff --git a/client_library/client_dbus.cc b/client_library/client_dbus.cc
deleted file mode 100644
index 30ad78c6..00000000
--- a/client_library/client_dbus.cc
+++ /dev/null
@@ -1,255 +0,0 @@
-//
-// Copyright (C) 2015 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/client_library/client_dbus.h"
-
-#include <base/message_loop/message_loop_current.h>
-
-#include <memory>
-
-#include <dbus/bus.h>
-#include <update_engine/dbus-constants.h>
-
-#include "update_engine/update_status_utils.h"
-
-using dbus::Bus;
-using org::chromium::UpdateEngineInterfaceProxy;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-
-namespace update_engine {
-
-unique_ptr<UpdateEngineClient> UpdateEngineClient::CreateInstance() {
- auto ret = std::make_unique<internal::DBusUpdateEngineClient>();
- if (!ret->Init()) {
- ret.reset();
- }
- return ret;
-}
-
-namespace internal {
-
-namespace {
-// This converts the status from Protobuf |StatusResult| to The internal
-// |UpdateEngineStatus| struct.
-void ConvertToUpdateEngineStatus(const StatusResult& status,
- UpdateEngineStatus* out_status) {
- out_status->last_checked_time = status.last_checked_time();
- out_status->progress = status.progress();
- out_status->new_version = status.new_version();
- out_status->new_size_bytes = status.new_size();
- out_status->status = static_cast<UpdateStatus>(status.current_operation());
- out_status->is_enterprise_rollback = status.is_enterprise_rollback();
- out_status->is_install = status.is_install();
- out_status->eol_date = status.eol_date();
- out_status->will_powerwash_after_reboot =
- status.will_powerwash_after_reboot();
-}
-} // namespace
-
-bool DBusUpdateEngineClient::Init() {
- Bus::Options options;
- options.bus_type = Bus::SYSTEM;
- scoped_refptr<Bus> bus{new Bus{options}};
-
- if (!bus->Connect())
- return false;
-
- proxy_.reset(new UpdateEngineInterfaceProxy{bus});
- return true;
-}
-
-bool DBusUpdateEngineClient::AttemptUpdate(const string& in_app_version,
- const string& in_omaha_url,
- bool at_user_request) {
- return proxy_->AttemptUpdateWithFlags(
- in_app_version,
- in_omaha_url,
- (at_user_request)
- ? 0
- : update_engine::UpdateAttemptFlags::kFlagNonInteractive,
- nullptr);
-}
-
-bool DBusUpdateEngineClient::AttemptInstall(const string& omaha_url,
- const vector<string>& dlc_ids) {
- return proxy_->AttemptInstall(omaha_url, dlc_ids, nullptr);
-}
-
-bool DBusUpdateEngineClient::SetDlcActiveValue(bool is_active,
- const std::string& dlc_id) {
- return proxy_->SetDlcActiveValue(is_active, dlc_id, /*error=*/nullptr);
-}
-
-bool DBusUpdateEngineClient::GetStatus(UpdateEngineStatus* out_status) const {
- StatusResult status;
- if (!proxy_->GetStatusAdvanced(&status, nullptr)) {
- return false;
- }
-
- ConvertToUpdateEngineStatus(status, out_status);
- return true;
-}
-
-bool DBusUpdateEngineClient::SetCohortHint(const string& cohort_hint) {
- return proxy_->SetCohortHint(cohort_hint, nullptr);
-}
-
-bool DBusUpdateEngineClient::GetCohortHint(string* cohort_hint) const {
- return proxy_->GetCohortHint(cohort_hint, nullptr);
-}
-
-bool DBusUpdateEngineClient::SetUpdateOverCellularPermission(bool allowed) {
- return proxy_->SetUpdateOverCellularPermission(allowed, nullptr);
-}
-
-bool DBusUpdateEngineClient::GetUpdateOverCellularPermission(
- bool* allowed) const {
- return proxy_->GetUpdateOverCellularPermission(allowed, nullptr);
-}
-
-bool DBusUpdateEngineClient::SetP2PUpdatePermission(bool enabled) {
- return proxy_->SetP2PUpdatePermission(enabled, nullptr);
-}
-
-bool DBusUpdateEngineClient::GetP2PUpdatePermission(bool* enabled) const {
- return proxy_->GetP2PUpdatePermission(enabled, nullptr);
-}
-
-bool DBusUpdateEngineClient::Rollback(bool powerwash) {
- return proxy_->AttemptRollback(powerwash, nullptr);
-}
-
-bool DBusUpdateEngineClient::GetRollbackPartition(
- string* rollback_partition) const {
- return proxy_->GetRollbackPartition(rollback_partition, nullptr);
-}
-
-bool DBusUpdateEngineClient::GetPrevVersion(string* prev_version) const {
- return proxy_->GetPrevVersion(prev_version, nullptr);
-}
-
-void DBusUpdateEngineClient::RebootIfNeeded() {
- bool ret = proxy_->RebootIfNeeded(nullptr);
- if (!ret) {
- // Reboot error code doesn't necessarily mean that a reboot
- // failed. For example, D-Bus may be shutdown before we receive the
- // result.
- LOG(INFO) << "RebootIfNeeded() failure ignored.";
- }
-}
-
-bool DBusUpdateEngineClient::ResetStatus() {
- return proxy_->ResetStatus(nullptr);
-}
-
-void DBusUpdateEngineClient::DBusStatusHandlersRegistered(
- const string& interface, const string& signal_name, bool success) const {
- if (!success) {
- for (auto handler : handlers_) {
- handler->IPCError("Could not connect to" + signal_name + " on " +
- interface);
- }
- } else {
- StatusUpdateHandlersRegistered(nullptr);
- }
-}
-
-void DBusUpdateEngineClient::StatusUpdateHandlersRegistered(
- StatusUpdateHandler* handler) const {
- UpdateEngineStatus status;
- if (!GetStatus(&status)) {
- handler->IPCError("Could not query current status");
- return;
- }
-
- std::vector<update_engine::StatusUpdateHandler*> just_handler = {handler};
- for (auto h : handler ? just_handler : handlers_) {
- h->HandleStatusUpdate(status);
- }
-}
-
-void DBusUpdateEngineClient::RunStatusUpdateHandlers(
- const StatusResult& status) {
- UpdateEngineStatus ue_status;
- ConvertToUpdateEngineStatus(status, &ue_status);
-
- for (auto handler : handlers_) {
- handler->HandleStatusUpdate(ue_status);
- }
-}
-
-bool DBusUpdateEngineClient::UnregisterStatusUpdateHandler(
- StatusUpdateHandler* handler) {
- auto it = std::find(handlers_.begin(), handlers_.end(), handler);
- if (it != handlers_.end()) {
- handlers_.erase(it);
- return true;
- }
-
- return false;
-}
-
-bool DBusUpdateEngineClient::RegisterStatusUpdateHandler(
- StatusUpdateHandler* handler) {
- if (!base::MessageLoopCurrent::IsSet()) {
- LOG(FATAL) << "Cannot get UpdateEngineClient outside of message loop.";
- return false;
- }
-
- handlers_.push_back(handler);
-
- if (dbus_handler_registered_) {
- StatusUpdateHandlersRegistered(handler);
- return true;
- }
-
- proxy_->RegisterStatusUpdateAdvancedSignalHandler(
- base::Bind(&DBusUpdateEngineClient::RunStatusUpdateHandlers,
- base::Unretained(this)),
- base::Bind(&DBusUpdateEngineClient::DBusStatusHandlersRegistered,
- base::Unretained(this)));
-
- dbus_handler_registered_ = true;
-
- return true;
-}
-
-bool DBusUpdateEngineClient::SetTargetChannel(const string& in_target_channel,
- bool allow_powerwash) {
- return proxy_->SetChannel(in_target_channel, allow_powerwash, nullptr);
-}
-
-bool DBusUpdateEngineClient::GetTargetChannel(string* out_channel) const {
- return proxy_->GetChannel(false, // Get the target channel.
- out_channel,
- nullptr);
-}
-
-bool DBusUpdateEngineClient::GetChannel(string* out_channel) const {
- return proxy_->GetChannel(true, // Get the current channel.
- out_channel,
- nullptr);
-}
-
-bool DBusUpdateEngineClient::GetLastAttemptError(
- int32_t* last_attempt_error) const {
- return proxy_->GetLastAttemptError(last_attempt_error, nullptr);
-}
-
-} // namespace internal
-} // namespace update_engine
diff --git a/client_library/client_dbus.h b/client_library/client_dbus.h
deleted file mode 100644
index f19555fc..00000000
--- a/client_library/client_dbus.h
+++ /dev/null
@@ -1,105 +0,0 @@
-//
-// Copyright (C) 2015 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_CLIENT_LIBRARY_CLIENT_DBUS_H_
-#define UPDATE_ENGINE_CLIENT_LIBRARY_CLIENT_DBUS_H_
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-#include <update_engine/proto_bindings/update_engine.pb.h>
-
-#include "update_engine/client_library/include/update_engine/client.h"
-#include "update_engine/dbus-proxies.h"
-
-namespace update_engine {
-namespace internal {
-
-class DBusUpdateEngineClient : public UpdateEngineClient {
- public:
- DBusUpdateEngineClient() = default;
- bool Init();
-
- virtual ~DBusUpdateEngineClient() = default;
-
- bool AttemptUpdate(const std::string& app_version,
- const std::string& omaha_url,
- bool at_user_request) override;
-
- bool AttemptInstall(const std::string& omaha_url,
- const std::vector<std::string>& dlc_ids) override;
-
- bool SetDlcActiveValue(bool is_active, const std::string& dlc_id) override;
-
- bool GetStatus(UpdateEngineStatus* out_status) const override;
-
- bool SetCohortHint(const std::string& cohort_hint) override;
- bool GetCohortHint(std::string* cohort_hint) const override;
-
- bool SetUpdateOverCellularPermission(bool allowed) override;
- bool GetUpdateOverCellularPermission(bool* allowed) const override;
-
- bool SetP2PUpdatePermission(bool enabled) override;
- bool GetP2PUpdatePermission(bool* enabled) const override;
-
- bool Rollback(bool powerwash) override;
-
- bool GetRollbackPartition(std::string* rollback_partition) const override;
-
- void RebootIfNeeded() override;
-
- bool GetPrevVersion(std::string* prev_version) const override;
-
- bool ResetStatus() override;
-
- bool SetTargetChannel(const std::string& target_channel,
- bool allow_powerwash) override;
-
- bool GetTargetChannel(std::string* out_channel) const override;
-
- bool GetChannel(std::string* out_channel) const override;
-
- bool RegisterStatusUpdateHandler(StatusUpdateHandler* handler) override;
- bool UnregisterStatusUpdateHandler(StatusUpdateHandler* handler) override;
-
- bool GetLastAttemptError(int32_t* last_attempt_error) const override;
-
- private:
- void DBusStatusHandlersRegistered(const std::string& interface,
- const std::string& signal_name,
- bool success) const;
-
- // Send an initial event to new StatusUpdateHandlers. If the handler argument
- // is not nullptr, only that handler receives the event. Otherwise all
- // registered handlers receive the event.
- void StatusUpdateHandlersRegistered(StatusUpdateHandler* handler) const;
-
- void RunStatusUpdateHandlers(const StatusResult& status);
-
- std::unique_ptr<org::chromium::UpdateEngineInterfaceProxy> proxy_;
- std::vector<update_engine::StatusUpdateHandler*> handlers_;
- bool dbus_handler_registered_{false};
-
- DISALLOW_COPY_AND_ASSIGN(DBusUpdateEngineClient);
-}; // class DBusUpdateEngineClient
-
-} // namespace internal
-} // namespace update_engine
-
-#endif // UPDATE_ENGINE_CLIENT_LIBRARY_CLIENT_DBUS_H_
diff --git a/common/action.h b/common/action.h
index fd82c2d5..d32322c3 100644
--- a/common/action.h
+++ b/common/action.h
@@ -98,7 +98,7 @@ class AbstractAction {
virtual void PerformAction() = 0;
// Called on ActionProcess::ActionComplete() by ActionProcessor.
- virtual void ActionCompleted(ErrorCode code) {}
+ virtual void ActionCompleted([[maybe_unused]] ErrorCode code) {}
// Called by the ActionProcessor to tell this Action which processor
// it belongs to.
diff --git a/common/action_processor.h b/common/action_processor.h
index ad98cc9c..6108c3ef 100644
--- a/common/action_processor.h
+++ b/common/action_processor.h
@@ -130,18 +130,19 @@ class ActionProcessorDelegate {
// Called when all processing in an ActionProcessor has completed. A pointer
// to the ActionProcessor is passed. |code| is set to the exit code of the
// last completed action.
- virtual void ProcessingDone(const ActionProcessor* processor,
- ErrorCode code) {}
+ virtual void ProcessingDone([[maybe_unused]] const ActionProcessor* processor,
+ [[maybe_unused]] ErrorCode code) {}
// Called when processing has stopped. Does not mean that all Actions have
// completed. If/when all Actions complete, ProcessingDone() will be called.
- virtual void ProcessingStopped(const ActionProcessor* processor) {}
+ virtual void ProcessingStopped(
+ [[maybe_unused]] const ActionProcessor* processor) {}
// Called whenever an action has finished processing, either successfully
// or otherwise.
- virtual void ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) {}
+ virtual void ActionCompleted([[maybe_unused]] ActionProcessor* processor,
+ [[maybe_unused]] AbstractAction* action,
+ [[maybe_unused]] ErrorCode code) {}
};
} // namespace chromeos_update_engine
diff --git a/common/boot_control_interface.h b/common/boot_control_interface.h
index 321174eb..2de21a16 100644
--- a/common/boot_control_interface.h
+++ b/common/boot_control_interface.h
@@ -93,6 +93,11 @@ class BootControlInterface {
// bootloader will attempt to load the |slot| marked as active. Note that this
// method doesn't change the value of GetCurrentSlot() on the current boot.
virtual bool SetActiveBootSlot(Slot slot) = 0;
+ // Get the active slot. In other words, the slot which will be used on
+ // next system reboot. This should match the |slot| parameter of last
+ // successful call to |SetActiveBootSlot|.
+ // Return 0xFFFFFFFF if underlying HAL doesn't support this operation.
+ virtual Slot GetActiveBootSlot() = 0;
// Mark the current slot as successfully booted asynchronously. No other slot
// flags are modified. Returns false if it was not able to schedule the
diff --git a/common/boot_control_stub.h b/common/boot_control_stub.h
index dcddbaea..31671154 100644
--- a/common/boot_control_stub.h
+++ b/common/boot_control_stub.h
@@ -56,6 +56,7 @@ class BootControlStub : public BootControlInterface {
bool IsSlotBootable(BootControlInterface::Slot slot) const override;
bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
+ Slot GetActiveBootSlot() override { return kInvalidSlot; }
bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
bool IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const override;
DynamicPartitionControlInterface* GetDynamicPartitionControl() override;
diff --git a/common/connection_utils.cc b/common/connection_utils.cc
deleted file mode 100644
index 44e51286..00000000
--- a/common/connection_utils.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-// Copyright (C) 2016 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/common/connection_utils.h"
-
-#include <shill/dbus-constants.h>
-
-namespace {
-// Not defined by shill since we don't use this outside of UE.
-constexpr char kTypeDisconnected[] = "Disconnected";
-constexpr char kTypeUnknown[] = "Unknown";
-} // namespace
-
-namespace chromeos_update_engine {
-namespace connection_utils {
-
-ConnectionType ParseConnectionType(const std::string& type_str) {
- if (type_str == shill::kTypeEthernet) {
- return ConnectionType::kEthernet;
- } else if (type_str == shill::kTypeWifi) {
- return ConnectionType::kWifi;
- } else if (type_str == shill::kTypeCellular) {
- return ConnectionType::kCellular;
- } else if (type_str == kTypeDisconnected) {
- return ConnectionType::kDisconnected;
- }
- return ConnectionType::kUnknown;
-}
-
-ConnectionTethering ParseConnectionTethering(const std::string& tethering_str) {
- if (tethering_str == shill::kTetheringNotDetectedState) {
- return ConnectionTethering::kNotDetected;
- } else if (tethering_str == shill::kTetheringSuspectedState) {
- return ConnectionTethering::kSuspected;
- } else if (tethering_str == shill::kTetheringConfirmedState) {
- return ConnectionTethering::kConfirmed;
- }
- return ConnectionTethering::kUnknown;
-}
-
-const char* StringForConnectionType(ConnectionType type) {
- switch (type) {
- case ConnectionType::kEthernet:
- return shill::kTypeEthernet;
- case ConnectionType::kWifi:
- return shill::kTypeWifi;
- case ConnectionType::kCellular:
- return shill::kTypeCellular;
- case ConnectionType::kDisconnected:
- return kTypeDisconnected;
- case ConnectionType::kUnknown:
- return kTypeUnknown;
- }
- return kTypeUnknown;
-}
-
-} // namespace connection_utils
-
-} // namespace chromeos_update_engine
diff --git a/common/constants.cc b/common/constants.cc
index 0677e663..ff467554 100644
--- a/common/constants.cc
+++ b/common/constants.cc
@@ -16,133 +16,4 @@
#include "update_engine/common/constants.h"
-namespace chromeos_update_engine {
-
-const char kExclusionPrefsSubDir[] = "exclusion";
-
-const char kDlcPrefsSubDir[] = "dlc";
-
-const char kPowerwashSafePrefsSubDirectory[] = "update_engine/prefs";
-
-const char kPrefsSubDirectory[] = "prefs";
-
-const char kStatefulPartition[] = "/mnt/stateful_partition";
-
-const char kPostinstallDefaultScript[] = "postinst";
-
-// Constants defining keys for the persisted state of update engine.
-const char kPrefsAttemptInProgress[] = "attempt-in-progress";
-const char kPrefsBackoffExpiryTime[] = "backoff-expiry-time";
-const char kPrefsBootId[] = "boot-id";
-const char kPrefsCurrentBytesDownloaded[] = "current-bytes-downloaded";
-const char kPrefsCurrentResponseSignature[] = "current-response-signature";
-const char kPrefsCurrentUrlFailureCount[] = "current-url-failure-count";
-const char kPrefsCurrentUrlIndex[] = "current-url-index";
-const char kPrefsDailyMetricsLastReportedAt[] =
- "daily-metrics-last-reported-at";
-const char kPrefsDeltaUpdateFailures[] = "delta-update-failures";
-const char kPrefsDynamicPartitionMetadataUpdated[] =
- "dynamic-partition-metadata-updated";
-const char kPrefsFullPayloadAttemptNumber[] = "full-payload-attempt-number";
-const char kPrefsInstallDateDays[] = "install-date-days";
-const char kPrefsLastActivePingDay[] = "last-active-ping-day";
-const char kPrefsLastRollCallPingDay[] = "last-roll-call-ping-day";
-const char kPrefsManifestMetadataSize[] = "manifest-metadata-size";
-const char kPrefsManifestSignatureSize[] = "manifest-signature-size";
-const char kPrefsMetricsAttemptLastReportingTime[] =
- "metrics-attempt-last-reporting-time";
-const char kPrefsMetricsCheckLastReportingTime[] =
- "metrics-check-last-reporting-time";
-const char kPrefsNoIgnoreBackoff[] = "no-ignore-backoff";
-const char kPrefsNumReboots[] = "num-reboots";
-const char kPrefsNumResponsesSeen[] = "num-responses-seen";
-const char kPrefsOmahaCohort[] = "omaha-cohort";
-const char kPrefsOmahaCohortHint[] = "omaha-cohort-hint";
-const char kPrefsOmahaCohortName[] = "omaha-cohort-name";
-const char kPrefsOmahaEolDate[] = "omaha-eol-date";
-const char kPrefsP2PEnabled[] = "p2p-enabled";
-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";
-const char kPrefsPingLastActive[] = "date_last_active";
-const char kPrefsPingLastRollcall[] = "date_last_rollcall";
-const char kPrefsLastFp[] = "last-fp";
-const char kPrefsPostInstallSucceeded[] = "post-install-succeeded";
-const char kPrefsPreviousVersion[] = "previous-version";
-const char kPrefsResumedUpdateFailures[] = "resumed-update-failures";
-const char kPrefsRollbackHappened[] = "rollback-happened";
-const char kPrefsRollbackVersion[] = "rollback-version";
-const char kPrefsChannelOnSlotPrefix[] = "channel-on-slot-";
-const char kPrefsSystemUpdatedMarker[] = "system-updated-marker";
-const char kPrefsTargetVersionAttempt[] = "target-version-attempt";
-const char kPrefsTargetVersionInstalledFrom[] = "target-version-installed-from";
-const char kPrefsTargetVersionUniqueId[] = "target-version-unique-id";
-const char kPrefsTotalBytesDownloaded[] = "total-bytes-downloaded";
-const char kPrefsUpdateCheckCount[] = "update-check-count";
-const char kPrefsUpdateCheckResponseHash[] = "update-check-response-hash";
-const char kPrefsUpdateCompletedBootTime[] = "update-completed-boot-time";
-const char kPrefsUpdateCompletedOnBootId[] = "update-completed-on-boot-id";
-const char kPrefsUpdateDurationUptime[] = "update-duration-uptime";
-const char kPrefsUpdateFirstSeenAt[] = "update-first-seen-at";
-const char kPrefsUpdateOverCellularPermission[] =
- "update-over-cellular-permission";
-const char kPrefsUpdateOverCellularTargetVersion[] =
- "update-over-cellular-target-version";
-const char kPrefsUpdateOverCellularTargetSize[] =
- "update-over-cellular-target-size";
-const char kPrefsUpdateServerCertificate[] = "update-server-cert";
-const char kPrefsUpdateStateNextDataLength[] = "update-state-next-data-length";
-const char kPrefsUpdateStateNextDataOffset[] = "update-state-next-data-offset";
-const char kPrefsUpdateStateNextOperation[] = "update-state-next-operation";
-const char kPrefsUpdateStatePayloadIndex[] = "update-state-payload-index";
-const char kPrefsUpdateStateSHA256Context[] = "update-state-sha-256-context";
-const char kPrefsUpdateStateSignatureBlob[] = "update-state-signature-blob";
-const char kPrefsUpdateStateSignedSHA256Context[] =
- "update-state-signed-sha-256-context";
-const char kPrefsUpdateBootTimestampStart[] = "update-boot-timestamp-start";
-const char kPrefsUpdateTimestampStart[] = "update-timestamp-start";
-const char kPrefsUrlSwitchCount[] = "url-switch-count";
-const char kPrefsVerityWritten[] = "verity-written";
-const char kPrefsWallClockScatteringWaitPeriod[] = "wall-clock-wait-period";
-const char kPrefsWallClockStagingWaitPeriod[] =
- "wall-clock-staging-wait-period";
-const char kPrefsManifestBytes[] = "manifest-bytes";
-const char kPrefsPreviousSlot[] = "previous-slot";
-
-// These four fields are generated by scripts/brillo_update_payload.
-const char kPayloadPropertyFileSize[] = "FILE_SIZE";
-const char kPayloadPropertyFileHash[] = "FILE_HASH";
-const char kPayloadPropertyMetadataSize[] = "METADATA_SIZE";
-const char kPayloadPropertyMetadataHash[] = "METADATA_HASH";
-// The Authorization: HTTP header to be sent when downloading the payload.
-const char kPayloadPropertyAuthorization[] = "AUTHORIZATION";
-// The User-Agent HTTP header to be sent when downloading the payload.
-const char kPayloadPropertyUserAgent[] = "USER_AGENT";
-// Set "POWERWASH=1" to powerwash (factory data reset) the device after
-// applying the update.
-const char kPayloadPropertyPowerwash[] = "POWERWASH";
-// The network id to pass to android_setprocnetwork before downloading.
-// 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 optional post install.
-// The default is 1 (always run post install).
-const char kPayloadPropertyRunPostInstall[] = "RUN_POST_INSTALL";
-
-const char kOmahaUpdaterVersion[] = "0.1.0.0";
-
-// X-Goog-Update headers.
-const char kXGoogleUpdateInteractivity[] = "X-Goog-Update-Interactivity";
-const char kXGoogleUpdateAppId[] = "X-Goog-Update-AppId";
-const char kXGoogleUpdateUpdater[] = "X-Goog-Update-Updater";
-const char kXGoogleUpdateSessionId[] = "X-Goog-SessionId";
-
-} // namespace chromeos_update_engine
+namespace chromeos_update_engine {} // namespace chromeos_update_engine
diff --git a/common/constants.h b/common/constants.h
index 68f720db..8c07fcf5 100644
--- a/common/constants.h
+++ b/common/constants.h
@@ -20,116 +20,176 @@
#include <cstdint>
namespace chromeos_update_engine {
-
// The root path of all exclusion prefs.
-extern const char kExclusionPrefsSubDir[];
+static constexpr const auto& kExclusionPrefsSubDir = "exclusion";
// The root path of all DLC metadata.
-extern const char kDlcPrefsSubDir[];
+static constexpr const auto& kDlcPrefsSubDir = "dlc";
// Directory for AU prefs that are preserved across powerwash.
-extern const char kPowerwashSafePrefsSubDirectory[];
+static constexpr const auto& kPowerwashSafePrefsSubDirectory =
+ "update_engine/prefs";
// The location where we store the AU preferences (state etc).
-extern const char kPrefsSubDirectory[];
-
-// Path to the post install command, relative to the partition.
-extern const char kPostinstallDefaultScript[];
+static constexpr const auto& kPrefsSubDirectory = "prefs";
// Path to the stateful partition on the root filesystem.
-extern const char kStatefulPartition[];
+static constexpr const auto& kStatefulPartition = "/mnt/stateful_partition";
+
+// Path to the post install command, relative to the partition.
+static constexpr const auto& kPostinstallDefaultScript = "postinst";
// Constants related to preferences.
-extern const char kPrefsAttemptInProgress[];
-extern const char kPrefsBackoffExpiryTime[];
-extern const char kPrefsBootId[];
-extern const char kPrefsCurrentBytesDownloaded[];
-extern const char kPrefsCurrentResponseSignature[];
-extern const char kPrefsCurrentUrlFailureCount[];
-extern const char kPrefsCurrentUrlIndex[];
-extern const char kPrefsDailyMetricsLastReportedAt[];
-extern const char kPrefsDeltaUpdateFailures[];
-extern const char kPrefsDynamicPartitionMetadataUpdated[];
-extern const char kPrefsFullPayloadAttemptNumber[];
-extern const char kPrefsInstallDateDays[];
-extern const char kPrefsLastActivePingDay[];
-extern const char kPrefsLastRollCallPingDay[];
-extern const char kPrefsManifestMetadataSize[];
-extern const char kPrefsManifestSignatureSize[];
-extern const char kPrefsMetricsAttemptLastReportingTime[];
-extern const char kPrefsMetricsCheckLastReportingTime[];
-extern const char kPrefsNoIgnoreBackoff[];
-extern const char kPrefsNumReboots[];
-extern const char kPrefsNumResponsesSeen[];
-extern const char kPrefsOmahaCohort[];
-extern const char kPrefsOmahaCohortHint[];
-extern const char kPrefsOmahaCohortName[];
-extern const char kPrefsOmahaEolDate[];
-extern const char kPrefsP2PEnabled[];
-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[];
-extern const char kPrefsLastFp[];
-extern const char kPrefsPostInstallSucceeded[];
-extern const char kPrefsPreviousVersion[];
-extern const char kPrefsPreviousSlot[];
-extern const char kPrefsResumedUpdateFailures[];
-extern const char kPrefsRollbackHappened[];
-extern const char kPrefsRollbackVersion[];
-extern const char kPrefsChannelOnSlotPrefix[];
-extern const char kPrefsSystemUpdatedMarker[];
-extern const char kPrefsTargetVersionAttempt[];
-extern const char kPrefsTargetVersionInstalledFrom[];
-extern const char kPrefsTargetVersionUniqueId[];
-extern const char kPrefsTotalBytesDownloaded[];
-extern const char kPrefsUpdateCheckCount[];
-extern const char kPrefsUpdateCheckResponseHash[];
-extern const char kPrefsUpdateCompletedBootTime[];
-extern const char kPrefsUpdateCompletedOnBootId[];
-extern const char kPrefsUpdateDurationUptime[];
-extern const char kPrefsUpdateFirstSeenAt[];
-extern const char kPrefsUpdateOverCellularPermission[];
-extern const char kPrefsUpdateOverCellularTargetVersion[];
-extern const char kPrefsUpdateOverCellularTargetSize[];
-extern const char kPrefsUpdateServerCertificate[];
-extern const char kPrefsUpdateStateNextDataLength[];
-extern const char kPrefsUpdateStateNextDataOffset[];
-extern const char kPrefsUpdateStateNextOperation[];
-extern const char kPrefsUpdateStatePayloadIndex[];
-extern const char kPrefsUpdateStateSHA256Context[];
-extern const char kPrefsUpdateStateSignatureBlob[];
-extern const char kPrefsUpdateStateSignedSHA256Context[];
-extern const char kPrefsUpdateBootTimestampStart[];
-extern const char kPrefsUpdateTimestampStart[];
-extern const char kPrefsUrlSwitchCount[];
-extern const char kPrefsVerityWritten[];
-extern const char kPrefsWallClockScatteringWaitPeriod[];
-extern const char kPrefsWallClockStagingWaitPeriod[];
-extern const char kPrefsManifestBytes[];
+// Constants defining keys for the persisted state of update engine.
+static constexpr const auto& kPrefsAttemptInProgress = "attempt-in-progress";
+static constexpr const auto& kPrefsBackoffExpiryTime = "backoff-expiry-time";
+static constexpr const auto& kPrefsBootId = "boot-id";
+static constexpr const auto& kPrefsCurrentBytesDownloaded =
+ "current-bytes-downloaded";
+static constexpr const auto& kPrefsCurrentResponseSignature =
+ "current-response-signature";
+static constexpr const auto& kPrefsCurrentUrlFailureCount =
+ "current-url-failure-count";
+static constexpr const auto& kPrefsCurrentUrlIndex = "current-url-index";
+static constexpr const auto& kPrefsDailyMetricsLastReportedAt =
+ "daily-metrics-last-reported-at";
+static constexpr const auto& kPrefsDeltaUpdateFailures =
+ "delta-update-failures";
+static constexpr const auto& kPrefsDynamicPartitionMetadataUpdated =
+ "dynamic-partition-metadata-updated";
+static constexpr const auto& kPrefsFullPayloadAttemptNumber =
+ "full-payload-attempt-number";
+static constexpr const auto& kPrefsInstallDateDays = "install-date-days";
+static constexpr const auto& kPrefsLastActivePingDay = "last-active-ping-day";
+static constexpr const auto& kPrefsLastRollCallPingDay =
+ "last-roll-call-ping-day";
+static constexpr const auto& kPrefsManifestMetadataSize =
+ "manifest-metadata-size";
+static constexpr const auto& kPrefsManifestSignatureSize =
+ "manifest-signature-size";
+static constexpr const auto& kPrefsMetricsAttemptLastReportingTime =
+ "metrics-attempt-last-reporting-time";
+static constexpr const auto& kPrefsMetricsCheckLastReportingTime =
+ "metrics-check-last-reporting-time";
+static constexpr const auto& kPrefsNoIgnoreBackoff = "no-ignore-backoff";
+static constexpr const auto& kPrefsNumReboots = "num-reboots";
+static constexpr const auto& kPrefsNumResponsesSeen = "num-responses-seen";
+static constexpr const auto& kPrefsOmahaCohort = "omaha-cohort";
+static constexpr const auto& kPrefsOmahaCohortHint = "omaha-cohort-hint";
+static constexpr const auto& kPrefsOmahaCohortName = "omaha-cohort-name";
+static constexpr const auto& kPrefsOmahaEolDate = "omaha-eol-date";
+static constexpr const auto& kPrefsP2PEnabled = "p2p-enabled";
+static constexpr const auto& kPrefsP2PFirstAttemptTimestamp =
+ "p2p-first-attempt-timestamp";
+static constexpr const auto& kPrefsP2PNumAttempts = "p2p-num-attempts";
+static constexpr const auto& kPrefsPayloadAttemptNumber =
+ "payload-attempt-number";
+static constexpr const auto& kPrefsTestUpdateCheckIntervalTimeout =
+ "test-update-check-interval-timeout";
+// Keep |kPrefsPingActive| in sync with |kDlcMetadataFilePingActive| in
+// dlcservice.
+static constexpr const auto& kPrefsPingActive = "active";
+static constexpr const auto& kPrefsPingLastActive = "date_last_active";
+static constexpr const auto& kPrefsPingLastRollcall = "date_last_rollcall";
+static constexpr const auto& kPrefsLastFp = "last-fp";
+static constexpr const auto& kPrefsPostInstallSucceeded =
+ "post-install-succeeded";
+static constexpr const auto& kPrefsPreviousVersion = "previous-version";
+static constexpr const auto& kPrefsResumedUpdateFailures =
+ "resumed-update-failures";
+static constexpr const auto& kPrefsRollbackHappened = "rollback-happened";
+static constexpr const auto& kPrefsRollbackVersion = "rollback-version";
+static constexpr const auto& kPrefsChannelOnSlotPrefix = "channel-on-slot-";
+static constexpr const auto& kPrefsSystemUpdatedMarker =
+ "system-updated-marker";
+static constexpr const auto& kPrefsTargetVersionAttempt =
+ "target-version-attempt";
+static constexpr const auto& kPrefsTargetVersionInstalledFrom =
+ "target-version-installed-from";
+static constexpr const auto& kPrefsTargetVersionUniqueId =
+ "target-version-unique-id";
+static constexpr const auto& kPrefsTotalBytesDownloaded =
+ "total-bytes-downloaded";
+static constexpr const auto& kPrefsUpdateCheckCount = "update-check-count";
+static constexpr const auto& kPrefsUpdateCheckResponseHash =
+ "update-check-response-hash";
+static constexpr const auto& kPrefsUpdateCompletedBootTime =
+ "update-completed-boot-time";
+static constexpr const auto& kPrefsUpdateCompletedOnBootId =
+ "update-completed-on-boot-id";
+static constexpr const auto& kPrefsUpdateDurationUptime =
+ "update-duration-uptime";
+static constexpr const auto& kPrefsUpdateFirstSeenAt = "update-first-seen-at";
+static constexpr const auto& kPrefsUpdateOverCellularPermission =
+ "update-over-cellular-permission";
+static constexpr const auto& kPrefsUpdateOverCellularTargetVersion =
+ "update-over-cellular-target-version";
+static constexpr const auto& kPrefsUpdateOverCellularTargetSize =
+ "update-over-cellular-target-size";
+static constexpr const auto& kPrefsUpdateServerCertificate =
+ "update-server-cert";
+static constexpr const auto& kPrefsUpdateStateNextDataLength =
+ "update-state-next-data-length";
+static constexpr const auto& kPrefsUpdateStateNextDataOffset =
+ "update-state-next-data-offset";
+static constexpr const auto& kPrefsUpdateStateNextOperation =
+ "update-state-next-operation";
+static constexpr const auto& kPrefsUpdateStatePayloadIndex =
+ "update-state-payload-index";
+static constexpr const auto& kPrefsUpdateStateSHA256Context =
+ "update-state-sha-256-context";
+static constexpr const auto& kPrefsUpdateStateSignatureBlob =
+ "update-state-signature-blob";
+static constexpr const auto& kPrefsUpdateStateSignedSHA256Context =
+ "update-state-signed-sha-256-context";
+static constexpr const auto& kPrefsUpdateBootTimestampStart =
+ "update-boot-timestamp-start";
+static constexpr const auto& kPrefsUpdateTimestampStart =
+ "update-timestamp-start";
+static constexpr const auto& kPrefsUrlSwitchCount = "url-switch-count";
+static constexpr const auto& kPrefsVerityWritten = "verity-written";
+static constexpr const auto& kPrefsWallClockScatteringWaitPeriod =
+ "wall-clock-wait-period";
+static constexpr const auto& kPrefsWallClockStagingWaitPeriod =
+ "wall-clock-staging-wait-period";
+static constexpr const auto& kPrefsManifestBytes = "manifest-bytes";
+static constexpr const auto& kPrefsPreviousSlot = "previous-slot";
// Keys used when storing and loading payload properties.
-extern const char kPayloadPropertyFileSize[];
-extern const char kPayloadPropertyFileHash[];
-extern const char kPayloadPropertyMetadataSize[];
-extern const char kPayloadPropertyMetadataHash[];
-extern const char kPayloadPropertyAuthorization[];
-extern const char kPayloadPropertyUserAgent[];
-extern const char kPayloadPropertyPowerwash[];
-extern const char kPayloadPropertyNetworkId[];
-extern const char kPayloadPropertySwitchSlotOnReboot[];
-extern const char kPayloadPropertyRunPostInstall[];
-
-extern const char kOmahaUpdaterVersion[];
+// These four fields are generated by scripts/brillo_update_payload.
+static constexpr const auto& kPayloadPropertyFileSize = "FILE_SIZE";
+static constexpr const auto& kPayloadPropertyFileHash = "FILE_HASH";
+static constexpr const auto& kPayloadPropertyMetadataSize = "METADATA_SIZE";
+static constexpr const auto& kPayloadPropertyMetadataHash = "METADATA_HASH";
+// The Authorization: HTTP header to be sent when downloading the payload.
+static constexpr const auto& kPayloadPropertyAuthorization = "AUTHORIZATION";
+// The User-Agent HTTP header to be sent when downloading the payload.
+static constexpr const auto& kPayloadPropertyUserAgent = "USER_AGENT";
+// Set "POWERWASH=1" to powerwash (factory data reset) the device after
+// applying the update.
+static constexpr const auto& kPayloadPropertyPowerwash = "POWERWASH";
+// The network id to pass to android_setprocnetwork before downloading.
+// This can be used to zero-rate OTA traffic by sending it over the correct
+// network.
+static constexpr const auto& 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).
+static constexpr const auto& kPayloadPropertySwitchSlotOnReboot =
+ "SWITCH_SLOT_ON_REBOOT";
+// Set "RUN_POST_INSTALL=0" to skip running optional post install.
+// The default is 1 (always run post install).
+static constexpr const auto& kPayloadPropertyRunPostInstall =
+ "RUN_POST_INSTALL";
+
+static constexpr const auto& kOmahaUpdaterVersion = "0.1.0.0";
// X-Goog-Update headers.
-extern const char kXGoogleUpdateInteractivity[];
-extern const char kXGoogleUpdateAppId[];
-extern const char kXGoogleUpdateUpdater[];
-extern const char kXGoogleUpdateSessionId[];
+// X-Goog-Update headers.
+static constexpr const auto& kXGoogleUpdateInteractivity =
+ "X-Goog-Update-Interactivity";
+static constexpr const auto& kXGoogleUpdateAppId = "X-Goog-Update-AppId";
+static constexpr const auto& kXGoogleUpdateUpdater = "X-Goog-Update-Updater";
+static constexpr const auto& kXGoogleUpdateSessionId = "X-Goog-SessionId";
// 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/cow_operation_convert.cc b/common/cow_operation_convert.cc
index 2564abf0..a8f7541f 100644
--- a/common/cow_operation_convert.cc
+++ b/common/cow_operation_convert.cc
@@ -24,6 +24,23 @@
namespace chromeos_update_engine {
+namespace {
+
+bool IsConsecutive(const CowOperation& op1, const CowOperation& op2) {
+ return op1.op == op2.op && op1.dst_block + op1.block_count == op2.dst_block &&
+ op1.src_block + op1.block_count == op2.src_block;
+}
+
+void push_back(std::vector<CowOperation>* converted, const CowOperation& op) {
+ if (!converted->empty() && IsConsecutive(converted->back(), op)) {
+ converted->back().block_count++;
+ } else {
+ converted->push_back(op);
+ }
+}
+
+} // namespace
+
std::vector<CowOperation> ConvertToCowOperations(
const ::google::protobuf::RepeatedPtrField<
::chromeos_update_engine::InstallOperation>& operations,
@@ -31,7 +48,6 @@ std::vector<CowOperation> ConvertToCowOperations(
merge_operations) {
ExtentRanges merge_extents;
std::vector<CowOperation> converted;
- ExtentRanges modified_extents;
// We want all CowCopy ops to be done first, before any COW_REPLACE happen.
// Therefore we add these ops in 2 separate loops. This is because during
@@ -53,8 +69,7 @@ std::vector<CowOperation> ConvertToCowOperations(
for (uint64_t i = src_extent.num_blocks(); i > 0; i--) {
auto src_block = src_extent.start_block() + i - 1;
auto dst_block = dst_extent.start_block() + i - 1;
- converted.push_back({CowOperation::CowCopy, src_block, dst_block});
- modified_extents.AddBlock(dst_block);
+ converted.push_back({CowOperation::CowCopy, src_block, dst_block, 1});
}
}
// COW_REPLACE are added after COW_COPY, because replace might modify blocks
@@ -68,10 +83,11 @@ std::vector<CowOperation> ConvertToCowOperations(
BlockIterator it1{src_extents};
BlockIterator it2{dst_extents};
while (!it1.is_end() && !it2.is_end()) {
- auto src_block = *it1;
- auto dst_block = *it2;
+ const auto src_block = *it1;
+ const auto dst_block = *it2;
if (!merge_extents.ContainsBlock(dst_block)) {
- converted.push_back({CowOperation::CowReplace, src_block, dst_block});
+ push_back(&converted,
+ {CowOperation::CowReplace, src_block, dst_block, 1});
}
++it1;
++it2;
diff --git a/common/cow_operation_convert.h b/common/cow_operation_convert.h
index c0543f7b..60c820f9 100644
--- a/common/cow_operation_convert.h
+++ b/common/cow_operation_convert.h
@@ -30,8 +30,9 @@ struct CowOperation {
CowReplace = android::snapshot::kCowReplaceOp,
};
Type op;
- uint64_t src_block;
- uint64_t dst_block;
+ uint64_t src_block{};
+ uint64_t dst_block{};
+ uint64_t block_count{1};
};
// Convert SOURCE_COPY operations in `operations` list to a list of
diff --git a/common/cow_operation_convert_unittest.cc b/common/cow_operation_convert_unittest.cc
index 93173fe8..d5b522ab 100644
--- a/common/cow_operation_convert_unittest.cc
+++ b/common/cow_operation_convert_unittest.cc
@@ -46,7 +46,8 @@ std::ostream& operator<<(std::ostream& out, CowOperation::Type op) {
}
std::ostream& operator<<(std::ostream& out, const CowOperation& c) {
- out << "{" << c.op << ", " << c.src_block << ", " << c.dst_block << "}";
+ out << "{" << c.op << ", " << c.src_block << ", " << c.dst_block << ", "
+ << c.block_count << "}";
return out;
}
@@ -63,18 +64,24 @@ class CowOperationConvertTest : public testing::Test {
ExtentRanges modified_extents;
for (auto&& cow_op : cow_ops) {
if (cow_op.op == CowOperation::CowCopy) {
- EXPECT_TRUE(src_extent_set.ContainsBlock(cow_op.src_block));
- // converted operations should be conflict free.
- EXPECT_FALSE(modified_extents.ContainsBlock(cow_op.src_block))
- << "SOURCE_COPY operation " << cow_op
- << " read from a modified block";
+ for (size_t i = 0; i < cow_op.block_count; i++) {
+ ASSERT_TRUE(src_extent_set.ContainsBlock(cow_op.src_block + i));
+ // converted operations should be conflict free.
+ ASSERT_FALSE(modified_extents.ContainsBlock(cow_op.src_block + i))
+ << "SOURCE_COPY operation " << cow_op
+ << " read from a modified block";
+ }
}
- EXPECT_TRUE(dst_extent_set.ContainsBlock(cow_op.dst_block));
- dst_extent_set.SubtractExtent(ExtentForRange(cow_op.dst_block, 1));
- modified_extents.AddBlock(cow_op.dst_block);
+ for (size_t i = 0; i < cow_op.block_count; i++) {
+ ASSERT_TRUE(dst_extent_set.ContainsBlock(cow_op.dst_block + i));
+ }
+ dst_extent_set.SubtractExtent(
+ ExtentForRange(cow_op.dst_block, cow_op.block_count));
+ modified_extents.AddExtent(
+ ExtentForRange(cow_op.dst_block, cow_op.block_count));
}
// The generated CowOps should cover all extents in InstallOps.
- EXPECT_EQ(dst_extent_set.blocks(), 0UL);
+ ASSERT_EQ(dst_extent_set.blocks(), 0UL);
// It's possible that src_extent_set is non-empty, because some operations
// will be converted to CowReplace, and we don't count the source extent for
// those.
@@ -233,4 +240,61 @@ TEST_F(CowOperationConvertTest, SelfOverlappingOperation) {
VerifyCowMergeOp(cow_ops);
}
+TEST_F(CowOperationConvertTest, CowReplaceCoalesce) {
+ AddOperation(
+ &operations_, InstallOperation::SOURCE_COPY, {{30, 10}}, {{0, 10}});
+
+ AddMergeOperation(
+ &merge_operations_, CowMergeOperation::COW_COPY, {30, 1}, {0, 1});
+ AddMergeOperation(
+ &merge_operations_, CowMergeOperation::COW_COPY, {31, 1}, {1, 1});
+ AddMergeOperation(
+ &merge_operations_, CowMergeOperation::COW_COPY, {32, 1}, {2, 1});
+
+ auto cow_ops = ConvertToCowOperations(operations_, merge_operations_);
+ for (const auto& op : cow_ops) {
+ LOG(INFO) << op;
+ }
+ ASSERT_EQ(cow_ops.size(), 4UL);
+ // Expect 3 COW_COPY and 1 COW_REPLACE
+ ASSERT_EQ(std::count_if(cow_ops.begin(),
+ cow_ops.end(),
+ [](auto&& cow_op) {
+ return cow_op.op == CowOperation::CowCopy;
+ }),
+ 3);
+ ASSERT_EQ(std::count_if(cow_ops.begin(),
+ cow_ops.end(),
+ [](auto&& cow_op) {
+ return cow_op.op == CowOperation::CowReplace;
+ }),
+ 1);
+ VerifyCowMergeOp(cow_ops);
+}
+
+TEST_F(CowOperationConvertTest, CowReplaceDifferenceSrc) {
+ AddOperation(
+ &operations_, InstallOperation::SOURCE_COPY, {{30, 10}}, {{0, 10}});
+ AddOperation(
+ &operations_, InstallOperation::SOURCE_COPY, {{100, 10}}, {{10, 10}});
+
+ auto cow_ops = ConvertToCowOperations(operations_, merge_operations_);
+ for (const auto& op : cow_ops) {
+ LOG(INFO) << op;
+ }
+ ASSERT_EQ(cow_ops.size(), 2UL);
+ // |src_block| matters. Even for ReplaceOperation.
+ // As update_engine still need to know where the data come from.
+ ASSERT_EQ(cow_ops[0].op, CowOperation::CowReplace);
+ ASSERT_EQ(cow_ops[0].src_block, 30UL);
+ ASSERT_EQ(cow_ops[0].dst_block, 0UL);
+ ASSERT_EQ(cow_ops[0].block_count, 10UL);
+
+ ASSERT_EQ(cow_ops[1].op, CowOperation::CowReplace);
+ ASSERT_EQ(cow_ops[1].src_block, 100UL);
+ ASSERT_EQ(cow_ops[1].dst_block, 10UL);
+ ASSERT_EQ(cow_ops[1].block_count, 10UL);
+ VerifyCowMergeOp(cow_ops);
+}
+
} // namespace chromeos_update_engine
diff --git a/common/dlcservice_stub.cc b/common/dlcservice_stub.cc
deleted file mode 100644
index 24471470..00000000
--- a/common/dlcservice_stub.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright (C) 2018 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/common/dlcservice_stub.h"
-
-#include <memory>
-
-using std::string;
-using std::vector;
-
-namespace chromeos_update_engine {
-
-std::unique_ptr<DlcServiceInterface> CreateDlcService() {
- return std::make_unique<DlcServiceStub>();
-}
-
-bool DlcServiceStub::GetDlcsToUpdate(vector<string>* dlc_ids) {
- if (dlc_ids)
- dlc_ids->clear();
- return true;
-}
-
-bool DlcServiceStub::InstallCompleted(const vector<string>& dlc_ids) {
- return true;
-}
-bool DlcServiceStub::UpdateCompleted(const vector<string>& dlc_ids) {
- return true;
-}
-
-} // namespace chromeos_update_engine
diff --git a/common/download_action.h b/common/download_action.h
index 7b496b17..ee6c8be6 100644
--- a/common/download_action.h
+++ b/common/download_action.h
@@ -73,11 +73,13 @@ class DownloadAction : public InstallPlanAction, public HttpFetcherDelegate {
// A good calling pattern is:
// DownloadAction(prefs, boot_contol, hardware,
// new WhateverHttpFetcher, false);
- DownloadAction(PrefsInterface* prefs,
- BootControlInterface* boot_control,
- HardwareInterface* hardware,
- HttpFetcher* http_fetcher,
- bool interactive);
+ DownloadAction(
+ PrefsInterface* prefs,
+ BootControlInterface* boot_control,
+ HardwareInterface* hardware,
+ HttpFetcher* http_fetcher,
+ bool interactive,
+ std::string update_certs_path = constants::kUpdateCertificatesPath);
~DownloadAction() override;
// InstallPlanAction overrides.
@@ -152,6 +154,9 @@ class DownloadAction : public InstallPlanAction, public HttpFetcherDelegate {
// Offset of the payload in the download URL, used by UpdateAttempterAndroid.
int64_t base_offset_{0};
+ // The path to the zip file with X509 certificates.
+ const std::string update_certificates_path_;
+
DISALLOW_COPY_AND_ASSIGN(DownloadAction);
};
diff --git a/common/dynamic_partition_control_interface.h b/common/dynamic_partition_control_interface.h
index a5be6e1a..2c01b1a9 100644
--- a/common/dynamic_partition_control_interface.h
+++ b/common/dynamic_partition_control_interface.h
@@ -73,6 +73,8 @@ class DynamicPartitionControlInterface {
// DOES NOT tell you if VABC is used for current OTA update. For that, use
// UpdateUsesSnapshotCompression.
virtual FeatureFlag GetVirtualAbCompressionFeatureFlag() = 0;
+ // Return the feature flag for Virtual AB Compression XOR
+ virtual FeatureFlag GetVirtualAbCompressionXorFeatureFlag() = 0;
// Attempt to optimize |operation|.
// If successful, |optimized| contains an operation with extents that
@@ -167,7 +169,7 @@ class DynamicPartitionControlInterface {
bool is_append = false) = 0;
// Open a general purpose FD capable to reading and writing to COW. Note that
// writes must be block aligned.
- virtual FileDescriptorPtr OpenCowFd(
+ virtual std::unique_ptr<FileDescriptor> OpenCowFd(
const std::string& unsuffixed_partition_name,
const std::optional<std::string>&,
bool is_append = false) = 0;
diff --git a/common/dynamic_partition_control_stub.cc b/common/dynamic_partition_control_stub.cc
index dd30a8b6..6283b1db 100644
--- a/common/dynamic_partition_control_stub.cc
+++ b/common/dynamic_partition_control_stub.cc
@@ -38,6 +38,10 @@ FeatureFlag DynamicPartitionControlStub::GetVirtualAbCompressionFeatureFlag() {
return FeatureFlag(FeatureFlag::Value::NONE);
}
+FeatureFlag DynamicPartitionControlStub::GetVirtualAbCompressionXorFeatureFlag() {
+ return FeatureFlag(FeatureFlag::Value::NONE);
+}
+
bool DynamicPartitionControlStub::OptimizeOperation(
const std::string& partition_name,
const InstallOperation& operation,
diff --git a/common/dynamic_partition_control_stub.h b/common/dynamic_partition_control_stub.h
index 515ec7c9..15137d2c 100644
--- a/common/dynamic_partition_control_stub.h
+++ b/common/dynamic_partition_control_stub.h
@@ -27,11 +27,12 @@
namespace chromeos_update_engine {
-class DynamicPartitionControlStub : public DynamicPartitionControlInterface {
+class DynamicPartitionControlStub final : public DynamicPartitionControlInterface {
public:
FeatureFlag GetDynamicPartitionsFeatureFlag() override;
FeatureFlag GetVirtualAbFeatureFlag() override;
FeatureFlag GetVirtualAbCompressionFeatureFlag() override;
+ FeatureFlag GetVirtualAbCompressionXorFeatureFlag() override;
bool OptimizeOperation(const std::string& partition_name,
const InstallOperation& operation,
InstallOperation* optimized) override;
@@ -65,9 +66,10 @@ class DynamicPartitionControlStub : public DynamicPartitionControlInterface {
const std::optional<std::string>&,
bool is_append) override;
- FileDescriptorPtr OpenCowFd(const std::string& unsuffixed_partition_name,
- const std::optional<std::string>&,
- bool is_append = false) override {
+ std::unique_ptr<FileDescriptor> OpenCowFd(
+ const std::string& unsuffixed_partition_name,
+ const std::optional<std::string>&,
+ bool is_append = false) override {
return nullptr;
}
diff --git a/common/fake_boot_control.h b/common/fake_boot_control.h
index 79e21390..8a685016 100644
--- a/common/fake_boot_control.h
+++ b/common/fake_boot_control.h
@@ -83,6 +83,7 @@ class FakeBootControl : public BootControlInterface {
}
bool SetActiveBootSlot(Slot slot) override { return true; }
+ Slot GetActiveBootSlot() override { return kInvalidSlot; }
bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override {
// We run the callback directly from here to avoid having to setup a message
diff --git a/common/fake_prefs.cc b/common/fake_prefs.cc
index ea6ea60d..e87e0ec2 100644
--- a/common/fake_prefs.cc
+++ b/common/fake_prefs.cc
@@ -28,7 +28,7 @@ using chromeos_update_engine::FakePrefs;
namespace {
-void CheckNotNull(const string& key, void* ptr) {
+void CheckNotNull(std::string_view key, void* ptr) {
EXPECT_NE(nullptr, ptr) << "Called Get*() for key \"" << key
<< "\" with a null parameter.";
}
@@ -63,41 +63,41 @@ template <>
bool FakePrefs::PrefValue::*const FakePrefs::PrefConsts<bool>::member =
&FakePrefs::PrefValue::as_bool;
-bool FakePrefs::GetString(const string& key, string* value) const {
+bool FakePrefs::GetString(std::string_view key, string* value) const {
return GetValue(key, value);
}
-bool FakePrefs::SetString(const string& key, std::string_view value) {
+bool FakePrefs::SetString(std::string_view key, std::string_view value) {
SetValue(key, std::string(value));
return true;
}
-bool FakePrefs::GetInt64(const string& key, int64_t* value) const {
+bool FakePrefs::GetInt64(std::string_view key, int64_t* value) const {
return GetValue(key, value);
}
-bool FakePrefs::SetInt64(const string& key, const int64_t value) {
+bool FakePrefs::SetInt64(std::string_view key, const int64_t value) {
SetValue(key, value);
return true;
}
-bool FakePrefs::GetBoolean(const string& key, bool* value) const {
+bool FakePrefs::GetBoolean(std::string_view key, bool* value) const {
return GetValue(key, value);
}
-bool FakePrefs::SetBoolean(const string& key, const bool value) {
+bool FakePrefs::SetBoolean(std::string_view key, const bool value) {
SetValue(key, value);
return true;
}
-bool FakePrefs::Exists(const string& key) const {
+bool FakePrefs::Exists(std::string_view key) const {
return values_.find(key) != values_.end();
}
-bool FakePrefs::Delete(const string& key) {
+bool FakePrefs::Delete(std::string_view key) {
if (values_.find(key) == values_.end())
return false;
- values_.erase(key);
+ values_.erase(std::string{key});
const auto observers_for_key = observers_.find(key);
if (observers_for_key != observers_.end()) {
std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
@@ -107,7 +107,7 @@ bool FakePrefs::Delete(const string& key) {
return true;
}
-bool FakePrefs::Delete(const string& key, const vector<string>& nss) {
+bool FakePrefs::Delete(std::string_view key, const vector<string>& nss) {
bool success = Delete(key);
for (const auto& ns : nss) {
vector<string> ns_keys;
@@ -123,7 +123,7 @@ bool FakePrefs::Delete(const string& key, const vector<string>& nss) {
return success;
}
-bool FakePrefs::GetSubKeys(const string& ns, vector<string>* keys) const {
+bool FakePrefs::GetSubKeys(std::string_view ns, vector<string>* keys) const {
for (const auto& pr : values_)
if (pr.first.compare(0, ns.length(), ns) == 0)
keys->push_back(pr.first);
@@ -142,7 +142,7 @@ string FakePrefs::GetTypeName(PrefType type) {
return "Unknown";
}
-void FakePrefs::CheckKeyType(const string& key, PrefType type) const {
+void FakePrefs::CheckKeyType(std::string_view key, PrefType type) const {
auto it = values_.find(key);
EXPECT_TRUE(it == values_.end() || it->second.type == type)
<< "Key \"" << key << "\" if defined as " << GetTypeName(it->second.type)
@@ -150,10 +150,11 @@ void FakePrefs::CheckKeyType(const string& key, PrefType type) const {
}
template <typename T>
-void FakePrefs::SetValue(const string& key, T value) {
+void FakePrefs::SetValue(std::string_view key, T value) {
+ std::string str_key{key};
CheckKeyType(key, PrefConsts<T>::type);
- values_[key].type = PrefConsts<T>::type;
- values_[key].value.*(PrefConsts<T>::member) = std::move(value);
+ values_[str_key].type = PrefConsts<T>::type;
+ values_[str_key].value.*(PrefConsts<T>::member) = std::move(value);
const auto observers_for_key = observers_.find(key);
if (observers_for_key != observers_.end()) {
std::vector<ObserverInterface*> copy_observers(observers_for_key->second);
@@ -163,7 +164,7 @@ void FakePrefs::SetValue(const string& key, T value) {
}
template <typename T>
-bool FakePrefs::GetValue(const string& key, T* value) const {
+bool FakePrefs::GetValue(std::string_view key, T* value) const {
CheckKeyType(key, PrefConsts<T>::type);
auto it = values_.find(key);
if (it == values_.end())
@@ -173,12 +174,14 @@ bool FakePrefs::GetValue(const string& key, T* value) const {
return true;
}
-void FakePrefs::AddObserver(const string& key, ObserverInterface* observer) {
- observers_[key].push_back(observer);
+void FakePrefs::AddObserver(std::string_view key, ObserverInterface* observer) {
+ observers_[string{key}].push_back(observer);
}
-void FakePrefs::RemoveObserver(const string& key, ObserverInterface* observer) {
- std::vector<ObserverInterface*>& observers_for_key = observers_[key];
+void FakePrefs::RemoveObserver(std::string_view key,
+ ObserverInterface* observer) {
+ string str_key{key};
+ std::vector<ObserverInterface*>& observers_for_key = observers_[str_key];
auto observer_it =
std::find(observers_for_key.begin(), observers_for_key.end(), observer);
EXPECT_NE(observer_it, observers_for_key.end())
@@ -186,7 +189,7 @@ void FakePrefs::RemoveObserver(const string& key, ObserverInterface* observer) {
if (observer_it != observers_for_key.end())
observers_for_key.erase(observer_it);
if (observers_for_key.empty())
- observers_.erase(key);
+ observers_.erase(str_key);
}
} // namespace chromeos_update_engine
diff --git a/common/fake_prefs.h b/common/fake_prefs.h
index 430c2914..7ae9fb92 100644
--- a/common/fake_prefs.h
+++ b/common/fake_prefs.h
@@ -17,6 +17,7 @@
#ifndef UPDATE_ENGINE_COMMON_FAKE_PREFS_H_
#define UPDATE_ENGINE_COMMON_FAKE_PREFS_H_
+#include <functional>
#include <map>
#include <string>
#include <string_view>
@@ -40,24 +41,23 @@ class FakePrefs : public PrefsInterface {
~FakePrefs();
// PrefsInterface methods.
- bool GetString(const std::string& key, std::string* value) const override;
- bool SetString(const std::string& key, std::string_view value) override;
- bool GetInt64(const std::string& key, int64_t* value) const override;
- bool SetInt64(const std::string& key, const int64_t value) override;
- bool GetBoolean(const std::string& key, bool* value) const override;
- bool SetBoolean(const std::string& key, const bool value) override;
-
- bool Exists(const std::string& key) const override;
- bool Delete(const std::string& key) override;
- bool Delete(const std::string& key,
+ bool GetString(std::string_view key, std::string* value) const override;
+ bool SetString(std::string_view key, std::string_view value) override;
+ bool GetInt64(std::string_view key, int64_t* value) const override;
+ bool SetInt64(std::string_view key, const int64_t value) override;
+ bool GetBoolean(std::string_view key, bool* value) const override;
+ bool SetBoolean(std::string_view key, const bool value) override;
+
+ bool Exists(std::string_view key) const override;
+ bool Delete(std::string_view key) override;
+ bool Delete(std::string_view key,
const std::vector<std::string>& nss) override;
- bool GetSubKeys(const std::string& ns,
+ bool GetSubKeys(std::string_view ns,
std::vector<std::string>* keys) const override;
- void AddObserver(const std::string& key,
- ObserverInterface* observer) override;
- void RemoveObserver(const std::string& key,
+ void AddObserver(std::string_view key, ObserverInterface* observer) override;
+ void RemoveObserver(std::string_view key,
ObserverInterface* observer) override;
private:
@@ -92,24 +92,25 @@ class FakePrefs : public PrefsInterface {
static std::string GetTypeName(PrefType type);
// Checks that the |key| is either not present or has the given |type|.
- void CheckKeyType(const std::string& key, PrefType type) const;
+ void CheckKeyType(std::string_view key, PrefType type) const;
// Helper function to set a value of the passed |key|. It sets the type based
// on the template parameter T.
template <typename T>
- void SetValue(const std::string& key, T value);
+ void SetValue(std::string_view key, T value);
// Helper function to get a value from the map checking for invalid calls.
// The function fails the test if you attempt to read a value defined as a
// different type. Returns whether the get succeeded.
template <typename T>
- bool GetValue(const std::string& key, T* value) const;
+ bool GetValue(std::string_view key, T* value) const;
// Container for all the key/value pairs.
- std::map<std::string, PrefTypeValue> values_;
+ std::map<std::string, PrefTypeValue, std::less<>> values_;
// The registered observers watching for changes.
- std::map<std::string, std::vector<ObserverInterface*>> observers_;
+ std::map<std::string, std::vector<ObserverInterface*>, std::less<>>
+ observers_;
DISALLOW_COPY_AND_ASSIGN(FakePrefs);
};
diff --git a/common/file_fetcher.h b/common/file_fetcher.h
index bd390074..0f034e33 100644
--- a/common/file_fetcher.h
+++ b/common/file_fetcher.h
@@ -23,7 +23,6 @@
#include <base/logging.h>
#include <base/macros.h>
-#include <brillo/message_loops/message_loop.h>
#include <brillo/streams/stream.h>
#include "update_engine/common/http_fetcher.h"
diff --git a/common/hash_calculator.cc b/common/hash_calculator.cc
index 60812d56..ea56beaf 100644
--- a/common/hash_calculator.cc
+++ b/common/hash_calculator.cc
@@ -125,4 +125,18 @@ bool HashCalculator::SetContext(const string& context) {
return true;
}
+std::string HashCalculator::SHA256Digest(std::string_view blob) {
+ std::vector<unsigned char> hash;
+ HashCalculator::RawHashOfBytes(blob.data(), blob.size(), &hash);
+ return HexEncode(hash);
+}
+
+std::string HashCalculator::SHA256Digest(std::vector<unsigned char> blob) {
+ return SHA256Digest(ToStringView(blob));
+}
+
+std::string HashCalculator::SHA256Digest(std::vector<char> blob) {
+ return SHA256Digest(ToStringView(blob));
+}
+
} // namespace chromeos_update_engine
diff --git a/common/hash_calculator.h b/common/hash_calculator.h
index 44261284..dd7b2e8c 100644
--- a/common/hash_calculator.h
+++ b/common/hash_calculator.h
@@ -76,6 +76,10 @@ class HashCalculator {
off_t length,
brillo::Blob* out_hash);
static bool RawHashOfFile(const std::string& name, brillo::Blob* out_hash);
+ static std::string SHA256Digest(std::string_view blob);
+
+ static std::string SHA256Digest(std::vector<unsigned char> blob);
+ static std::string SHA256Digest(std::vector<char> blob);
private:
// If non-empty, the final raw hash. Will only be set to non-empty when
diff --git a/common/http_fetcher.h b/common/http_fetcher.h
index 7fa5f098..80985afb 100644
--- a/common/http_fetcher.h
+++ b/common/http_fetcher.h
@@ -170,7 +170,7 @@ class HttpFetcher {
ErrorCode auxiliary_error_code_{ErrorCode::kSuccess};
// The delegate; may be null.
- HttpFetcherDelegate* delegate_;
+ HttpFetcherDelegate* delegate_ = nullptr;
// Proxy servers
std::deque<std::string> proxies_;
diff --git a/common/http_fetcher_unittest.cc b/common/http_fetcher_unittest.cc
index 99ea99bd..bc8a3257 100644
--- a/common/http_fetcher_unittest.cc
+++ b/common/http_fetcher_unittest.cc
@@ -97,6 +97,8 @@ static inline string LocalServerUrlForPath(in_port_t port, const string& path) {
// Class hierarchy for HTTP server implementations.
//
+namespace {
+
class HttpServer {
public:
// This makes it an abstract class (dirty but works).
@@ -193,10 +195,10 @@ const char* PythonHttpServer::kServerListeningMsgPrefix = "listening on port ";
// Class hierarchy for HTTP fetcher test wrappers.
//
-class AnyHttpFetcherTest {
+class AnyHttpFetcherFactory {
public:
- AnyHttpFetcherTest() {}
- virtual ~AnyHttpFetcherTest() {}
+ AnyHttpFetcherFactory() {}
+ virtual ~AnyHttpFetcherFactory() {}
virtual HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) = 0;
HttpFetcher* NewLargeFetcher(size_t num_proxies) {
@@ -231,10 +233,10 @@ class AnyHttpFetcherTest {
FakeHardware fake_hardware_;
};
-class MockHttpFetcherTest : public AnyHttpFetcherTest {
+class MockHttpFetcherFactory : public AnyHttpFetcherFactory {
public:
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewLargeFetcher;
+ using AnyHttpFetcherFactory::NewLargeFetcher;
HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
brillo::Blob big_data(1000000);
return new MockHttpFetcher(
@@ -242,7 +244,7 @@ class MockHttpFetcherTest : public AnyHttpFetcherTest {
}
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewSmallFetcher;
+ using AnyHttpFetcherFactory::NewSmallFetcher;
HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
return new MockHttpFetcher("x", 1, proxy_resolver);
}
@@ -255,10 +257,10 @@ class MockHttpFetcherTest : public AnyHttpFetcherTest {
HttpServer* CreateServer() override { return new NullHttpServer; }
};
-class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
+class LibcurlHttpFetcherFactory : public AnyHttpFetcherFactory {
public:
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewLargeFetcher;
+ using AnyHttpFetcherFactory::NewLargeFetcher;
HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
LibcurlHttpFetcher* ret =
new LibcurlHttpFetcher(proxy_resolver, &fake_hardware_);
@@ -270,7 +272,7 @@ class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
}
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewSmallFetcher;
+ using AnyHttpFetcherFactory::NewSmallFetcher;
HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
return NewLargeFetcher(proxy_resolver);
}
@@ -298,10 +300,10 @@ class LibcurlHttpFetcherTest : public AnyHttpFetcherTest {
HttpServer* CreateServer() override { return new PythonHttpServer; }
};
-class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
+class MultiRangeHttpFetcherFactory : public LibcurlHttpFetcherFactory {
public:
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewLargeFetcher;
+ using AnyHttpFetcherFactory::NewLargeFetcher;
HttpFetcher* NewLargeFetcher(ProxyResolver* proxy_resolver) override {
MultiRangeHttpFetcher* ret = new MultiRangeHttpFetcher(
new LibcurlHttpFetcher(proxy_resolver, &fake_hardware_));
@@ -315,7 +317,7 @@ class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
}
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewSmallFetcher;
+ using AnyHttpFetcherFactory::NewSmallFetcher;
HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
return NewLargeFetcher(proxy_resolver);
}
@@ -323,16 +325,16 @@ class MultiRangeHttpFetcherTest : public LibcurlHttpFetcherTest {
bool IsMulti() const override { return true; }
};
-class FileFetcherTest : public AnyHttpFetcherTest {
+class FileFetcherFactory : public AnyHttpFetcherFactory {
public:
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewLargeFetcher;
+ using AnyHttpFetcherFactory::NewLargeFetcher;
HttpFetcher* NewLargeFetcher(ProxyResolver* /* proxy_resolver */) override {
return new FileFetcher();
}
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewSmallFetcher;
+ using AnyHttpFetcherFactory::NewSmallFetcher;
HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
return NewLargeFetcher(proxy_resolver);
}
@@ -372,10 +374,10 @@ class FileFetcherTest : public AnyHttpFetcherTest {
ScopedTempFile temp_file_{"ue_file_fetcher.XXXXXX"};
};
-class MultiRangeHttpFetcherOverFileFetcherTest : public FileFetcherTest {
+class MultiRangeHttpFetcherOverFileFetcherFactory : public FileFetcherFactory {
public:
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewLargeFetcher;
+ using AnyHttpFetcherFactory::NewLargeFetcher;
HttpFetcher* NewLargeFetcher(ProxyResolver* /* proxy_resolver */) override {
MultiRangeHttpFetcher* ret = new MultiRangeHttpFetcher(new FileFetcher());
ret->ClearRanges();
@@ -389,7 +391,7 @@ class MultiRangeHttpFetcherOverFileFetcherTest : public FileFetcherTest {
}
// Necessary to unhide the definition in the base class.
- using AnyHttpFetcherTest::NewSmallFetcher;
+ using AnyHttpFetcherFactory::NewSmallFetcher;
HttpFetcher* NewSmallFetcher(ProxyResolver* proxy_resolver) override {
return NewLargeFetcher(proxy_resolver);
}
@@ -427,22 +429,21 @@ class HttpFetcherTest : public ::testing::Test {
private:
static void TypeConstraint(T* a) {
- AnyHttpFetcherTest* b = a;
+ AnyHttpFetcherFactory* b = a;
if (b == 0) // Silence compiler warning of unused variable.
*b = a;
}
};
// Test case types list.
-typedef ::testing::Types<LibcurlHttpFetcherTest,
- MockHttpFetcherTest,
- MultiRangeHttpFetcherTest,
- FileFetcherTest,
- MultiRangeHttpFetcherOverFileFetcherTest>
+typedef ::testing::Types<LibcurlHttpFetcherFactory,
+ MockHttpFetcherFactory,
+ MultiRangeHttpFetcherFactory,
+ FileFetcherFactory,
+ MultiRangeHttpFetcherOverFileFetcherFactory>
HttpFetcherTestTypes;
TYPED_TEST_CASE(HttpFetcherTest, HttpFetcherTestTypes);
-namespace {
class HttpFetcherTestDelegate : public HttpFetcherDelegate {
public:
HttpFetcherTestDelegate() = default;
@@ -487,7 +488,6 @@ class HttpFetcherTestDelegate : public HttpFetcherDelegate {
void StartTransfer(HttpFetcher* http_fetcher, const string& url) {
http_fetcher->BeginTransfer(url);
}
-} // namespace
TYPED_TEST(HttpFetcherTest, SimpleTest) {
HttpFetcherTestDelegate delegate;
@@ -592,7 +592,6 @@ TYPED_TEST(HttpFetcherTest, ExtraHeadersInRequestTest) {
EXPECT_EQ(string::npos, delegate.data.find("X-Bar: I do not"));
}
-namespace {
class PausingHttpFetcherTestDelegate : public HttpFetcherDelegate {
public:
bool ReceivedBytes(HttpFetcher* fetcher,
@@ -626,7 +625,6 @@ void UnpausingTimeoutCallback(PausingHttpFetcherTestDelegate* delegate,
base::Bind(&UnpausingTimeoutCallback, delegate, my_id),
base::TimeDelta::FromMilliseconds(200));
}
-} // namespace
TYPED_TEST(HttpFetcherTest, PauseTest) {
PausingHttpFetcherTestDelegate delegate;
@@ -673,7 +671,6 @@ TYPED_TEST(HttpFetcherTest, PauseWhileResolvingProxyTest) {
proxy_callback.Run({1, kNoProxy});
}
-namespace {
class AbortingHttpFetcherTestDelegate : public HttpFetcherDelegate {
public:
bool ReceivedBytes(HttpFetcher* fetcher,
@@ -716,7 +713,6 @@ void AbortingTimeoutCallback(AbortingHttpFetcherTestDelegate* delegate,
*my_id = MessageLoop::kTaskIdNull;
}
}
-} // namespace
TYPED_TEST(HttpFetcherTest, AbortTest) {
AbortingHttpFetcherTestDelegate delegate;
@@ -767,7 +763,6 @@ TYPED_TEST(HttpFetcherTest, TerminateTransferWhileResolvingProxyTest) {
EXPECT_EQ(1, delegate.times_transfer_terminated_called_);
}
-namespace {
class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
public:
bool ReceivedBytes(HttpFetcher* fetcher,
@@ -784,7 +779,6 @@ class FlakyHttpFetcherTestDelegate : public HttpFetcherDelegate {
void TransferTerminated(HttpFetcher* fetcher) override { ADD_FAILURE(); }
string data;
};
-} // namespace
TYPED_TEST(HttpFetcherTest, FlakyTest) {
if (this->test_.IsMock() || !this->test_.IsHttpSupported())
@@ -818,7 +812,6 @@ TYPED_TEST(HttpFetcherTest, FlakyTest) {
}
}
-namespace {
// This delegate kills the server attached to it after receiving any bytes.
// This can be used for testing what happens when you try to fetch data and
// the server dies.
@@ -859,7 +852,6 @@ class FailureHttpFetcherTestDelegate : public HttpFetcherDelegate {
int times_transfer_terminated_called_{0};
int times_transfer_complete_called_{0};
};
-} // namespace
TYPED_TEST(HttpFetcherTest, FailureTest) {
// This test ensures that a fetcher responds correctly when a server isn't
@@ -1000,7 +992,6 @@ TYPED_TEST(HttpFetcherTest, TerminateTransferWhenServerDiedTest) {
EXPECT_TRUE(timeout);
}
-namespace {
const HttpResponseCode kRedirectCodes[] = {kHttpResponseMovedPermanently,
kHttpResponseFound,
kHttpResponseSeeOther,
@@ -1055,7 +1046,6 @@ void RedirectTest(const HttpServer* server,
}
}
}
-} // namespace
TYPED_TEST(HttpFetcherTest, SimpleRedirectTest) {
if (this->test_.IsMock() || !this->test_.IsHttpSupported())
@@ -1103,7 +1093,6 @@ TYPED_TEST(HttpFetcherTest, BeyondMaxRedirectTest) {
RedirectTest(server.get(), false, url, this->test_.NewLargeFetcher());
}
-namespace {
class MultiHttpFetcherTestDelegate : public HttpFetcherDelegate {
public:
explicit MultiHttpFetcherTestDelegate(int expected_response_code)
@@ -1173,7 +1162,6 @@ void MultiTest(HttpFetcher* fetcher_in,
EXPECT_EQ(expected_prefix,
string(delegate.data.data(), expected_prefix.size()));
}
-} // namespace
TYPED_TEST(HttpFetcherTest, MultiHttpFetcherSimpleTest) {
if (!this->test_.IsMulti())
@@ -1323,7 +1311,6 @@ TYPED_TEST(HttpFetcherTest, MultiHttpFetcherErrorIfOffsetUnrecoverableTest) {
kHttpResponseUndefined);
}
-namespace {
// This HttpFetcherDelegate calls TerminateTransfer at a configurable point.
class MultiHttpFetcherTerminateTestDelegate : public HttpFetcherDelegate {
public:
@@ -1365,7 +1352,6 @@ class MultiHttpFetcherTerminateTestDelegate : public HttpFetcherDelegate {
size_t bytes_downloaded_{0};
size_t terminate_trigger_bytes_;
};
-} // namespace
TYPED_TEST(HttpFetcherTest, MultiHttpFetcherTerminateBetweenRangesTest) {
if (!this->test_.IsMulti())
@@ -1396,7 +1382,6 @@ TYPED_TEST(HttpFetcherTest, MultiHttpFetcherTerminateBetweenRangesTest) {
EXPECT_EQ(kRangeTrigger, delegate.bytes_downloaded_);
}
-namespace {
class BlockedTransferTestDelegate : public HttpFetcherDelegate {
public:
bool ReceivedBytes(HttpFetcher* fetcher,
@@ -1412,7 +1397,7 @@ class BlockedTransferTestDelegate : public HttpFetcherDelegate {
void TransferTerminated(HttpFetcher* fetcher) override { ADD_FAILURE(); }
};
-void BlockedTransferTestHelper(AnyHttpFetcherTest* fetcher_test,
+void BlockedTransferTestHelper(AnyHttpFetcherFactory* fetcher_test,
bool is_official_build) {
if (fetcher_test->IsMock() || fetcher_test->IsMulti())
return;
@@ -1436,7 +1421,6 @@ void BlockedTransferTestHelper(AnyHttpFetcherTest* fetcher_test,
fetcher_test->SmallUrl(server->GetPort()))));
MessageLoop::current()->Run();
}
-} // namespace
TYPED_TEST(HttpFetcherTest, BlockedTransferTest) {
BlockedTransferTestHelper(&this->test_, false);
@@ -1446,4 +1430,6 @@ TYPED_TEST(HttpFetcherTest, BlockedTransferOfficialBuildTest) {
BlockedTransferTestHelper(&this->test_, true);
}
+} // namespace
+
} // namespace chromeos_update_engine
diff --git a/common/mock_dynamic_partition_control.h b/common/mock_dynamic_partition_control.h
index bfd1b0c6..fd0a5a98 100644
--- a/common/mock_dynamic_partition_control.h
+++ b/common/mock_dynamic_partition_control.h
@@ -34,9 +34,13 @@ class MockDynamicPartitionControl : public DynamicPartitionControlInterface {
MOCK_METHOD(bool, GetDeviceDir, (std::string*), (override));
MOCK_METHOD(FeatureFlag, GetDynamicPartitionsFeatureFlag, (), (override));
MOCK_METHOD(FeatureFlag, GetVirtualAbCompressionFeatureFlag, (), (override));
+ MOCK_METHOD(FeatureFlag,
+ GetVirtualAbCompressionXorFeatureFlag,
+ (),
+ (override));
MOCK_METHOD(FeatureFlag, GetVirtualAbFeatureFlag, (), (override));
MOCK_METHOD(bool, FinishUpdate, (bool), (override));
- MOCK_METHOD(FileDescriptorPtr,
+ MOCK_METHOD(std::unique_ptr<FileDescriptor>,
OpenCowFd,
(const std::string& unsuffixed_partition_name,
const std::optional<std::string>& source_path,
@@ -50,12 +54,10 @@ class MockDynamicPartitionControl : public DynamicPartitionControlInterface {
(const std::string&, const InstallOperation&, InstallOperation*),
(override));
- std::unique_ptr<android::snapshot::ISnapshotWriter> OpenCowWriter(
- const std::string& unsuffixed_partition_name,
- const std::optional<std::string>&,
- bool is_append = false) override {
- return nullptr;
- }
+ MOCK_METHOD(std::unique_ptr<android::snapshot::ISnapshotWriter>,
+ OpenCowWriter,
+ (const std::string&, const std::optional<std::string>&, bool),
+ (override));
MOCK_METHOD(
bool,
diff --git a/common/mock_http_fetcher.h b/common/mock_http_fetcher.h
index ea5b83da..3d7859ba 100644
--- a/common/mock_http_fetcher.h
+++ b/common/mock_http_fetcher.h
@@ -36,7 +36,7 @@ namespace chromeos_update_engine {
// MockHttpFetcher will send a chunk of data down in each call to BeginTransfer
// and Unpause. For the other chunks of data, a callback is put on the run
// loop and when that's called, another chunk is sent down.
-const size_t kMockHttpFetcherChunkSize(65536);
+static constexpr size_t kMockHttpFetcherChunkSize(65536);
class MockHttpFetcher : public HttpFetcher {
public:
diff --git a/common/mock_prefs.h b/common/mock_prefs.h
index 49431fbd..f3080743 100644
--- a/common/mock_prefs.h
+++ b/common/mock_prefs.h
@@ -29,27 +29,24 @@ namespace chromeos_update_engine {
class MockPrefs : public PrefsInterface {
public:
- MOCK_CONST_METHOD2(GetString,
- bool(const std::string& key, std::string* value));
- MOCK_METHOD2(SetString, bool(const std::string& key, std::string_view value));
- MOCK_CONST_METHOD2(GetInt64, bool(const std::string& key, int64_t* value));
- MOCK_METHOD2(SetInt64, bool(const std::string& key, const int64_t value));
+ MOCK_CONST_METHOD2(GetString, bool(std::string_view key, std::string* value));
+ MOCK_METHOD2(SetString, bool(std::string_view key, std::string_view value));
+ MOCK_CONST_METHOD2(GetInt64, bool(std::string_view key, int64_t* value));
+ MOCK_METHOD2(SetInt64, bool(std::string_view key, const int64_t value));
- MOCK_CONST_METHOD2(GetBoolean, bool(const std::string& key, bool* value));
- MOCK_METHOD2(SetBoolean, bool(const std::string& key, const bool value));
+ MOCK_CONST_METHOD2(GetBoolean, bool(std::string_view key, bool* value));
+ MOCK_METHOD2(SetBoolean, bool(std::string_view key, const bool value));
- MOCK_CONST_METHOD1(Exists, bool(const std::string& key));
- MOCK_METHOD1(Delete, bool(const std::string& key));
+ MOCK_CONST_METHOD1(Exists, bool(std::string_view key));
+ MOCK_METHOD1(Delete, bool(std::string_view key));
MOCK_METHOD2(Delete,
- bool(const std::string& key,
- const std::vector<std::string>& nss));
+ bool(std::string_view key, const std::vector<std::string>& nss));
MOCK_CONST_METHOD2(GetSubKeys,
- bool(const std::string&, std::vector<std::string>*));
+ bool(std::string_view, std::vector<std::string>*));
- MOCK_METHOD2(AddObserver, void(const std::string& key, ObserverInterface*));
- MOCK_METHOD2(RemoveObserver,
- void(const std::string& key, ObserverInterface*));
+ MOCK_METHOD2(AddObserver, void(std::string_view key, ObserverInterface*));
+ MOCK_METHOD2(RemoveObserver, void(std::string_view key, ObserverInterface*));
};
} // namespace chromeos_update_engine
diff --git a/common/prefs.cc b/common/prefs.cc
index 1e06be44..f33a8a93 100644
--- a/common/prefs.cc
+++ b/common/prefs.cc
@@ -51,11 +51,11 @@ void DeleteEmptyDirectories(const base::FilePath& path) {
} // namespace
-bool PrefsBase::GetString(const string& key, string* value) const {
+bool PrefsBase::GetString(const std::string_view key, string* value) const {
return storage_->GetKey(key, value);
}
-bool PrefsBase::SetString(const string& key, std::string_view value) {
+bool PrefsBase::SetString(std::string_view key, std::string_view value) {
TEST_AND_RETURN_FALSE(storage_->SetKey(key, value));
const auto observers_for_key = observers_.find(key);
if (observers_for_key != observers_.end()) {
@@ -66,7 +66,7 @@ bool PrefsBase::SetString(const string& key, std::string_view value) {
return true;
}
-bool PrefsBase::GetInt64(const string& key, int64_t* value) const {
+bool PrefsBase::GetInt64(const std::string_view key, int64_t* value) const {
string str_value;
if (!GetString(key, &str_value))
return false;
@@ -75,11 +75,11 @@ bool PrefsBase::GetInt64(const string& key, int64_t* value) const {
return true;
}
-bool PrefsBase::SetInt64(const string& key, const int64_t value) {
+bool PrefsBase::SetInt64(std::string_view key, const int64_t value) {
return SetString(key, base::NumberToString(value));
}
-bool PrefsBase::GetBoolean(const string& key, bool* value) const {
+bool PrefsBase::GetBoolean(std::string_view key, bool* value) const {
string str_value;
if (!GetString(key, &str_value))
return false;
@@ -95,15 +95,15 @@ bool PrefsBase::GetBoolean(const string& key, bool* value) const {
return false;
}
-bool PrefsBase::SetBoolean(const string& key, const bool value) {
+bool PrefsBase::SetBoolean(std::string_view key, const bool value) {
return SetString(key, value ? "true" : "false");
}
-bool PrefsBase::Exists(const string& key) const {
+bool PrefsBase::Exists(std::string_view key) const {
return storage_->KeyExists(key);
}
-bool PrefsBase::Delete(const string& key) {
+bool PrefsBase::Delete(std::string_view key) {
TEST_AND_RETURN_FALSE(storage_->DeleteKey(key));
const auto observers_for_key = observers_.find(key);
if (observers_for_key != observers_.end()) {
@@ -114,7 +114,7 @@ bool PrefsBase::Delete(const string& key) {
return true;
}
-bool PrefsBase::Delete(const string& pref_key, const vector<string>& nss) {
+bool PrefsBase::Delete(std::string_view pref_key, const vector<string>& nss) {
// Delete pref key for platform.
bool success = Delete(pref_key);
// Delete pref key in each namespace.
@@ -132,16 +132,18 @@ bool PrefsBase::Delete(const string& pref_key, const vector<string>& nss) {
return success;
}
-bool PrefsBase::GetSubKeys(const string& ns, vector<string>* keys) const {
+bool PrefsBase::GetSubKeys(std::string_view ns, vector<string>* keys) const {
return storage_->GetSubKeys(ns, keys);
}
-void PrefsBase::AddObserver(const string& key, ObserverInterface* observer) {
- observers_[key].push_back(observer);
+void PrefsBase::AddObserver(std::string_view key, ObserverInterface* observer) {
+ observers_[std::string{key}].push_back(observer);
}
-void PrefsBase::RemoveObserver(const string& key, ObserverInterface* observer) {
- std::vector<ObserverInterface*>& observers_for_key = observers_[key];
+void PrefsBase::RemoveObserver(std::string_view key,
+ ObserverInterface* observer) {
+ std::vector<ObserverInterface*>& observers_for_key =
+ observers_[std::string{key}];
auto observer_it =
std::find(observers_for_key.begin(), observers_for_key.end(), observer);
if (observer_it != observers_for_key.end())
@@ -165,7 +167,7 @@ bool Prefs::FileStorage::Init(const base::FilePath& prefs_dir) {
return true;
}
-bool Prefs::FileStorage::GetKey(const string& key, string* value) const {
+bool Prefs::FileStorage::GetKey(std::string_view key, string* value) const {
base::FilePath filename;
TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
if (!base::ReadFileToString(filename, value)) {
@@ -174,7 +176,7 @@ bool Prefs::FileStorage::GetKey(const string& key, string* value) const {
return true;
}
-bool Prefs::FileStorage::GetSubKeys(const string& ns,
+bool Prefs::FileStorage::GetSubKeys(std::string_view ns,
vector<string>* keys) const {
base::FilePath filename;
TEST_AND_RETURN_FALSE(GetFileNameForKey(ns, &filename));
@@ -192,7 +194,7 @@ bool Prefs::FileStorage::GetSubKeys(const string& ns,
return true;
}
-bool Prefs::FileStorage::SetKey(const string& key, std::string_view value) {
+bool Prefs::FileStorage::SetKey(std::string_view key, std::string_view value) {
base::FilePath filename;
TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
if (!base::DirectoryExists(filename.DirName())) {
@@ -205,13 +207,13 @@ bool Prefs::FileStorage::SetKey(const string& key, std::string_view value) {
return true;
}
-bool Prefs::FileStorage::KeyExists(const string& key) const {
+bool Prefs::FileStorage::KeyExists(std::string_view key) const {
base::FilePath filename;
TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
return base::PathExists(filename);
}
-bool Prefs::FileStorage::DeleteKey(const string& key) {
+bool Prefs::FileStorage::DeleteKey(std::string_view key) {
base::FilePath filename;
TEST_AND_RETURN_FALSE(GetFileNameForKey(key, &filename));
#if BASE_VER < 800000
@@ -222,20 +224,21 @@ bool Prefs::FileStorage::DeleteKey(const string& key) {
return true;
}
-bool Prefs::FileStorage::GetFileNameForKey(const string& key,
+bool Prefs::FileStorage::GetFileNameForKey(std::string_view key,
base::FilePath* filename) const {
// Allows only non-empty keys containing [A-Za-z0-9_-/].
TEST_AND_RETURN_FALSE(!key.empty());
for (char c : key)
TEST_AND_RETURN_FALSE(base::IsAsciiAlpha(c) || base::IsAsciiDigit(c) ||
c == '_' || c == '-' || c == kKeySeparator);
- *filename = prefs_dir_.Append(key);
+ *filename = prefs_dir_.Append(
+ base::FilePath::StringPieceType(key.data(), key.size()));
return true;
}
// MemoryPrefs
-bool MemoryPrefs::MemoryStorage::GetKey(const string& key,
+bool MemoryPrefs::MemoryStorage::GetKey(std::string_view key,
string* value) const {
auto it = values_.find(key);
if (it == values_.end())
@@ -244,15 +247,13 @@ bool MemoryPrefs::MemoryStorage::GetKey(const string& key,
return true;
}
-bool MemoryPrefs::MemoryStorage::GetSubKeys(const string& ns,
+bool MemoryPrefs::MemoryStorage::GetSubKeys(std::string_view ns,
vector<string>* keys) const {
- using value_type = decltype(values_)::value_type;
- using key_type = decltype(values_)::key_type;
- auto lower_comp = [](const value_type& pr, const key_type& ns) {
- return pr.first.substr(0, ns.length()) < ns;
+ auto lower_comp = [](const auto& pr, const auto& ns) {
+ return std::string_view{pr.first.data(), ns.length()} < ns;
};
- auto upper_comp = [](const key_type& ns, const value_type& pr) {
- return ns < pr.first.substr(0, ns.length());
+ auto upper_comp = [](const auto& ns, const auto& pr) {
+ return ns < std::string_view{pr.first.data(), ns.length()};
};
auto lower_it =
std::lower_bound(begin(values_), end(values_), ns, lower_comp);
@@ -262,17 +263,17 @@ bool MemoryPrefs::MemoryStorage::GetSubKeys(const string& ns,
return true;
}
-bool MemoryPrefs::MemoryStorage::SetKey(const string& key,
+bool MemoryPrefs::MemoryStorage::SetKey(std::string_view key,
std::string_view value) {
- values_[key] = value;
+ values_[std::string{key}] = value;
return true;
}
-bool MemoryPrefs::MemoryStorage::KeyExists(const string& key) const {
+bool MemoryPrefs::MemoryStorage::KeyExists(std::string_view key) const {
return values_.find(key) != values_.end();
}
-bool MemoryPrefs::MemoryStorage::DeleteKey(const string& key) {
+bool MemoryPrefs::MemoryStorage::DeleteKey(std::string_view key) {
auto it = values_.find(key);
if (it != values_.end())
values_.erase(it);
diff --git a/common/prefs.h b/common/prefs.h
index 93477ddc..c3105c61 100644
--- a/common/prefs.h
+++ b/common/prefs.h
@@ -17,6 +17,7 @@
#ifndef UPDATE_ENGINE_COMMON_PREFS_H_
#define UPDATE_ENGINE_COMMON_PREFS_H_
+#include <functional>
#include <map>
#include <string>
#include <string_view>
@@ -41,23 +42,23 @@ class PrefsBase : public PrefsInterface {
// Get the key named |key| and store its value in the referenced |value|.
// Returns whether the operation succeeded.
- virtual bool GetKey(const std::string& key, std::string* value) const = 0;
+ virtual bool GetKey(std::string_view key, std::string* value) const = 0;
// Get the keys stored within the namespace. If there are no keys in the
// namespace, |keys| will be empty. Returns whether the operation succeeded.
- virtual bool GetSubKeys(const std::string& ns,
+ virtual bool GetSubKeys(std::string_view ns,
std::vector<std::string>* keys) const = 0;
// Set the value of the key named |key| to |value| regardless of the
// previous value. Returns whether the operation succeeded.
- virtual bool SetKey(const std::string& key, std::string_view value) = 0;
+ virtual bool SetKey(std::string_view key, std::string_view value) = 0;
// Returns whether the key named |key| exists.
- virtual bool KeyExists(const std::string& key) const = 0;
+ virtual bool KeyExists(std::string_view key) const = 0;
// Deletes the value associated with the key name |key|. Returns whether the
// key was deleted.
- virtual bool DeleteKey(const std::string& key) = 0;
+ virtual bool DeleteKey(std::string_view key) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(StorageInterface);
@@ -66,29 +67,29 @@ class PrefsBase : public PrefsInterface {
explicit PrefsBase(StorageInterface* storage) : storage_(storage) {}
// PrefsInterface methods.
- bool GetString(const std::string& key, std::string* value) const override;
- bool SetString(const std::string& key, std::string_view value) override;
- bool GetInt64(const std::string& key, int64_t* value) const override;
- bool SetInt64(const std::string& key, const int64_t value) override;
- bool GetBoolean(const std::string& key, bool* value) const override;
- bool SetBoolean(const std::string& key, const bool value) override;
-
- bool Exists(const std::string& key) const override;
- bool Delete(const std::string& key) override;
- bool Delete(const std::string& pref_key,
+ bool GetString(std::string_view key, std::string* value) const override;
+ bool SetString(std::string_view key, std::string_view value) override;
+ bool GetInt64(std::string_view key, int64_t* value) const override;
+ bool SetInt64(std::string_view key, const int64_t value) override;
+ bool GetBoolean(std::string_view key, bool* value) const override;
+ bool SetBoolean(std::string_view key, const bool value) override;
+
+ bool Exists(std::string_view key) const override;
+ bool Delete(std::string_view key) override;
+ bool Delete(std::string_view pref_key,
const std::vector<std::string>& nss) override;
- bool GetSubKeys(const std::string& ns,
+ bool GetSubKeys(std::string_view ns,
std::vector<std::string>* keys) const override;
- void AddObserver(const std::string& key,
- ObserverInterface* observer) override;
- void RemoveObserver(const std::string& key,
+ void AddObserver(std::string_view key, ObserverInterface* observer) override;
+ void RemoveObserver(std::string_view key,
ObserverInterface* observer) override;
private:
// The registered observers watching for changes.
- std::map<std::string, std::vector<ObserverInterface*>> observers_;
+ std::map<std::string, std::vector<ObserverInterface*>, std::less<>>
+ observers_;
// The concrete implementation of the storage used for the keys.
StorageInterface* storage_;
@@ -121,12 +122,12 @@ class Prefs : public PrefsBase {
bool Init(const base::FilePath& prefs_dir);
// PrefsBase::StorageInterface overrides.
- bool GetKey(const std::string& key, std::string* value) const override;
- bool GetSubKeys(const std::string& ns,
+ bool GetKey(std::string_view key, std::string* value) const override;
+ bool GetSubKeys(std::string_view ns,
std::vector<std::string>* keys) const override;
- bool SetKey(const std::string& key, std::string_view value) override;
- bool KeyExists(const std::string& key) const override;
- bool DeleteKey(const std::string& key) override;
+ bool SetKey(std::string_view key, std::string_view value) override;
+ bool KeyExists(std::string_view key) const override;
+ bool DeleteKey(std::string_view key) override;
private:
FRIEND_TEST(PrefsTest, GetFileNameForKey);
@@ -135,7 +136,7 @@ class Prefs : public PrefsBase {
// Sets |filename| to the full path to the file containing the data
// associated with |key|. Returns true on success, false otherwise.
- bool GetFileNameForKey(const std::string& key,
+ bool GetFileNameForKey(std::string_view key,
base::FilePath* filename) const;
// Preference store directory.
@@ -161,16 +162,16 @@ class MemoryPrefs : public PrefsBase {
MemoryStorage() = default;
// PrefsBase::StorageInterface overrides.
- bool GetKey(const std::string& key, std::string* value) const override;
- bool GetSubKeys(const std::string& ns,
+ bool GetKey(std::string_view, std::string* value) const override;
+ bool GetSubKeys(std::string_view ns,
std::vector<std::string>* keys) const override;
- bool SetKey(const std::string& key, std::string_view value) override;
- bool KeyExists(const std::string& key) const override;
- bool DeleteKey(const std::string& key) override;
+ bool SetKey(std::string_view key, std::string_view value) override;
+ bool KeyExists(std::string_view key) const override;
+ bool DeleteKey(std::string_view key) override;
private:
// The std::map holding the values in memory.
- std::map<std::string, std::string> values_;
+ std::map<std::string, std::string, std::less<>> values_;
};
// The concrete memory storage implementation.
diff --git a/common/prefs_interface.h b/common/prefs_interface.h
index e773a35e..69ccf683 100644
--- a/common/prefs_interface.h
+++ b/common/prefs_interface.h
@@ -37,10 +37,10 @@ class PrefsInterface {
virtual ~ObserverInterface() = default;
// Called when the value is set for the observed |key|.
- virtual void OnPrefSet(const std::string& key) = 0;
+ virtual void OnPrefSet(std::string_view key) = 0;
// Called when the observed |key| is deleted.
- virtual void OnPrefDeleted(const std::string& key) = 0;
+ virtual void OnPrefDeleted(std::string_view key) = 0;
};
virtual ~PrefsInterface() = default;
@@ -48,61 +48,61 @@ class PrefsInterface {
// Gets a string |value| associated with |key|. Returns true on
// success, false on failure (including when the |key| is not
// present in the store).
- virtual bool GetString(const std::string& key, std::string* value) const = 0;
+ virtual bool GetString(std::string_view key, std::string* value) const = 0;
// Associates |key| with a string |value|. Returns true on success,
// false otherwise.
- virtual bool SetString(const std::string& key, std::string_view value) = 0;
+ virtual bool SetString(std::string_view key, std::string_view value) = 0;
// Gets an int64_t |value| associated with |key|. Returns true on
// success, false on failure (including when the |key| is not
// present in the store).
- virtual bool GetInt64(const std::string& key, int64_t* value) const = 0;
+ virtual bool GetInt64(std::string_view key, int64_t* value) const = 0;
// Associates |key| with an int64_t |value|. Returns true on success,
// false otherwise.
- virtual bool SetInt64(const std::string& key, const int64_t value) = 0;
+ virtual bool SetInt64(std::string_view key, const int64_t value) = 0;
// Gets a boolean |value| associated with |key|. Returns true on
// success, false on failure (including when the |key| is not
// present in the store).
- virtual bool GetBoolean(const std::string& key, bool* value) const = 0;
+ virtual bool GetBoolean(std::string_view key, bool* value) const = 0;
// Associates |key| with a boolean |value|. Returns true on success,
// false otherwise.
- virtual bool SetBoolean(const std::string& key, const bool value) = 0;
+ virtual bool SetBoolean(std::string_view key, const bool value) = 0;
// Returns true if the setting exists (i.e. a file with the given key
// exists in the prefs directory)
- virtual bool Exists(const std::string& key) const = 0;
+ virtual bool Exists(std::string_view key) const = 0;
// Returns true if successfully deleted the file corresponding to
// this key. Calling with non-existent keys does nothing.
- virtual bool Delete(const std::string& key) = 0;
+ virtual bool Delete(std::string_view key) = 0;
// Deletes the pref key from platform and given namespace subdirectories.
// Keys are matched against end of pref keys in each namespace.
// Returns true if all deletes were successful.
- virtual bool Delete(const std::string& pref_key,
+ virtual bool Delete(std::string_view pref_key,
const std::vector<std::string>& nss) = 0;
// Creates a key which is part of a sub preference.
static std::string CreateSubKey(const std::vector<std::string>& ns_with_key);
// Returns a list of keys within the namespace.
- virtual bool GetSubKeys(const std::string& ns,
+ virtual bool GetSubKeys(std::string_view ns,
std::vector<std::string>* keys) const = 0;
// Add an observer to watch whenever the given |key| is modified. The
// OnPrefSet() and OnPrefDelete() methods will be called whenever any of the
// Set*() methods or the Delete() method are called on the given key,
// respectively.
- virtual void AddObserver(const std::string& key,
+ virtual void AddObserver(std::string_view key,
ObserverInterface* observer) = 0;
// Remove an observer added with AddObserver(). The observer won't be called
// anymore for future Set*() and Delete() method calls.
- virtual void RemoveObserver(const std::string& key,
+ virtual void RemoveObserver(std::string_view key,
ObserverInterface* observer) = 0;
protected:
diff --git a/common/prefs_unittest.cc b/common/prefs_unittest.cc
index a5f46e53..cef6d441 100644
--- a/common/prefs_unittest.cc
+++ b/common/prefs_unittest.cc
@@ -507,8 +507,8 @@ TEST_F(PrefsTest, DeleteMultipleNamespaces) {
class MockPrefsObserver : public PrefsInterface::ObserverInterface {
public:
- MOCK_METHOD1(OnPrefSet, void(const string&));
- MOCK_METHOD1(OnPrefDeleted, void(const string& key));
+ MOCK_METHOD1(OnPrefSet, void(std::string_view));
+ MOCK_METHOD1(OnPrefDeleted, void(std::string_view));
};
TEST_F(PrefsTest, ObserversCalled) {
diff --git a/common/subprocess.cc b/common/subprocess.cc
index 023017b9..a0cb9a71 100644
--- a/common/subprocess.cc
+++ b/common/subprocess.cc
@@ -124,7 +124,7 @@ void Subprocess::OnStdoutReady(SubprocessRecord* record) {
bool eof;
bool ok = utils::ReadAll(
record->stdout_fd, buf, base::size(buf), &bytes_read, &eof);
- record->stdout.append(buf, bytes_read);
+ record->stdout_str.append(buf, bytes_read);
if (!ok || eof) {
// There was either an error or an EOF condition, so we are done watching
// the file descriptor.
@@ -152,11 +152,11 @@ void Subprocess::ChildExitedCallback(const siginfo_t& info) {
LOG(INFO) << "Subprocess exited with si_status: " << info.si_status;
}
- if (!record->stdout.empty()) {
- LOG(INFO) << "Subprocess output:\n" << record->stdout;
+ if (!record->stdout_str.empty()) {
+ LOG(INFO) << "Subprocess output:\n" << record->stdout_str;
}
if (!record->callback.is_null()) {
- record->callback.Run(info.si_status, record->stdout);
+ record->callback.Run(info.si_status, record->stdout_str);
}
// Release and close all the pipes after calling the callback so our
// redirected pipes are still alive. Releasing the process first makes
@@ -230,29 +230,30 @@ int Subprocess::GetPipeFd(pid_t pid, int fd) const {
bool Subprocess::SynchronousExec(const vector<string>& cmd,
int* return_code,
- string* stdout,
- string* stderr) {
+ string* stdout_str,
+ string* stderr_str) {
// The default for |SynchronousExec| is to use |kSearchPath| since the code
// relies on that.
- return SynchronousExecFlags(cmd, kSearchPath, return_code, stdout, stderr);
+ return SynchronousExecFlags(
+ cmd, kSearchPath, return_code, stdout_str, stderr_str);
}
bool Subprocess::SynchronousExecFlags(const vector<string>& cmd,
uint32_t flags,
int* return_code,
- string* stdout,
- string* stderr) {
+ string* stdout_str,
+ string* stderr_str) {
brillo::ProcessImpl proc;
if (!LaunchProcess(cmd, flags, {STDERR_FILENO}, &proc)) {
LOG(ERROR) << "Failed to launch subprocess";
return false;
}
- if (stdout) {
- stdout->clear();
+ if (stdout_str) {
+ stdout_str->clear();
}
- if (stderr) {
- stderr->clear();
+ if (stderr_str) {
+ stderr_str->clear();
}
// Read from both stdout and stderr individually.
@@ -267,8 +268,8 @@ bool Subprocess::SynchronousExecFlags(const vector<string>& cmd,
stdout_closed = true;
if (rc < 0)
PLOG(ERROR) << "Reading from child's stdout";
- } else if (stdout != nullptr) {
- stdout->append(buffer.data(), rc);
+ } else if (stdout_str != nullptr) {
+ stdout_str->append(buffer.data(), rc);
}
}
@@ -278,8 +279,8 @@ bool Subprocess::SynchronousExecFlags(const vector<string>& cmd,
stderr_closed = true;
if (rc < 0)
PLOG(ERROR) << "Reading from child's stderr";
- } else if (stderr != nullptr) {
- stderr->append(buffer.data(), rc);
+ } else if (stderr_str != nullptr) {
+ stderr_str->append(buffer.data(), rc);
}
}
}
@@ -299,9 +300,9 @@ void Subprocess::FlushBufferedLogsAtExit() {
SubprocessRecord* record = pid_record.second.get();
// Make sure we read any remaining process output.
OnStdoutReady(record);
- if (!record->stdout.empty()) {
+ if (!record->stdout_str.empty()) {
LOG(INFO) << "Subprocess(" << pid_record.first << ") output:\n"
- << record->stdout;
+ << record->stdout_str;
}
}
}
diff --git a/common/subprocess.h b/common/subprocess.h
index 2ed8b81f..e59776a2 100644
--- a/common/subprocess.h
+++ b/common/subprocess.h
@@ -91,18 +91,18 @@ class Subprocess {
// |output_pipes|, otherwise returns -1.
int GetPipeFd(pid_t pid, int fd) const;
- // Executes a command synchronously. Returns true on success. If |stdout| is
- // non-null, the process output is stored in it, otherwise the output is
+ // Executes a command synchronously. Returns true on success. If |stdout_str|
+ // is non-null, the process output is stored in it, otherwise the output is
// logged.
static bool SynchronousExec(const std::vector<std::string>& cmd,
int* return_code,
- std::string* stdout,
- std::string* stderr);
+ std::string* stdout_str,
+ std::string* stderr_str);
static bool SynchronousExecFlags(const std::vector<std::string>& cmd,
uint32_t flags,
int* return_code,
- std::string* stdout,
- std::string* stderr);
+ std::string* stdout_str,
+ std::string* stderr_str);
// Gets the one instance.
static Subprocess& Get() { return *subprocess_singleton_; }
@@ -131,7 +131,7 @@ class Subprocess {
std::unique_ptr<base::FileDescriptorWatcher::Controller> stdout_controller;
int stdout_fd{-1};
- std::string stdout;
+ std::string stdout_str;
};
// Callback which runs whenever there is input available on the subprocess
diff --git a/common/test_utils.h b/common/test_utils.h
index bb5a6789..b85f80da 100644
--- a/common/test_utils.h
+++ b/common/test_utils.h
@@ -29,10 +29,10 @@
#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"
+#include "update_engine/common/testing_constants.h"
#include "update_engine/common/utils.h"
#include "update_engine/update_metadata.pb.h"
@@ -78,11 +78,6 @@ std::string Readlink(const std::string& path);
void FillWithData(brillo::Blob* buffer);
-// Compare the value of builtin 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/common/testing_constants.h b/common/testing_constants.h
new file mode 100644
index 00000000..60a7ad8d
--- /dev/null
+++ b/common/testing_constants.h
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2021 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_COMMON_TESTING_CONSTANTS_H_
+#define UPDATE_ENGINE_COMMON_TESTING_CONSTANTS_H_
+
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKeyPath =
+ "unittest_key.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestOTACertsPath = "otacerts.zip";
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKeyPath =
+ "unittest_key.pub.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKey2Path =
+ "unittest_key2.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKey2Path =
+ "unittest_key2.pub.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKeyRSA4096Path =
+ "unittest_key_RSA4096.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKeyRSA4096Path =
+ "unittest_key_RSA4096.pub.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPrivateKeyECPath =
+ "unittest_key_EC.pem";
+[[maybe_unused]] static constexpr auto&& kUnittestPublicKeyECPath =
+ "unittest_key_EC.pub.pem";
+
+#endif // UPDATE_ENGINE_COMMON_TESTING_CONSTANTS_H_
diff --git a/common/utils.cc b/common/utils.cc
index 5dbb4453..0b76eea9 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -38,6 +38,7 @@
#include <utility>
#include <vector>
+#include <android-base/strings.h>
#include <base/callback.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
@@ -63,7 +64,6 @@ using base::Time;
using base::TimeDelta;
using std::min;
using std::numeric_limits;
-using std::pair;
using std::string;
using std::vector;
@@ -181,7 +181,7 @@ bool PWriteAll(int fd, const void* buf, size_t count, off_t offset) {
return true;
}
-bool WriteAll(const FileDescriptorPtr& fd, const void* buf, size_t count) {
+bool WriteAll(FileDescriptor* fd, const void* buf, size_t count) {
const char* c_buf = static_cast<const char*>(buf);
ssize_t bytes_written = 0;
while (bytes_written < static_cast<ssize_t>(count)) {
@@ -218,7 +218,7 @@ bool PReadAll(
return true;
}
-bool ReadAll(const FileDescriptorPtr& fd,
+bool ReadAll(FileDescriptor* fd,
void* buf,
size_t count,
off_t offset,
@@ -239,7 +239,7 @@ bool ReadAll(const FileDescriptorPtr& fd,
return true;
}
-bool PReadAll(const FileDescriptorPtr& fd,
+bool PReadAll(FileDescriptor* fd,
void* buf,
size_t count,
off_t offset,
@@ -397,6 +397,19 @@ off_t FileSize(const string& path) {
return size;
}
+bool SendFile(int out_fd, int in_fd, size_t count) {
+ off64_t offset = lseek(in_fd, 0, SEEK_CUR);
+ TEST_AND_RETURN_FALSE_ERRNO(offset >= 0);
+ constexpr size_t BUFFER_SIZE = 4096;
+ while (count > 0) {
+ const auto bytes_written =
+ sendfile(out_fd, in_fd, &offset, std::min(count, BUFFER_SIZE));
+ TEST_AND_RETURN_FALSE_ERRNO(bytes_written > 0);
+ count -= bytes_written;
+ }
+ return true;
+}
+
void HexDumpArray(const uint8_t* const arr, const size_t length) {
LOG(INFO) << "Logging array of length: " << length;
const unsigned int bytes_per_line = 16;
@@ -477,12 +490,6 @@ string MakePartitionName(const string& disk_name, int partition_num) {
return partition_name;
}
-string ErrnoNumberAsString(int err) {
- char buf[100];
- buf[0] = '\0';
- return strerror_r(err, buf, sizeof(buf));
-}
-
bool FileExists(const char* path) {
struct stat stbuf;
return 0 == lstat(path, &stbuf);
@@ -555,7 +562,7 @@ bool MountFilesystem(const string& device,
const string& fs_mount_options) {
vector<const char*> fstypes;
if (type.empty()) {
- fstypes = {"ext2", "ext3", "ext4", "squashfs"};
+ fstypes = {"ext2", "ext3", "ext4", "squashfs", "erofs"};
} else {
fstypes = {type.c_str()};
}
@@ -892,21 +899,66 @@ bool GetMinorVersion(const brillo::KeyValueStore& store,
return false;
}
-bool ReadExtents(const string& path,
+bool ReadExtents(const std::string& path,
+ const google::protobuf::RepeatedPtrField<Extent>& extents,
+ brillo::Blob* out_data,
+ size_t block_size) {
+ return ReadExtents(path,
+ {extents.begin(), extents.end()},
+ out_data,
+ utils::BlocksInExtents(extents) * block_size,
+ block_size);
+}
+
+bool WriteExtents(const std::string& path,
+ const google::protobuf::RepeatedPtrField<Extent>& extents,
+ const brillo::Blob& data,
+ size_t block_size) {
+ EintrSafeFileDescriptor fd;
+ TEST_AND_RETURN_FALSE(fd.Open(path.c_str(), O_RDWR));
+ size_t bytes_written = 0;
+ for (const auto& ext : extents) {
+ TEST_AND_RETURN_FALSE_ERRNO(
+ fd.Seek(ext.start_block() * block_size, SEEK_SET));
+ TEST_AND_RETURN_FALSE_ERRNO(
+ fd.Write(data.data() + bytes_written, ext.num_blocks() * block_size));
+ bytes_written += ext.num_blocks() * block_size;
+ }
+ return true;
+}
+bool ReadExtents(const std::string& path,
+ const vector<Extent>& extents,
+ brillo::Blob* out_data,
+ ssize_t out_data_size,
+ size_t block_size) {
+ FileDescriptorPtr fd = std::make_shared<EintrSafeFileDescriptor>();
+ fd->Open(path.c_str(), O_RDONLY);
+ return ReadExtents(fd, extents, out_data, out_data_size, block_size);
+}
+
+bool ReadExtents(FileDescriptorPtr fd,
+ const google::protobuf::RepeatedPtrField<Extent>& extents,
+ brillo::Blob* out_data,
+ size_t block_size) {
+ return ReadExtents(fd,
+ {extents.begin(), extents.end()},
+ out_data,
+ utils::BlocksInExtents(extents) * block_size,
+ block_size);
+}
+
+bool ReadExtents(FileDescriptorPtr fd,
const vector<Extent>& extents,
brillo::Blob* out_data,
ssize_t out_data_size,
size_t block_size) {
brillo::Blob data(out_data_size);
ssize_t bytes_read = 0;
- int fd = open(path.c_str(), O_RDONLY);
- TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
- ScopedFdCloser fd_closer(&fd);
for (const Extent& extent : extents) {
ssize_t bytes_read_this_iteration = 0;
ssize_t bytes = extent.num_blocks() * block_size;
- TEST_AND_RETURN_FALSE(bytes_read + bytes <= out_data_size);
+ TEST_LE(bytes_read + bytes, out_data_size);
TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
&data[bytes_read],
bytes,
@@ -1010,16 +1062,16 @@ string GetExclusionName(const string& str_to_convert) {
return base::NumberToString(base::StringPieceHash()(str_to_convert));
}
-static bool ParseTimestamp(const std::string& str, int64_t* out) {
- if (!base::StringToInt64(str, out)) {
+static bool ParseTimestamp(std::string_view str, int64_t* out) {
+ if (!base::StringToInt64(base::StringPiece(str.data(), str.size()), out)) {
LOG(WARNING) << "Invalid timestamp: " << str;
return false;
}
return true;
}
-ErrorCode IsTimestampNewer(const std::string& old_version,
- const std::string& new_version) {
+ErrorCode IsTimestampNewer(const std::string_view old_version,
+ const std::string_view new_version) {
if (old_version.empty() || new_version.empty()) {
LOG(WARNING)
<< "One of old/new timestamp is empty, permit update anyway. Old: "
@@ -1040,6 +1092,40 @@ ErrorCode IsTimestampNewer(const std::string& old_version,
return ErrorCode::kSuccess;
}
+std::unique_ptr<android::base::MappedFile> GetReadonlyZeroBlock(size_t size) {
+ android::base::unique_fd fd{HANDLE_EINTR(open("/dev/zero", O_RDONLY))};
+ return android::base::MappedFile::FromFd(fd, 0, size, PROT_READ);
+}
+
+std::string_view GetReadonlyZeroString(size_t size) {
+ // Reserve 512MB of Virtual Address Space. No actual memory will be used.
+ static auto zero_block = GetReadonlyZeroBlock(1024 * 1024 * 512);
+ if (size > zero_block->size()) {
+ auto larger_block = GetReadonlyZeroBlock(size);
+ zero_block = std::move(larger_block);
+ }
+ return {zero_block->data(), size};
+}
+
} // namespace utils
+std::string HexEncode(const brillo::Blob& blob) noexcept {
+ return base::HexEncode(blob.data(), blob.size());
+}
+
+std::string HexEncode(const std::string_view blob) noexcept {
+ return base::HexEncode(blob.data(), blob.size());
+}
+
+[[nodiscard]] std::string_view ToStringView(
+ const std::vector<unsigned char>& blob) noexcept {
+ return std::string_view{reinterpret_cast<const char*>(blob.data()),
+ blob.size()};
+}
+
+[[nodiscard]] std::string_view ToStringView(const void* data,
+ size_t size) noexcept {
+ return std::string_view(reinterpret_cast<const char*>(data), size);
+}
+
} // namespace chromeos_update_engine
diff --git a/common/utils.h b/common/utils.h
index 59f236ef..201e47e9 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -30,12 +30,17 @@
#include <string>
#include <vector>
+#include <android-base/strings.h>
#include <base/files/file_path.h>
#include <base/posix/eintr_wrapper.h>
+#include <base/strings/string_number_conversions.h>
#include <base/time/time.h>
#include <brillo/key_value_store.h>
#include <brillo/secure_blob.h>
+#include "android-base/mapped_file.h"
+#include "android-base/scopeguard.h"
+#include "google/protobuf/repeated_field.h"
#include "update_engine/common/action.h"
#include "update_engine/common/action_processor.h"
#include "update_engine/common/constants.h"
@@ -63,12 +68,15 @@ bool WriteFile(const char* path, const void* data, size_t data_len);
bool WriteAll(int fd, const void* buf, size_t count);
bool PWriteAll(int fd, const void* buf, size_t count, off_t offset);
-bool WriteAll(const FileDescriptorPtr& fd, const void* buf, size_t count);
+bool WriteAll(FileDescriptor* fd, const void* buf, size_t count);
+
+constexpr bool WriteAll(const FileDescriptorPtr& fd,
+ const void* buf,
+ size_t count) {
+ return WriteAll(fd.get(), buf, count);
+}
// WriteAll writes data at specified offset, but it modifies file position.
-bool WriteAll(const FileDescriptorPtr& fd,
- const void* buf,
- size_t count,
- off_t off);
+bool WriteAll(FileDescriptorPtr* fd, const void* buf, size_t count, off_t off);
// https://man7.org/linux/man-pages/man2/pread.2.html
// PWriteAll writes data at specified offset, but it DOES NOT modify file
@@ -92,21 +100,38 @@ bool PReadAll(
int fd, void* buf, size_t count, off_t offset, ssize_t* out_bytes_read);
// Reads data at specified offset, this function does change file position.
-bool ReadAll(const FileDescriptorPtr& fd,
+
+bool ReadAll(FileDescriptor* fd,
void* buf,
size_t count,
off_t offset,
ssize_t* out_bytes_read);
+constexpr bool ReadAll(const FileDescriptorPtr& fd,
+ void* buf,
+ size_t count,
+ off_t offset,
+ ssize_t* out_bytes_read) {
+ return ReadAll(fd.get(), buf, count, offset, out_bytes_read);
+}
+
// https://man7.org/linux/man-pages/man2/pread.2.html
// Reads data at specified offset, this function DOES NOT change file position.
// Behavior is similar to linux's pread syscall.
-bool PReadAll(const FileDescriptorPtr& fd,
+bool PReadAll(FileDescriptor* fd,
void* buf,
size_t count,
off_t offset,
ssize_t* out_bytes_read);
+constexpr bool PReadAll(const FileDescriptorPtr& fd,
+ void* buf,
+ size_t count,
+ off_t offset,
+ ssize_t* out_bytes_read) {
+ return PReadAll(fd.get(), buf, count, offset, out_bytes_read);
+}
+
// Opens |path| for reading and appends its entire content to the container
// pointed to by |out_p|. Returns true upon successfully reading all of the
// file's content, false otherwise, in which case the state of the output
@@ -135,7 +160,7 @@ off_t BlockDevSize(int fd);
off_t FileSize(const std::string& path);
off_t FileSize(int fd);
-std::string ErrnoNumberAsString(int err);
+bool SendFile(int out_fd, int in_fd, size_t count);
// Returns true if the file exists for sure. Returns false if it doesn't exist,
// or an error occurs.
@@ -306,6 +331,38 @@ bool ReadExtents(const std::string& path,
ssize_t out_data_size,
size_t block_size);
+bool ReadExtents(FileDescriptorPtr path,
+ const std::vector<Extent>& extents,
+ brillo::Blob* out_data,
+ ssize_t out_data_size,
+ size_t block_size);
+
+bool WriteExtents(const std::string& path,
+ const google::protobuf::RepeatedPtrField<Extent>& extents,
+ const brillo::Blob& data,
+ size_t block_size);
+
+constexpr bool ReadExtents(const std::string& path,
+ const std::vector<Extent>& extents,
+ brillo::Blob* out_data,
+ size_t block_size) {
+ return ReadExtents(path,
+ extents,
+ out_data,
+ utils::BlocksInExtents(extents) * block_size,
+ block_size);
+}
+
+bool ReadExtents(const std::string& path,
+ const google::protobuf::RepeatedPtrField<Extent>& extents,
+ brillo::Blob* out_data,
+ size_t block_size);
+
+bool ReadExtents(FileDescriptorPtr path,
+ const google::protobuf::RepeatedPtrField<Extent>& extents,
+ brillo::Blob* out_data,
+ size_t block_size);
+
// Read the current boot identifier and store it in |boot_id|. This identifier
// is constants during the same boot of the kernel and is regenerated after
// reboot. Returns whether it succeeded getting the boot_id.
@@ -354,8 +411,12 @@ std::string GetExclusionName(const std::string& str_to_convert);
// integer.
// Return kPayloadTimestampError if both are integers but |new_version| <
// |old_version|.
-ErrorCode IsTimestampNewer(const std::string& old_version,
- const std::string& new_version);
+ErrorCode IsTimestampNewer(const std::string_view old_version,
+ const std::string_view new_version);
+
+std::unique_ptr<android::base::MappedFile> GetReadonlyZeroBlock(size_t size);
+
+std::string_view GetReadonlyZeroString(size_t size);
} // namespace utils
@@ -465,17 +526,46 @@ class ScopedActionCompleter {
DISALLOW_COPY_AND_ASSIGN(ScopedActionCompleter);
};
+// Simple wrapper for creating a slice of some container,
+// similar to string_view but for other containers.
+template <typename T>
+struct Range {
+ Range(T t1, T t2) : t1_(t1), t2_(t2) {}
+ constexpr auto begin() const noexcept { return t1_; }
+ constexpr auto end() const noexcept { return t2_; }
+ T t1_;
+ T t2_;
+};
+
+std::string HexEncode(const brillo::Blob& blob) noexcept;
+std::string HexEncode(const std::string_view blob) noexcept;
+
+template <size_t kSize>
+std::string HexEncode(const std::array<uint8_t, kSize> blob) noexcept {
+ return base::HexEncode(blob.data(), blob.size());
+}
+
+[[nodiscard]] std::string_view ToStringView(
+ const std::vector<unsigned char>& blob) noexcept;
+
+constexpr std::string_view ToStringView(
+ const std::vector<char>& blob) noexcept {
+ return std::string_view{blob.data(), blob.size()};
+}
+
+[[nodiscard]] std::string_view ToStringView(const void* data,
+ size_t size) noexcept;
+
} // namespace chromeos_update_engine
-#define TEST_AND_RETURN_FALSE_ERRNO(_x) \
- do { \
- bool _success = static_cast<bool>(_x); \
- if (!_success) { \
- std::string _msg = \
- chromeos_update_engine::utils::ErrnoNumberAsString(errno); \
- LOG(ERROR) << #_x " failed: " << _msg; \
- return false; \
- } \
+#define TEST_AND_RETURN_FALSE_ERRNO(_x) \
+ do { \
+ bool _success = static_cast<bool>(_x); \
+ if (!_success) { \
+ std::string _msg = android::base::ErrnoNumberAsString(errno); \
+ LOG(ERROR) << #_x " failed: " << _msg; \
+ return false; \
+ } \
} while (0)
#define TEST_AND_RETURN_FALSE(_x) \
@@ -487,15 +577,14 @@ class ScopedActionCompleter {
} \
} while (0)
-#define TEST_AND_RETURN_ERRNO(_x) \
- do { \
- bool _success = static_cast<bool>(_x); \
- if (!_success) { \
- std::string _msg = \
- chromeos_update_engine::utils::ErrnoNumberAsString(errno); \
- LOG(ERROR) << #_x " failed: " << _msg; \
- return; \
- } \
+#define TEST_AND_RETURN_ERRNO(_x) \
+ do { \
+ bool _success = static_cast<bool>(_x); \
+ if (!_success) { \
+ std::string _msg = android::base::ErrnoNumberAsString(errno); \
+ LOG(ERROR) << #_x " failed: " << _msg; \
+ return; \
+ } \
} while (0)
#define TEST_AND_RETURN(_x) \
@@ -517,4 +606,43 @@ class ScopedActionCompleter {
} \
} while (0)
+#define TEST_OP(_x, _y, op) \
+ do { \
+ const auto& x = _x; \
+ const auto& y = _y; \
+ if (!(x op y)) { \
+ LOG(ERROR) << #_x " " #op " " #_y << " failed: " << x << " " #op " " \
+ << y; \
+ return {}; \
+ } \
+ } while (0)
+
+#define TEST_EQ(_x, _y) TEST_OP(_x, _y, ==)
+#define TEST_NE(_x, _y) TEST_OP(_x, _y, !=)
+#define TEST_LE(_x, _y) TEST_OP(_x, _y, <=)
+#define TEST_GE(_x, _y) TEST_OP(_x, _y, >=)
+#define TEST_LT(_x, _y) TEST_OP(_x, _y, <)
+#define TEST_GT(_x, _y) TEST_OP(_x, _y, >)
+
+// Macro for running a block of code before function exits.
+// Example:
+// DEFER {
+// fclose(hc);
+// hc = nullptr;
+// };
+// It works by creating a new local variable struct holding the lambda, the
+// destructor of that struct will invoke the lambda.
+
+constexpr struct {
+ template <typename F>
+ constexpr auto operator<<(F&& f) const noexcept {
+ return android::base::make_scope_guard(std::forward<F>(f));
+ }
+} deferrer;
+
+#define TOKENPASTE(x, y) x##y
+#define DEFER \
+ auto TOKENPASTE(_deferred_lambda_call, __COUNTER__) = deferrer \
+ << [&]() mutable
+
#endif // UPDATE_ENGINE_COMMON_UTILS_H_
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index 20c6b849..739f2981 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -77,10 +77,6 @@ TEST(UtilsTest, ReadFileChunk) {
EXPECT_EQ(brillo::Blob(data.begin() + 10, data.begin() + 10 + 20), in_data);
}
-TEST(UtilsTest, ErrnoNumberAsStringTest) {
- EXPECT_EQ("No such file or directory", utils::ErrnoNumberAsString(ENOENT));
-}
-
TEST(UtilsTest, IsSymlinkTest) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/cros/boot_control_chromeos.cc b/cros/boot_control_chromeos.cc
deleted file mode 100644
index 17659ae7..00000000
--- a/cros/boot_control_chromeos.cc
+++ /dev/null
@@ -1,378 +0,0 @@
-//
-// Copyright (C) 2015 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/cros/boot_control_chromeos.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/files/file_path.h>
-#include <base/files/file_util.h>
-#include <base/strings/string_split.h>
-#include <base/strings/string_util.h>
-#include <chromeos/constants/imageloader.h>
-#include <rootdev/rootdev.h>
-
-extern "C" {
-#include <vboot/vboot_host.h>
-}
-
-#include "update_engine/common/boot_control.h"
-#include "update_engine/common/dynamic_partition_control_stub.h"
-#include "update_engine/common/subprocess.h"
-#include "update_engine/common/utils.h"
-
-using std::string;
-using std::vector;
-
-namespace {
-
-const char* kChromeOSPartitionNameKernel = "kernel";
-const char* kChromeOSPartitionNameRoot = "root";
-const char* kAndroidPartitionNameKernel = "boot";
-const char* kAndroidPartitionNameRoot = "system";
-
-const char kPartitionNamePrefixDlc[] = "dlc";
-const char kPartitionNameDlcA[] = "dlc_a";
-const char kPartitionNameDlcB[] = "dlc_b";
-const char kPartitionNameDlcImage[] = "dlc.img";
-
-// Returns the currently booted rootfs partition. "/dev/sda3", for example.
-string GetBootDevice() {
- char boot_path[PATH_MAX];
- // Resolve the boot device path fully, including dereferencing through
- // dm-verity.
- int ret = rootdev(boot_path, sizeof(boot_path), true, false);
- if (ret < 0) {
- LOG(ERROR) << "rootdev failed to find the root device";
- return "";
- }
- LOG_IF(WARNING, ret > 0) << "rootdev found a device name with no device node";
-
- // This local variable is used to construct the return string and is not
- // passed around after use.
- return boot_path;
-}
-
-// ExecCallback called when the execution of setgoodkernel finishes. Notifies
-// the caller of MarkBootSuccessfullAsync() by calling |callback| with the
-// result.
-void OnMarkBootSuccessfulDone(base::Callback<void(bool)> callback,
- int return_code,
- const string& output) {
- callback.Run(return_code == 0);
-}
-
-} // namespace
-
-namespace chromeos_update_engine {
-
-namespace boot_control {
-
-// Factory defined in boot_control.h.
-std::unique_ptr<BootControlInterface> CreateBootControl() {
- std::unique_ptr<BootControlChromeOS> boot_control_chromeos(
- new BootControlChromeOS());
- if (!boot_control_chromeos->Init()) {
- LOG(ERROR) << "Ignoring BootControlChromeOS failure. We won't run updates.";
- }
- return std::move(boot_control_chromeos);
-}
-
-} // namespace boot_control
-
-bool BootControlChromeOS::Init() {
- string boot_device = GetBootDevice();
- if (boot_device.empty())
- return false;
-
- int partition_num;
- if (!utils::SplitPartitionName(boot_device, &boot_disk_name_, &partition_num))
- return false;
-
- // All installed Chrome OS devices have two slots. We don't update removable
- // devices, so we will pretend we have only one slot in that case.
- if (IsRemovableDevice(boot_disk_name_)) {
- LOG(INFO)
- << "Booted from a removable device, pretending we have only one slot.";
- num_slots_ = 1;
- } else {
- // TODO(deymo): Look at the actual number of slots reported in the GPT.
- num_slots_ = 2;
- }
-
- // Search through the slots to see which slot has the partition_num we booted
- // from. This should map to one of the existing slots, otherwise something is
- // very wrong.
- current_slot_ = 0;
- while (current_slot_ < num_slots_ &&
- partition_num !=
- GetPartitionNumber(kChromeOSPartitionNameRoot, current_slot_)) {
- current_slot_++;
- }
- if (current_slot_ >= num_slots_) {
- LOG(ERROR) << "Couldn't find the slot number corresponding to the "
- << "partition " << boot_device
- << ", number of slots: " << num_slots_
- << ". This device is not updateable.";
- num_slots_ = 1;
- current_slot_ = BootControlInterface::kInvalidSlot;
- return false;
- }
-
- dynamic_partition_control_.reset(new DynamicPartitionControlStub());
-
- LOG(INFO) << "Booted from slot " << current_slot_ << " (slot "
- << SlotName(current_slot_) << ") of " << num_slots_
- << " slots present on disk " << boot_disk_name_;
- return true;
-}
-
-unsigned int BootControlChromeOS::GetNumSlots() const {
- return num_slots_;
-}
-
-BootControlInterface::Slot BootControlChromeOS::GetCurrentSlot() const {
- return current_slot_;
-}
-
-bool BootControlChromeOS::ParseDlcPartitionName(
- const std::string partition_name,
- std::string* dlc_id,
- std::string* dlc_package) const {
- CHECK_NE(dlc_id, nullptr);
- CHECK_NE(dlc_package, nullptr);
-
- vector<string> tokens = base::SplitString(
- partition_name, "/", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- if (tokens.size() != 3 || tokens[0] != kPartitionNamePrefixDlc) {
- LOG(ERROR) << "DLC partition name (" << partition_name
- << ") is not well formatted.";
- return false;
- }
- if (tokens[1].empty() || tokens[2].empty()) {
- LOG(ERROR) << " partition name does not contain valid DLC ID (" << tokens[1]
- << ") or package (" << tokens[2] << ")";
- return false;
- }
-
- *dlc_id = tokens[1];
- *dlc_package = tokens[2];
- return true;
-}
-
-bool BootControlChromeOS::GetPartitionDevice(const std::string& partition_name,
- BootControlInterface::Slot slot,
- bool not_in_payload,
- std::string* device,
- bool* is_dynamic) const {
- // Partition name prefixed with |kPartitionNamePrefixDlc| is a DLC module.
- if (base::StartsWith(partition_name,
- kPartitionNamePrefixDlc,
- base::CompareCase::SENSITIVE)) {
- string dlc_id, dlc_package;
- if (!ParseDlcPartitionName(partition_name, &dlc_id, &dlc_package))
- return false;
-
- *device = base::FilePath(imageloader::kDlcImageRootpath)
- .Append(dlc_id)
- .Append(dlc_package)
- .Append(slot == 0 ? kPartitionNameDlcA : kPartitionNameDlcB)
- .Append(kPartitionNameDlcImage)
- .value();
- return true;
- }
- int partition_num = GetPartitionNumber(partition_name, slot);
- if (partition_num < 0)
- return false;
-
- string part_device = utils::MakePartitionName(boot_disk_name_, partition_num);
- if (part_device.empty())
- return false;
-
- *device = part_device;
- if (is_dynamic) {
- *is_dynamic = false;
- }
- return true;
-}
-
-bool BootControlChromeOS::GetPartitionDevice(const string& partition_name,
- BootControlInterface::Slot slot,
- string* device) const {
- return GetPartitionDevice(partition_name, slot, false, device, nullptr);
-}
-
-bool BootControlChromeOS::IsSlotBootable(Slot slot) const {
- int partition_num = GetPartitionNumber(kChromeOSPartitionNameKernel, slot);
- if (partition_num < 0)
- return false;
-
- CgptAddParams params;
- memset(&params, '\0', sizeof(params));
- params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
- params.partition = partition_num;
-
- int retval = CgptGetPartitionDetails(&params);
- if (retval != CGPT_OK)
- return false;
-
- return params.successful || params.tries > 0;
-}
-
-bool BootControlChromeOS::MarkSlotUnbootable(Slot slot) {
- LOG(INFO) << "Marking slot " << SlotName(slot) << " unbootable";
-
- if (slot == current_slot_) {
- LOG(ERROR) << "Refusing to mark current slot as unbootable.";
- return false;
- }
-
- int partition_num = GetPartitionNumber(kChromeOSPartitionNameKernel, slot);
- if (partition_num < 0)
- return false;
-
- CgptAddParams params;
- memset(&params, 0, sizeof(params));
-
- params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
- params.partition = partition_num;
-
- params.successful = false;
- params.set_successful = true;
-
- params.tries = 0;
- params.set_tries = true;
-
- int retval = CgptSetAttributes(&params);
- if (retval != CGPT_OK) {
- LOG(ERROR) << "Marking kernel unbootable failed.";
- return false;
- }
-
- return true;
-}
-
-bool BootControlChromeOS::SetActiveBootSlot(Slot slot) {
- LOG(INFO) << "Marking slot " << SlotName(slot) << " active.";
-
- int partition_num = GetPartitionNumber(kChromeOSPartitionNameKernel, slot);
- if (partition_num < 0)
- return false;
-
- CgptPrioritizeParams prio_params;
- memset(&prio_params, 0, sizeof(prio_params));
-
- prio_params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
- prio_params.set_partition = partition_num;
-
- prio_params.max_priority = 0;
-
- int retval = CgptPrioritize(&prio_params);
- if (retval != CGPT_OK) {
- LOG(ERROR) << "Unable to set highest priority for slot " << SlotName(slot)
- << " (partition " << partition_num << ").";
- return false;
- }
-
- CgptAddParams add_params;
- memset(&add_params, 0, sizeof(add_params));
-
- add_params.drive_name = const_cast<char*>(boot_disk_name_.c_str());
- add_params.partition = partition_num;
-
- add_params.tries = 6;
- add_params.set_tries = true;
-
- retval = CgptSetAttributes(&add_params);
- if (retval != CGPT_OK) {
- LOG(ERROR) << "Unable to set NumTriesLeft to " << add_params.tries
- << " for slot " << SlotName(slot) << " (partition "
- << partition_num << ").";
- return false;
- }
-
- return true;
-}
-
-bool BootControlChromeOS::MarkBootSuccessfulAsync(
- base::Callback<void(bool)> callback) {
- return Subprocess::Get().Exec(
- {"/usr/sbin/chromeos-setgoodkernel"},
- base::Bind(&OnMarkBootSuccessfulDone, callback)) != 0;
-}
-
-// static
-string BootControlChromeOS::SysfsBlockDevice(const string& device) {
- base::FilePath device_path(device);
- if (device_path.DirName().value() != "/dev") {
- return "";
- }
- return base::FilePath("/sys/block").Append(device_path.BaseName()).value();
-}
-
-// static
-bool BootControlChromeOS::IsRemovableDevice(const string& device) {
- string sysfs_block = SysfsBlockDevice(device);
- string removable;
- if (sysfs_block.empty() ||
- !base::ReadFileToString(base::FilePath(sysfs_block).Append("removable"),
- &removable)) {
- return false;
- }
- base::TrimWhitespaceASCII(removable, base::TRIM_ALL, &removable);
- return removable == "1";
-}
-
-int BootControlChromeOS::GetPartitionNumber(
- const string partition_name, BootControlInterface::Slot slot) const {
- if (slot >= num_slots_) {
- LOG(ERROR) << "Invalid slot number: " << slot << ", we only have "
- << num_slots_ << " slot(s)";
- return -1;
- }
-
- // In Chrome OS, the partition numbers are hard-coded:
- // KERNEL-A=2, ROOT-A=3, KERNEL-B=4, ROOT-B=4, ...
- // To help compatibility between different we accept both lowercase and
- // uppercase names in the ChromeOS or Brillo standard names.
- // See http://www.chromium.org/chromium-os/chromiumos-design-docs/disk-format
- string partition_lower = base::ToLowerASCII(partition_name);
- int base_part_num = 2 + 2 * slot;
- if (partition_lower == kChromeOSPartitionNameKernel ||
- partition_lower == kAndroidPartitionNameKernel)
- return base_part_num + 0;
- if (partition_lower == kChromeOSPartitionNameRoot ||
- partition_lower == kAndroidPartitionNameRoot)
- return base_part_num + 1;
- LOG(ERROR) << "Unknown Chrome OS partition name \"" << partition_name << "\"";
- return -1;
-}
-
-bool BootControlChromeOS::IsSlotMarkedSuccessful(Slot slot) const {
- LOG(ERROR) << __func__ << " not supported.";
- return false;
-}
-
-DynamicPartitionControlInterface*
-BootControlChromeOS::GetDynamicPartitionControl() {
- return dynamic_partition_control_.get();
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/boot_control_chromeos.h b/cros/boot_control_chromeos.h
deleted file mode 100644
index 0dff2c02..00000000
--- a/cros/boot_control_chromeos.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//
-// Copyright (C) 2015 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_CROS_BOOT_CONTROL_CHROMEOS_H_
-#define UPDATE_ENGINE_CROS_BOOT_CONTROL_CHROMEOS_H_
-
-#include <memory>
-#include <string>
-
-#include <base/callback.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/dynamic_partition_control_interface.h"
-
-namespace chromeos_update_engine {
-
-// The Chrome OS implementation of the BootControlInterface. This interface
-// assumes the partition names and numbers used in Chrome OS devices.
-class BootControlChromeOS : public BootControlInterface {
- public:
- BootControlChromeOS() = default;
- ~BootControlChromeOS() = default;
-
- // Initialize the BootControl instance loading the constant values. Returns
- // whether the operation succeeded. In case of failure, normally meaning
- // some critical failure such as we couldn't determine the slot that we
- // booted from, the implementation will pretend that there's only one slot and
- // therefore A/B updates are disabled.
- bool Init();
-
- // BootControlInterface overrides.
- unsigned int GetNumSlots() const override;
- BootControlInterface::Slot GetCurrentSlot() const override;
- bool GetPartitionDevice(const std::string& partition_name,
- BootControlInterface::Slot slot,
- bool not_in_payload,
- std::string* device,
- bool* is_dynamic) const override;
- bool GetPartitionDevice(const std::string& partition_name,
- BootControlInterface::Slot slot,
- std::string* device) const override;
- bool IsSlotBootable(BootControlInterface::Slot slot) const override;
- bool MarkSlotUnbootable(BootControlInterface::Slot slot) override;
- bool SetActiveBootSlot(BootControlInterface::Slot slot) override;
- bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override;
- bool IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const override;
- DynamicPartitionControlInterface* GetDynamicPartitionControl() override;
-
- private:
- friend class BootControlChromeOSTest;
- FRIEND_TEST(BootControlChromeOSTest, SysfsBlockDeviceTest);
- FRIEND_TEST(BootControlChromeOSTest, GetPartitionNumberTest);
- FRIEND_TEST(BootControlChromeOSTest, ParseDlcPartitionNameTest);
-
- // Returns the sysfs block device for a root block device. For example,
- // SysfsBlockDevice("/dev/sda") returns "/sys/block/sda". Returns an empty
- // string if the input device is not of the "/dev/xyz" form.
- static std::string SysfsBlockDevice(const std::string& device);
-
- // Returns true if the root |device| (e.g., "/dev/sdb") is known to be
- // removable, false otherwise.
- static bool IsRemovableDevice(const std::string& device);
-
- // Return the hard-coded partition number used in Chrome OS for the passed
- // |partition_name| and |slot|. In case of invalid data, returns -1.
- int GetPartitionNumber(const std::string partition_name,
- BootControlInterface::Slot slot) const;
-
- // Extracts DLC module ID and package ID from partition name. The structure of
- // the partition name is dlc/<dlc-id>/<dlc-package>. For example:
- // dlc/fake-dlc/fake-package
- bool ParseDlcPartitionName(const std::string partition_name,
- std::string* dlc_id,
- std::string* dlc_package) const;
-
- // Cached values for GetNumSlots() and GetCurrentSlot().
- BootControlInterface::Slot num_slots_{1};
- BootControlInterface::Slot current_slot_{BootControlInterface::kInvalidSlot};
-
- // The block device of the disk we booted from, without the partition number.
- std::string boot_disk_name_;
-
- std::unique_ptr<DynamicPartitionControlInterface> dynamic_partition_control_;
-
- DISALLOW_COPY_AND_ASSIGN(BootControlChromeOS);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_BOOT_CONTROL_CHROMEOS_H_
diff --git a/cros/boot_control_chromeos_unittest.cc b/cros/boot_control_chromeos_unittest.cc
deleted file mode 100644
index fc1dd1e5..00000000
--- a/cros/boot_control_chromeos_unittest.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-// Copyright (C) 2015 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/cros/boot_control_chromeos.h"
-
-#include <gtest/gtest.h>
-
-using std::string;
-
-namespace chromeos_update_engine {
-
-class BootControlChromeOSTest : public ::testing::Test {
- protected:
- void SetUp() override {
- // We don't run Init() for bootctl_, we set its internal values instead.
- bootctl_.num_slots_ = 2;
- bootctl_.current_slot_ = 0;
- bootctl_.boot_disk_name_ = "/dev/null";
- }
-
- BootControlChromeOS bootctl_; // BootControlChromeOS under test.
-};
-
-TEST_F(BootControlChromeOSTest, SysfsBlockDeviceTest) {
- EXPECT_EQ("/sys/block/sda", bootctl_.SysfsBlockDevice("/dev/sda"));
- EXPECT_EQ("", bootctl_.SysfsBlockDevice("/foo/sda"));
- EXPECT_EQ("", bootctl_.SysfsBlockDevice("/dev/foo/bar"));
- EXPECT_EQ("", bootctl_.SysfsBlockDevice("/"));
- EXPECT_EQ("", bootctl_.SysfsBlockDevice("./"));
- EXPECT_EQ("", bootctl_.SysfsBlockDevice(""));
-}
-
-TEST_F(BootControlChromeOSTest, GetPartitionNumberTest) {
- // The partition name should not be case-sensitive.
- EXPECT_EQ(2, bootctl_.GetPartitionNumber("kernel", 0));
- EXPECT_EQ(2, bootctl_.GetPartitionNumber("boot", 0));
- EXPECT_EQ(2, bootctl_.GetPartitionNumber("KERNEL", 0));
- EXPECT_EQ(2, bootctl_.GetPartitionNumber("BOOT", 0));
-
- EXPECT_EQ(3, bootctl_.GetPartitionNumber("ROOT", 0));
- EXPECT_EQ(3, bootctl_.GetPartitionNumber("system", 0));
-
- EXPECT_EQ(3, bootctl_.GetPartitionNumber("ROOT", 0));
- EXPECT_EQ(3, bootctl_.GetPartitionNumber("system", 0));
-
- // Slot B.
- EXPECT_EQ(4, bootctl_.GetPartitionNumber("KERNEL", 1));
- EXPECT_EQ(5, bootctl_.GetPartitionNumber("ROOT", 1));
-
- // Slot C doesn't exists.
- EXPECT_EQ(-1, bootctl_.GetPartitionNumber("KERNEL", 2));
- EXPECT_EQ(-1, bootctl_.GetPartitionNumber("ROOT", 2));
-
- // Non A/B partitions are ignored.
- EXPECT_EQ(-1, bootctl_.GetPartitionNumber("OEM", 0));
- EXPECT_EQ(-1, bootctl_.GetPartitionNumber("A little panda", 0));
-}
-
-TEST_F(BootControlChromeOSTest, ParseDlcPartitionNameTest) {
- string id, package;
-
- EXPECT_TRUE(bootctl_.ParseDlcPartitionName("dlc/id/package", &id, &package));
- EXPECT_EQ(id, "id");
- EXPECT_EQ(package, "package");
-
- EXPECT_FALSE(
- bootctl_.ParseDlcPartitionName("dlc-foo/id/package", &id, &package));
- EXPECT_FALSE(
- bootctl_.ParseDlcPartitionName("dlc-foo/id/package/", &id, &package));
- EXPECT_FALSE(bootctl_.ParseDlcPartitionName("dlc/id", &id, &package));
- EXPECT_FALSE(bootctl_.ParseDlcPartitionName("dlc/id/", &id, &package));
- EXPECT_FALSE(bootctl_.ParseDlcPartitionName("dlc//package", &id, &package));
- EXPECT_FALSE(bootctl_.ParseDlcPartitionName("dlc", &id, &package));
- EXPECT_FALSE(bootctl_.ParseDlcPartitionName("foo", &id, &package));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/chrome_browser_proxy_resolver.cc b/cros/chrome_browser_proxy_resolver.cc
deleted file mode 100644
index 3ea8a9b1..00000000
--- a/cros/chrome_browser_proxy_resolver.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-//
-// Copyright (C) 2011 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/cros/chrome_browser_proxy_resolver.h"
-
-#include <utility>
-
-#include <base/bind.h>
-#include <base/memory/ptr_util.h>
-#include <base/strings/string_util.h>
-#include <brillo/http/http_proxy.h>
-
-#include "update_engine/cros/dbus_connection.h"
-
-namespace chromeos_update_engine {
-
-ChromeBrowserProxyResolver::ChromeBrowserProxyResolver()
- : next_request_id_(kProxyRequestIdNull + 1), weak_ptr_factory_(this) {}
-
-ChromeBrowserProxyResolver::~ChromeBrowserProxyResolver() = default;
-
-ProxyRequestId ChromeBrowserProxyResolver::GetProxiesForUrl(
- const std::string& url, const ProxiesResolvedFn& callback) {
- const ProxyRequestId id = next_request_id_++;
- brillo::http::GetChromeProxyServersAsync(
- DBusConnection::Get()->GetDBus(),
- url,
- base::Bind(&ChromeBrowserProxyResolver::OnGetChromeProxyServers,
- weak_ptr_factory_.GetWeakPtr(),
- id));
- pending_callbacks_[id] = callback;
- return id;
-}
-
-bool ChromeBrowserProxyResolver::CancelProxyRequest(ProxyRequestId request) {
- return pending_callbacks_.erase(request) != 0;
-}
-
-void ChromeBrowserProxyResolver::OnGetChromeProxyServers(
- ProxyRequestId request_id,
- bool success,
- const std::vector<std::string>& proxies) {
- // If |success| is false, |proxies| will still hold the direct proxy option
- // which is what we do in our error case.
- auto it = pending_callbacks_.find(request_id);
- if (it == pending_callbacks_.end())
- return;
-
- ProxiesResolvedFn callback = it->second;
- pending_callbacks_.erase(it);
- callback.Run(std::deque<std::string>(proxies.begin(), proxies.end()));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/chrome_browser_proxy_resolver.h b/cros/chrome_browser_proxy_resolver.h
deleted file mode 100644
index 76848ef3..00000000
--- a/cros/chrome_browser_proxy_resolver.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright (C) 2011 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_CROS_CHROME_BROWSER_PROXY_RESOLVER_H_
-#define UPDATE_ENGINE_CROS_CHROME_BROWSER_PROXY_RESOLVER_H_
-
-#include <deque>
-#include <map>
-#include <string>
-#include <vector>
-
-#include <base/memory/weak_ptr.h>
-
-#include "update_engine/common/proxy_resolver.h"
-
-namespace chromeos_update_engine {
-
-class ChromeBrowserProxyResolver : public ProxyResolver {
- public:
- ChromeBrowserProxyResolver();
- ~ChromeBrowserProxyResolver() override;
-
- // ProxyResolver:
- ProxyRequestId GetProxiesForUrl(const std::string& url,
- const ProxiesResolvedFn& callback) override;
- bool CancelProxyRequest(ProxyRequestId request) override;
-
- private:
- // Callback for calls made by GetProxiesForUrl().
- void OnGetChromeProxyServers(ProxyRequestId request_id,
- bool success,
- const std::vector<std::string>& proxies);
-
- // Finds the callback identified by |request_id| in |pending_callbacks_|,
- // passes |proxies| to it, and deletes it. Does nothing if the request has
- // been cancelled.
- void RunCallback(ProxyRequestId request_id,
- const std::deque<std::string>& proxies);
-
- // Next ID to return from GetProxiesForUrl().
- ProxyRequestId next_request_id_;
-
- // Callbacks that were passed to GetProxiesForUrl() but haven't yet been run.
- std::map<ProxyRequestId, ProxiesResolvedFn> pending_callbacks_;
-
- base::WeakPtrFactory<ChromeBrowserProxyResolver> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ChromeBrowserProxyResolver);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_CHROME_BROWSER_PROXY_RESOLVER_H_
diff --git a/cros/common_service.cc b/cros/common_service.cc
deleted file mode 100644
index e5ee828c..00000000
--- a/cros/common_service.cc
+++ /dev/null
@@ -1,411 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/common_service.h"
-
-#include <string>
-
-#include <base/bind.h>
-#include <base/location.h>
-#include <base/logging.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/strings/string_utils.h>
-#include <policy/device_policy.h>
-
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/connection_manager_interface.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/omaha_utils.h"
-#include "update_engine/cros/p2p_manager.h"
-#include "update_engine/cros/payload_state_interface.h"
-#include "update_engine/cros/update_attempter.h"
-
-using base::StringPrintf;
-using brillo::ErrorPtr;
-using brillo::string_utils::ToString;
-using std::string;
-using std::vector;
-using update_engine::UpdateAttemptFlags;
-using update_engine::UpdateEngineStatus;
-
-namespace chromeos_update_engine {
-
-namespace {
-// Log and set the error on the passed ErrorPtr.
-void LogAndSetError(ErrorPtr* error,
- const base::Location& location,
- const string& reason) {
- brillo::Error::AddTo(error,
- location,
- UpdateEngineService::kErrorDomain,
- UpdateEngineService::kErrorFailed,
- reason);
- LOG(ERROR) << "Sending Update Engine Failure: " << location.ToString() << ": "
- << reason;
-}
-} // namespace
-
-const char* const UpdateEngineService::kErrorDomain = "update_engine";
-const char* const UpdateEngineService::kErrorFailed =
- "org.chromium.UpdateEngine.Error.Failed";
-
-UpdateEngineService::UpdateEngineService() = default;
-
-// org::chromium::UpdateEngineInterfaceInterface methods implementation.
-
-bool UpdateEngineService::SetUpdateAttemptFlags(ErrorPtr* /* error */,
- int32_t in_flags_as_int) {
- auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int);
- LOG(INFO) << "Setting Update Attempt Flags: "
- << "flags=0x" << std::hex << flags << " "
- << "RestrictDownload="
- << ((flags & UpdateAttemptFlags::kFlagRestrictDownload) ? "yes"
- : "no");
- SystemState::Get()->update_attempter()->SetUpdateAttemptFlags(flags);
- return true;
-}
-
-bool UpdateEngineService::AttemptUpdate(ErrorPtr* /* error */,
- const string& in_app_version,
- const string& in_omaha_url,
- int32_t in_flags_as_int,
- bool* out_result) {
- auto flags = static_cast<UpdateAttemptFlags>(in_flags_as_int);
- bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive);
- bool restrict_downloads = (flags & UpdateAttemptFlags::kFlagRestrictDownload);
-
- LOG(INFO) << "Attempt update: app_version=\"" << in_app_version << "\" "
- << "omaha_url=\"" << in_omaha_url << "\" "
- << "flags=0x" << std::hex << flags << " "
- << "interactive=" << (interactive ? "yes " : "no ")
- << "RestrictDownload=" << (restrict_downloads ? "yes " : "no ");
-
- *out_result = SystemState::Get()->update_attempter()->CheckForUpdate(
- in_app_version, in_omaha_url, flags);
- return true;
-}
-
-bool UpdateEngineService::AttemptInstall(brillo::ErrorPtr* error,
- const string& omaha_url,
- const vector<string>& dlc_ids) {
- if (!SystemState::Get()->update_attempter()->CheckForInstall(dlc_ids,
- omaha_url)) {
- // TODO(xiaochu): support more detailed error messages.
- LogAndSetError(error, FROM_HERE, "Could not schedule install operation.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::AttemptRollback(ErrorPtr* error, bool in_powerwash) {
- LOG(INFO) << "Attempting rollback to non-active partitions.";
-
- if (!SystemState::Get()->update_attempter()->Rollback(in_powerwash)) {
- // TODO(dgarrett): Give a more specific error code/reason.
- LogAndSetError(error, FROM_HERE, "Rollback attempt failed.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::CanRollback(ErrorPtr* /* error */,
- bool* out_can_rollback) {
- bool can_rollback = SystemState::Get()->update_attempter()->CanRollback();
- LOG(INFO) << "Checking to see if we can rollback . Result: " << can_rollback;
- *out_can_rollback = can_rollback;
- return true;
-}
-
-bool UpdateEngineService::ResetStatus(ErrorPtr* error) {
- if (!SystemState::Get()->update_attempter()->ResetStatus()) {
- // TODO(dgarrett): Give a more specific error code/reason.
- LogAndSetError(error, FROM_HERE, "ResetStatus failed.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::SetDlcActiveValue(brillo::ErrorPtr* error,
- bool is_active,
- const string& dlc_id) {
- if (!SystemState::Get()->update_attempter()->SetDlcActiveValue(is_active,
- dlc_id)) {
- LogAndSetError(error, FROM_HERE, "SetDlcActiveValue failed.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::GetStatus(ErrorPtr* error,
- UpdateEngineStatus* out_status) {
- if (!SystemState::Get()->update_attempter()->GetStatus(out_status)) {
- LogAndSetError(error, FROM_HERE, "GetStatus failed.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::RebootIfNeeded(ErrorPtr* error) {
- if (!SystemState::Get()->update_attempter()->RebootIfNeeded()) {
- // TODO(dgarrett): Give a more specific error code/reason.
- LogAndSetError(error, FROM_HERE, "Reboot not needed, or attempt failed.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::SetChannel(ErrorPtr* error,
- const string& in_target_channel,
- bool in_is_powerwash_allowed) {
- const policy::DevicePolicy* device_policy =
- SystemState::Get()->device_policy();
-
- // The device_policy is loaded in a lazy way before an update check. Load it
- // now from the libbrillo cache if it wasn't already loaded.
- if (!device_policy) {
- UpdateAttempter* update_attempter = SystemState::Get()->update_attempter();
- if (update_attempter) {
- update_attempter->RefreshDevicePolicy();
- device_policy = SystemState::Get()->device_policy();
- }
- }
-
- bool delegated = false;
- if (device_policy && device_policy->GetReleaseChannelDelegated(&delegated) &&
- !delegated) {
- LogAndSetError(error,
- FROM_HERE,
- "Cannot set target channel explicitly when channel "
- "policy/settings is not delegated");
- return false;
- }
-
- LOG(INFO) << "Setting destination channel to: " << in_target_channel;
- string error_message;
- if (!SystemState::Get()->request_params()->SetTargetChannel(
- in_target_channel, in_is_powerwash_allowed, &error_message)) {
- LogAndSetError(error, FROM_HERE, error_message);
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::GetChannel(ErrorPtr* /* error */,
- bool in_get_current_channel,
- string* out_channel) {
- OmahaRequestParams* rp = SystemState::Get()->request_params();
- *out_channel =
- (in_get_current_channel ? rp->current_channel() : rp->target_channel());
- return true;
-}
-
-bool UpdateEngineService::SetCohortHint(ErrorPtr* error,
- const string& in_cohort_hint) {
- // It is ok to override the cohort hint with an invalid value since it is
- // stored in stateful partition. The code reading it should sanitize it
- // anyway.
- if (!SystemState::Get()->prefs()->SetString(kPrefsOmahaCohortHint,
- in_cohort_hint)) {
- LogAndSetError(
- error,
- FROM_HERE,
- StringPrintf("Error setting the cohort hint value to \"%s\".",
- in_cohort_hint.c_str()));
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::GetCohortHint(ErrorPtr* error,
- string* out_cohort_hint) {
- const auto* prefs = SystemState::Get()->prefs();
- *out_cohort_hint = "";
- if (prefs->Exists(kPrefsOmahaCohortHint) &&
- !prefs->GetString(kPrefsOmahaCohortHint, out_cohort_hint)) {
- LogAndSetError(error, FROM_HERE, "Error getting the cohort hint.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::SetP2PUpdatePermission(ErrorPtr* error,
- bool in_enabled) {
- if (!SystemState::Get()->prefs()->SetBoolean(kPrefsP2PEnabled, in_enabled)) {
- LogAndSetError(
- error,
- FROM_HERE,
- StringPrintf("Error setting the update via p2p permission to %s.",
- ToString(in_enabled).c_str()));
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::GetP2PUpdatePermission(ErrorPtr* error,
- bool* out_enabled) {
- const auto* prefs = SystemState::Get()->prefs();
- bool p2p_pref = false; // Default if no setting is present.
- if (prefs->Exists(kPrefsP2PEnabled) &&
- !prefs->GetBoolean(kPrefsP2PEnabled, &p2p_pref)) {
- LogAndSetError(error, FROM_HERE, "Error getting the P2PEnabled setting.");
- return false;
- }
-
- *out_enabled = p2p_pref;
- return true;
-}
-
-bool UpdateEngineService::SetUpdateOverCellularPermission(ErrorPtr* error,
- bool in_allowed) {
- ConnectionManagerInterface* connection_manager =
- SystemState::Get()->connection_manager();
-
- // Check if this setting is allowed by the device policy.
- if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
- LogAndSetError(error,
- FROM_HERE,
- "Ignoring the update over cellular setting since there's "
- "a device policy enforcing this setting.");
- return false;
- }
-
- // If the policy wasn't loaded yet, then it is still OK to change the local
- // setting because the policy will be checked again during the update check.
- if (!SystemState::Get()->prefs()->SetBoolean(
- kPrefsUpdateOverCellularPermission, in_allowed)) {
- LogAndSetError(error,
- FROM_HERE,
- string("Error setting the update over cellular to ") +
- (in_allowed ? "true" : "false"));
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::SetUpdateOverCellularTarget(
- brillo::ErrorPtr* error,
- const std::string& target_version,
- int64_t target_size) {
- ConnectionManagerInterface* connection_manager =
- SystemState::Get()->connection_manager();
-
- // Check if this setting is allowed by the device policy.
- if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
- LogAndSetError(error,
- FROM_HERE,
- "Ignoring the update over cellular setting since there's "
- "a device policy enforcing this setting.");
- return false;
- }
-
- // If the policy wasn't loaded yet, then it is still OK to change the local
- // setting because the policy will be checked again during the update check.
-
- auto* prefs = SystemState::Get()->prefs();
- if (!prefs->SetString(kPrefsUpdateOverCellularTargetVersion,
- target_version) ||
- !prefs->SetInt64(kPrefsUpdateOverCellularTargetSize, target_size)) {
- LogAndSetError(
- error, FROM_HERE, "Error setting the target for update over cellular.");
- return false;
- }
- return true;
-}
-
-bool UpdateEngineService::GetUpdateOverCellularPermission(ErrorPtr* error,
- bool* out_allowed) {
- ConnectionManagerInterface* connection_manager =
- SystemState::Get()->connection_manager();
-
- if (connection_manager->IsAllowedConnectionTypesForUpdateSet()) {
- // We have device policy, so ignore the user preferences.
- *out_allowed = connection_manager->IsUpdateAllowedOver(
- ConnectionType::kCellular, ConnectionTethering::kUnknown);
- } else {
- const auto* prefs = SystemState::Get()->prefs();
- if (!prefs->Exists(kPrefsUpdateOverCellularPermission)) {
- // Update is not allowed as user preference is not set or not available.
- *out_allowed = false;
- return true;
- }
-
- bool is_allowed;
-
- if (!prefs->GetBoolean(kPrefsUpdateOverCellularPermission, &is_allowed)) {
- LogAndSetError(error,
- FROM_HERE,
- "Error getting the update over cellular preference.");
- return false;
- }
- *out_allowed = is_allowed;
- }
- return true;
-}
-
-bool UpdateEngineService::GetDurationSinceUpdate(ErrorPtr* error,
- int64_t* out_usec_wallclock) {
- base::Time time;
- if (!SystemState::Get()->update_attempter()->GetBootTimeAtUpdate(&time)) {
- LogAndSetError(error, FROM_HERE, "No pending update.");
- return false;
- }
-
- const auto* clock = SystemState::Get()->clock();
- *out_usec_wallclock = (clock->GetBootTime() - time).InMicroseconds();
- return true;
-}
-
-bool UpdateEngineService::GetPrevVersion(ErrorPtr* /* error */,
- string* out_prev_version) {
- *out_prev_version = SystemState::Get()->update_attempter()->GetPrevVersion();
- return true;
-}
-
-bool UpdateEngineService::GetRollbackPartition(
- ErrorPtr* /* error */, string* out_rollback_partition_name) {
- BootControlInterface::Slot rollback_slot =
- SystemState::Get()->update_attempter()->GetRollbackSlot();
-
- if (rollback_slot == BootControlInterface::kInvalidSlot) {
- out_rollback_partition_name->clear();
- return true;
- }
-
- string name;
- if (!SystemState::Get()->boot_control()->GetPartitionDevice(
- "KERNEL", rollback_slot, &name)) {
- LOG(ERROR) << "Invalid rollback device";
- return false;
- }
-
- LOG(INFO) << "Getting rollback partition name. Result: " << name;
- *out_rollback_partition_name = name;
- return true;
-}
-
-bool UpdateEngineService::GetLastAttemptError(ErrorPtr* /* error */,
- int32_t* out_last_attempt_error) {
- ErrorCode error_code =
- SystemState::Get()->update_attempter()->GetAttemptErrorCode();
- *out_last_attempt_error = static_cast<int>(error_code);
- return true;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/common_service.h b/cros/common_service.h
deleted file mode 100644
index 2c176c55..00000000
--- a/cros/common_service.h
+++ /dev/null
@@ -1,166 +0,0 @@
-//
-// Copyright (C) 2016 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_CROS_SERVICE_H_
-#define UPDATE_ENGINE_CROS_SERVICE_H_
-
-#include <inttypes.h>
-
-#include <string>
-#include <vector>
-
-#include <base/memory/ref_counted.h>
-#include <brillo/errors/error.h>
-
-#include "update_engine/client_library/include/update_engine/update_status.h"
-
-namespace chromeos_update_engine {
-
-class UpdateEngineService {
- public:
- // Error domain for all the service errors.
- static const char* const kErrorDomain;
-
- // Generic service error.
- static const char* const kErrorFailed;
-
- UpdateEngineService();
- virtual ~UpdateEngineService() = default;
-
- // Set flags that influence how updates and checks are performed. These
- // influence all future checks and updates until changed or the device
- // reboots. The |in_flags_as_int| values are a union of values from
- // |UpdateAttemptFlags|
- bool SetUpdateAttemptFlags(brillo::ErrorPtr* error, int32_t in_flags_as_int);
-
- bool AttemptUpdate(brillo::ErrorPtr* error,
- const std::string& in_app_version,
- const std::string& in_omaha_url,
- int32_t in_flags_as_int,
- bool* out_result);
-
- // Attempts a DLC module install operation.
- // |omaha_url|: the URL to query for update.
- // |dlc_ids|: a list of DLC module IDs.
- bool AttemptInstall(brillo::ErrorPtr* error,
- const std::string& omaha_url,
- const std::vector<std::string>& dlc_ids);
-
- bool AttemptRollback(brillo::ErrorPtr* error, bool in_powerwash);
-
- // Checks if the system rollback is available by verifying if the secondary
- // system partition is valid and bootable.
- bool CanRollback(brillo::ErrorPtr* error, bool* out_can_rollback);
-
- // Resets the status of the update_engine to idle, ignoring any applied
- // update. This is used for development only.
- bool ResetStatus(brillo::ErrorPtr* error);
-
- // Sets the DLC as active or inactive. When set to active, the ping metadata
- // for the DLC is updated accordingly. When set to inactive, the metadata
- // for the DLC is deleted.
- bool SetDlcActiveValue(brillo::ErrorPtr* error,
- bool is_active,
- const std::string& dlc_id);
-
- // Returns the current status of the Update Engine. If an update is in
- // progress, the number of operations, size to download and overall progress
- // is reported.
- bool GetStatus(brillo::ErrorPtr* error,
- update_engine::UpdateEngineStatus* out_status);
-
- // Reboots the device if an update is applied and a reboot is required.
- bool RebootIfNeeded(brillo::ErrorPtr* error);
-
- // Changes the current channel of the device to the target channel. If the
- // target channel is a less stable channel than the current channel, then the
- // channel change happens immediately (at the next update check). If the
- // target channel is a more stable channel, then if is_powerwash_allowed is
- // set to true, then also the change happens immediately but with a powerwash
- // if required. Otherwise, the change takes effect eventually (when the
- // version on the target channel goes above the version number of what the
- // device currently has).
- bool SetChannel(brillo::ErrorPtr* error,
- const std::string& in_target_channel,
- bool in_is_powerwash_allowed);
-
- // If get_current_channel is set to true, populates |channel| with the name of
- // the channel that the device is currently on. Otherwise, it populates it
- // with the name of the channel the device is supposed to be (in case of a
- // pending channel change).
- bool GetChannel(brillo::ErrorPtr* error,
- bool in_get_current_channel,
- std::string* out_channel);
-
- // Sets the current "cohort hint" value to |in_cohort_hint|. The cohort hint
- // is sent back to Omaha on every request and can be used as a hint of what
- // cohort should we be put on.
- bool SetCohortHint(brillo::ErrorPtr* error,
- const std::string& in_cohort_hint);
-
- // Return the current cohort hint. This value can be set with SetCohortHint()
- // and can also be updated from Omaha on every update check request.
- bool GetCohortHint(brillo::ErrorPtr* error, std::string* out_cohort_hint);
-
- // Enables or disables the sharing and consuming updates over P2P feature
- // according to the |enabled| argument passed.
- bool SetP2PUpdatePermission(brillo::ErrorPtr* error, bool in_enabled);
-
- // Returns the current value for the P2P enabled setting. This involves both
- // sharing and consuming updates over P2P.
- bool GetP2PUpdatePermission(brillo::ErrorPtr* error, bool* out_enabled);
-
- // If there's no device policy installed, sets the update over cellular
- // networks permission to the |allowed| value. Otherwise, this method returns
- // with an error since this setting is overridden by the applied policy.
- bool SetUpdateOverCellularPermission(brillo::ErrorPtr* error,
- bool in_allowed);
-
- // If there's no device policy installed, sets the update over cellular
- // target. Otherwise, this method returns with an error.
- bool SetUpdateOverCellularTarget(brillo::ErrorPtr* error,
- const std::string& target_version,
- int64_t target_size);
-
- // Returns the current value of the update over cellular network setting,
- // either forced by the device policy if the device is enrolled or the current
- // user preference otherwise.
- bool GetUpdateOverCellularPermission(brillo::ErrorPtr* error,
- bool* out_allowed);
-
- // Returns the duration since the last successful update, as the
- // duration on the wallclock. Returns an error if the device has not
- // updated.
- bool GetDurationSinceUpdate(brillo::ErrorPtr* error,
- int64_t* out_usec_wallclock);
-
- // Returns the version string of OS that was used before the last reboot
- // into an updated version. This is available only when rebooting into an
- // update from previous version, otherwise an empty string is returned.
- bool GetPrevVersion(brillo::ErrorPtr* error, std::string* out_prev_version);
-
- // Returns the name of kernel partition that can be rolled back into.
- bool GetRollbackPartition(brillo::ErrorPtr* error,
- std::string* out_rollback_partition_name);
-
- // Returns the last UpdateAttempt error.
- bool GetLastAttemptError(brillo::ErrorPtr* error,
- int32_t* out_last_attempt_error);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_SERVICE_H_
diff --git a/cros/common_service_unittest.cc b/cros/common_service_unittest.cc
deleted file mode 100644
index 06446432..00000000
--- a/cros/common_service_unittest.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-//
-// Copyright (C) 2014 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/cros/common_service.h"
-
-#include <gtest/gtest.h>
-#include <string>
-#include <vector>
-
-#include <brillo/errors/error.h>
-#include <policy/libpolicy.h>
-#include <policy/mock_device_policy.h>
-
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/cros/omaha_utils.h"
-
-using std::string;
-using std::vector;
-using testing::_;
-using testing::Return;
-using testing::SetArgPointee;
-using update_engine::UpdateAttemptFlags;
-
-namespace chromeos_update_engine {
-
-class UpdateEngineServiceTest : public ::testing::Test {
- protected:
- UpdateEngineServiceTest() = default;
-
- void SetUp() override {
- FakeSystemState::CreateInstance();
- FakeSystemState::Get()->set_device_policy(nullptr);
- mock_update_attempter_ = FakeSystemState::Get()->mock_update_attempter();
- }
-
- MockUpdateAttempter* mock_update_attempter_;
-
- brillo::ErrorPtr error_;
- UpdateEngineService common_service_;
-};
-
-TEST_F(UpdateEngineServiceTest, AttemptUpdate) {
- EXPECT_CALL(
- *mock_update_attempter_,
- CheckForUpdate("app_ver", "url", UpdateAttemptFlags::kFlagNonInteractive))
- .WillOnce(Return(true));
-
- // The non-interactive flag needs to be passed through to CheckForUpdate.
- bool result = false;
- EXPECT_TRUE(
- common_service_.AttemptUpdate(&error_,
- "app_ver",
- "url",
- UpdateAttemptFlags::kFlagNonInteractive,
- &result));
- EXPECT_EQ(nullptr, error_);
- EXPECT_TRUE(result);
-}
-
-TEST_F(UpdateEngineServiceTest, AttemptUpdateReturnsFalse) {
- EXPECT_CALL(*mock_update_attempter_,
- CheckForUpdate("app_ver", "url", UpdateAttemptFlags::kNone))
- .WillOnce(Return(false));
- bool result = true;
- EXPECT_TRUE(common_service_.AttemptUpdate(
- &error_, "app_ver", "url", UpdateAttemptFlags::kNone, &result));
- EXPECT_EQ(nullptr, error_);
- EXPECT_FALSE(result);
-}
-
-TEST_F(UpdateEngineServiceTest, AttemptInstall) {
- EXPECT_CALL(*mock_update_attempter_, CheckForInstall(_, _))
- .WillOnce(Return(true));
-
- EXPECT_TRUE(common_service_.AttemptInstall(&error_, "", {}));
- EXPECT_EQ(nullptr, error_);
-}
-
-TEST_F(UpdateEngineServiceTest, AttemptInstallReturnsFalse) {
- EXPECT_CALL(*mock_update_attempter_, CheckForInstall(_, _))
- .WillOnce(Return(false));
-
- EXPECT_FALSE(common_service_.AttemptInstall(&error_, "", {}));
-}
-
-TEST_F(UpdateEngineServiceTest, SetDlcActiveValue) {
- EXPECT_CALL(*mock_update_attempter_, SetDlcActiveValue(_, _))
- .WillOnce(Return(true));
-
- EXPECT_TRUE(common_service_.SetDlcActiveValue(&error_, true, "dlc0"));
-}
-
-TEST_F(UpdateEngineServiceTest, SetDlcActiveValueReturnsFalse) {
- EXPECT_CALL(*mock_update_attempter_, SetDlcActiveValue(_, _))
- .WillOnce(Return(false));
-
- EXPECT_FALSE(common_service_.SetDlcActiveValue(&error_, true, "dlc0"));
-}
-
-// SetChannel is allowed when there's no device policy (the device is not
-// enterprise enrolled).
-TEST_F(UpdateEngineServiceTest, SetChannelWithNoPolicy) {
- EXPECT_CALL(*mock_update_attempter_, RefreshDevicePolicy());
- // If SetTargetChannel is called it means the policy check passed.
- EXPECT_CALL(*FakeSystemState::Get()->mock_request_params(),
- SetTargetChannel("stable-channel", true, _))
- .WillOnce(Return(true));
- EXPECT_TRUE(common_service_.SetChannel(&error_, "stable-channel", true));
- ASSERT_EQ(nullptr, error_);
-}
-
-// When the policy is present, the delegated value should be checked.
-TEST_F(UpdateEngineServiceTest, SetChannelWithDelegatedPolicy) {
- policy::MockDevicePolicy mock_device_policy;
- FakeSystemState::Get()->set_device_policy(&mock_device_policy);
- EXPECT_CALL(mock_device_policy, GetReleaseChannelDelegated(_))
- .WillOnce(DoAll(SetArgPointee<0>(true), Return(true)));
- EXPECT_CALL(*FakeSystemState::Get()->mock_request_params(),
- SetTargetChannel("beta-channel", true, _))
- .WillOnce(Return(true));
-
- EXPECT_TRUE(common_service_.SetChannel(&error_, "beta-channel", true));
- ASSERT_EQ(nullptr, error_);
-}
-
-// When passing an invalid value (SetTargetChannel fails) an error should be
-// raised.
-TEST_F(UpdateEngineServiceTest, SetChannelWithInvalidChannel) {
- EXPECT_CALL(*mock_update_attempter_, RefreshDevicePolicy());
- EXPECT_CALL(*FakeSystemState::Get()->mock_request_params(),
- SetTargetChannel("foo-channel", true, _))
- .WillOnce(Return(false));
-
- EXPECT_FALSE(common_service_.SetChannel(&error_, "foo-channel", true));
- ASSERT_NE(nullptr, error_);
- EXPECT_TRUE(error_->HasError(UpdateEngineService::kErrorDomain,
- UpdateEngineService::kErrorFailed));
-}
-
-TEST_F(UpdateEngineServiceTest, GetChannel) {
- FakeSystemState::Get()->mock_request_params()->set_current_channel("current");
- FakeSystemState::Get()->mock_request_params()->set_target_channel("target");
- string channel;
- EXPECT_TRUE(common_service_.GetChannel(
- &error_, true /* get_current_channel */, &channel));
- EXPECT_EQ(nullptr, error_);
- EXPECT_EQ("current", channel);
-
- EXPECT_TRUE(common_service_.GetChannel(
- &error_, false /* get_current_channel */, &channel));
- EXPECT_EQ(nullptr, error_);
- EXPECT_EQ("target", channel);
-}
-
-TEST_F(UpdateEngineServiceTest, ResetStatusSucceeds) {
- EXPECT_CALL(*mock_update_attempter_, ResetStatus()).WillOnce(Return(true));
- EXPECT_TRUE(common_service_.ResetStatus(&error_));
- EXPECT_EQ(nullptr, error_);
-}
-
-TEST_F(UpdateEngineServiceTest, ResetStatusFails) {
- EXPECT_CALL(*mock_update_attempter_, ResetStatus()).WillOnce(Return(false));
- EXPECT_FALSE(common_service_.ResetStatus(&error_));
- ASSERT_NE(nullptr, error_);
- EXPECT_TRUE(error_->HasError(UpdateEngineService::kErrorDomain,
- UpdateEngineService::kErrorFailed));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/connection_manager.cc b/cros/connection_manager.cc
deleted file mode 100644
index 6a5c63b5..00000000
--- a/cros/connection_manager.cc
+++ /dev/null
@@ -1,211 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/connection_manager.h"
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include <base/stl_util.h>
-#include <base/strings/string_util.h>
-#include <policy/device_policy.h>
-#include <shill/dbus-constants.h>
-#include <shill/dbus-proxies.h>
-
-#include "update_engine/common/connection_utils.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/shill_proxy.h"
-#include "update_engine/cros/update_attempter.h"
-
-using org::chromium::flimflam::ManagerProxyInterface;
-using org::chromium::flimflam::ServiceProxyInterface;
-using std::set;
-using std::string;
-
-namespace chromeos_update_engine {
-
-namespace connection_manager {
-std::unique_ptr<ConnectionManagerInterface> CreateConnectionManager() {
- return std::unique_ptr<ConnectionManagerInterface>(
- new ConnectionManager(new ShillProxy()));
-}
-} // namespace connection_manager
-
-ConnectionManager::ConnectionManager(ShillProxyInterface* shill_proxy)
- : shill_proxy_(shill_proxy) {}
-
-bool ConnectionManager::IsUpdateAllowedOver(
- ConnectionType type, ConnectionTethering tethering) const {
- if (type != ConnectionType::kCellular) {
- if (tethering != ConnectionTethering::kConfirmed) {
- return true;
- }
-
- // Treat this connection as if it is a cellular connection.
- LOG(INFO)
- << "Current connection is confirmed tethered, using Cellular setting.";
- }
-
- const policy::DevicePolicy* device_policy =
- SystemState::Get()->device_policy();
-
- // The device_policy is loaded in a lazy way before an update check. Load
- // it now from the libbrillo cache if it wasn't already loaded.
- if (!device_policy) {
- UpdateAttempter* update_attempter = SystemState::Get()->update_attempter();
- if (update_attempter) {
- update_attempter->RefreshDevicePolicy();
- device_policy = SystemState::Get()->device_policy();
- }
- }
-
- if (!device_policy) {
- // Device policy fails to be loaded (possibly due to guest account). We
- // do not check the local user setting here, which should be checked by
- // |OmahaRequestAction| during checking for update.
- LOG(INFO) << "Allowing updates over cellular as device policy fails to be "
- "loaded.";
- return true;
- }
-
- set<string> allowed_types;
- if (device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
- // The update setting is enforced by the device policy.
-
- // TODO(crbug.com/1054279): Use base::Contains after uprev to r680000.
- if (allowed_types.find(shill::kTypeCellular) == allowed_types.end()) {
- LOG(INFO) << "Disabling updates over cellular connection as it's not "
- "allowed in the device policy.";
- return false;
- }
-
- LOG(INFO) << "Allowing updates over cellular per device policy.";
- return true;
- }
-
- // If there's no update setting in the device policy, we do not check
- // the local user setting here, which should be checked by
- // |OmahaRequestAction| during checking for update.
- LOG(INFO) << "Allowing updates over cellular as device policy does "
- "not include update setting.";
- return true;
-}
-
-bool ConnectionManager::IsAllowedConnectionTypesForUpdateSet() const {
- const policy::DevicePolicy* device_policy =
- SystemState::Get()->device_policy();
- if (!device_policy) {
- LOG(INFO) << "There's no device policy loaded yet.";
- return false;
- }
-
- set<string> allowed_types;
- if (!device_policy->GetAllowedConnectionTypesForUpdate(&allowed_types)) {
- return false;
- }
-
- return true;
-}
-
-bool ConnectionManager::GetConnectionProperties(
- ConnectionType* out_type, ConnectionTethering* out_tethering) {
- dbus::ObjectPath default_service_path;
- TEST_AND_RETURN_FALSE(GetDefaultServicePath(&default_service_path));
- if (!default_service_path.IsValid())
- return false;
- // Shill uses the "/" service path to indicate that it is not connected.
- if (default_service_path.value() == "/") {
- *out_type = ConnectionType::kDisconnected;
- *out_tethering = ConnectionTethering::kUnknown;
- return true;
- }
- TEST_AND_RETURN_FALSE(
- GetServicePathProperties(default_service_path, out_type, out_tethering));
- return true;
-}
-
-bool ConnectionManager::GetDefaultServicePath(dbus::ObjectPath* out_path) {
- brillo::VariantDictionary properties;
- brillo::ErrorPtr error;
- ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy();
- if (!manager_proxy)
- return false;
- TEST_AND_RETURN_FALSE(manager_proxy->GetProperties(&properties, &error));
-
- const auto& prop_default_service =
- properties.find(shill::kDefaultServiceProperty);
- if (prop_default_service == properties.end())
- return false;
-
- *out_path = prop_default_service->second.TryGet<dbus::ObjectPath>();
- return out_path->IsValid();
-}
-
-bool ConnectionManager::GetServicePathProperties(
- const dbus::ObjectPath& path,
- ConnectionType* out_type,
- ConnectionTethering* out_tethering) {
- // We create and dispose the ServiceProxyInterface on every request.
- std::unique_ptr<ServiceProxyInterface> service =
- shill_proxy_->GetServiceForPath(path);
-
- brillo::VariantDictionary properties;
- brillo::ErrorPtr error;
- TEST_AND_RETURN_FALSE(service->GetProperties(&properties, &error));
-
- // Populate the out_tethering.
- const auto& prop_tethering = properties.find(shill::kTetheringProperty);
- if (prop_tethering == properties.end()) {
- // Set to Unknown if not present.
- *out_tethering = ConnectionTethering::kUnknown;
- } else {
- // If the property doesn't contain a string value, the empty string will
- // become kUnknown.
- *out_tethering = connection_utils::ParseConnectionTethering(
- prop_tethering->second.TryGet<string>());
- }
-
- // Populate the out_type property.
- const auto& prop_type = properties.find(shill::kTypeProperty);
- if (prop_type == properties.end()) {
- // Set to Unknown if not present.
- *out_type = ConnectionType::kUnknown;
- return false;
- }
-
- string type_str = prop_type->second.TryGet<string>();
- if (type_str == shill::kTypeVPN) {
- const auto& prop_physical =
- properties.find(shill::kPhysicalTechnologyProperty);
- if (prop_physical == properties.end()) {
- LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
- " connection (service: "
- << path.value() << "). Returning default kUnknown value.";
- *out_type = ConnectionType::kUnknown;
- } else {
- *out_type = connection_utils::ParseConnectionType(
- prop_physical->second.TryGet<string>());
- }
- } else {
- *out_type = connection_utils::ParseConnectionType(type_str);
- }
- return true;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/connection_manager.h b/cros/connection_manager.h
deleted file mode 100644
index bb54ff7a..00000000
--- a/cros/connection_manager.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_CONNECTION_MANAGER_H_
-#define UPDATE_ENGINE_CROS_CONNECTION_MANAGER_H_
-
-#include <memory>
-#include <string>
-
-#include <base/macros.h>
-#include <dbus/object_path.h>
-
-#include "update_engine/cros/connection_manager_interface.h"
-#include "update_engine/cros/shill_proxy_interface.h"
-
-namespace chromeos_update_engine {
-
-// This class implements the concrete class that talks with the connection
-// manager (shill) over DBus.
-// TODO(deymo): Remove this class and use ShillProvider from the UpdateManager.
-class ConnectionManager : public ConnectionManagerInterface {
- public:
- // Constructs a new ConnectionManager object initialized with the
- // given system state.
- explicit ConnectionManager(ShillProxyInterface* shill_proxy);
- ~ConnectionManager() override = default;
-
- // ConnectionManagerInterface overrides.
- bool GetConnectionProperties(ConnectionType* out_type,
- ConnectionTethering* out_tethering) override;
- bool IsUpdateAllowedOver(ConnectionType type,
- ConnectionTethering tethering) const override;
- bool IsAllowedConnectionTypesForUpdateSet() const override;
-
- private:
- // Returns (via out_path) the default network path, or "/" if there's no
- // network up. Returns true on success.
- bool GetDefaultServicePath(dbus::ObjectPath* out_path);
-
- bool GetServicePathProperties(const dbus::ObjectPath& path,
- ConnectionType* out_type,
- ConnectionTethering* out_tethering);
-
- // The mockable interface to access the shill DBus proxies.
- std::unique_ptr<ShillProxyInterface> shill_proxy_;
-
- DISALLOW_COPY_AND_ASSIGN(ConnectionManager);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_CONNECTION_MANAGER_H_
diff --git a/cros/connection_manager_interface.h b/cros/connection_manager_interface.h
deleted file mode 100644
index dc6c9838..00000000
--- a/cros/connection_manager_interface.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// Copyright (C) 2015 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_CROS_CONNECTION_MANAGER_INTERFACE_H_
-#define UPDATE_ENGINE_CROS_CONNECTION_MANAGER_INTERFACE_H_
-
-#include <memory>
-
-#include <base/macros.h>
-
-#include "update_engine/common/connection_utils.h"
-
-namespace chromeos_update_engine {
-
-// This class exposes a generic interface to the connection manager
-// (e.g FlimFlam, Shill, etc.) to consolidate all connection-related
-// logic in update_engine.
-class ConnectionManagerInterface {
- public:
- virtual ~ConnectionManagerInterface() = default;
-
- // Populates |out_type| with the type of the network connection
- // that we are currently connected and |out_tethering| with the estimate of
- // whether that network is being tethered.
- virtual bool GetConnectionProperties(ConnectionType* out_type,
- ConnectionTethering* out_tethering) = 0;
-
- // Returns true if we're allowed to update the system when we're
- // connected to the internet through the given network connection type and the
- // given tethering state.
- virtual bool IsUpdateAllowedOver(ConnectionType type,
- ConnectionTethering tethering) const = 0;
-
- // Returns true if the allowed connection types for update is set in the
- // device policy. Otherwise, returns false.
- virtual bool IsAllowedConnectionTypesForUpdateSet() const = 0;
-
- protected:
- ConnectionManagerInterface() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConnectionManagerInterface);
-};
-
-namespace connection_manager {
-// Factory function which creates a ConnectionManager.
-std::unique_ptr<ConnectionManagerInterface> CreateConnectionManager();
-} // namespace connection_manager
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_CONNECTION_MANAGER_INTERFACE_H_
diff --git a/cros/connection_manager_unittest.cc b/cros/connection_manager_unittest.cc
deleted file mode 100644
index 46da8cc9..00000000
--- a/cros/connection_manager_unittest.cc
+++ /dev/null
@@ -1,360 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/connection_manager.h"
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-
-#include <base/logging.h>
-#include <brillo/any.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/variant_dictionary.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <shill/dbus-constants.h>
-#include <shill/dbus-proxies.h>
-#include <shill/dbus-proxy-mocks.h>
-
-#include "update_engine/common/test_utils.h"
-#include "update_engine/cros/fake_shill_proxy.h"
-#include "update_engine/cros/fake_system_state.h"
-
-using chromeos_update_engine::connection_utils::StringForConnectionType;
-using org::chromium::flimflam::ManagerProxyMock;
-using org::chromium::flimflam::ServiceProxyMock;
-using std::set;
-using std::string;
-using testing::_;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace chromeos_update_engine {
-
-class ConnectionManagerTest : public ::testing::Test {
- public:
- ConnectionManagerTest() : fake_shill_proxy_(new FakeShillProxy()) {}
-
- void SetUp() override {
- loop_.SetAsCurrent();
- FakeSystemState::CreateInstance();
- FakeSystemState::Get()->set_connection_manager(&cmut_);
- }
-
- void TearDown() override { EXPECT_FALSE(loop_.PendingTasks()); }
-
- protected:
- // Sets the default_service object path in the response from the
- // ManagerProxyMock instance.
- void SetManagerReply(const char* default_service, bool reply_succeeds);
-
- // Sets the |service_type|, |physical_technology| and |service_tethering|
- // properties in the mocked service |service_path|. If any of the three
- // const char* is a nullptr, the corresponding property will not be included
- // in the response.
- void SetServiceReply(const string& service_path,
- const char* service_type,
- const char* physical_technology,
- const char* service_tethering);
-
- void TestWithServiceType(const char* service_type,
- const char* physical_technology,
- ConnectionType expected_type);
-
- void TestWithServiceDisconnected(ConnectionType expected_type);
-
- void TestWithServiceTethering(const char* service_tethering,
- ConnectionTethering expected_tethering);
-
- brillo::FakeMessageLoop loop_{nullptr};
- FakeShillProxy* fake_shill_proxy_;
-
- // ConnectionManager under test.
- ConnectionManager cmut_{fake_shill_proxy_};
-};
-
-void ConnectionManagerTest::SetManagerReply(const char* default_service,
- bool reply_succeeds) {
- ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy();
- if (!reply_succeeds) {
- EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
- .WillOnce(Return(false));
- return;
- }
-
- // Create a dictionary of properties and optionally include the default
- // service.
- brillo::VariantDictionary reply_dict;
- reply_dict["SomeOtherProperty"] = 0xC0FFEE;
-
- if (default_service) {
- reply_dict[shill::kDefaultServiceProperty] =
- dbus::ObjectPath(default_service);
- }
- EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
- .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
-}
-
-void ConnectionManagerTest::SetServiceReply(const string& service_path,
- const char* service_type,
- const char* physical_technology,
- const char* service_tethering) {
- brillo::VariantDictionary reply_dict;
- reply_dict["SomeOtherProperty"] = 0xC0FFEE;
-
- if (service_type)
- reply_dict[shill::kTypeProperty] = string(service_type);
-
- if (physical_technology) {
- reply_dict[shill::kPhysicalTechnologyProperty] =
- string(physical_technology);
- }
-
- if (service_tethering)
- reply_dict[shill::kTetheringProperty] = string(service_tethering);
-
- std::unique_ptr<ServiceProxyMock> service_proxy_mock(new ServiceProxyMock());
-
- // Plumb return value into mock object.
- EXPECT_CALL(*service_proxy_mock.get(), GetProperties(_, _, _))
- .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
-
- fake_shill_proxy_->SetServiceForPath(dbus::ObjectPath(service_path),
- std::move(service_proxy_mock));
-}
-
-void ConnectionManagerTest::TestWithServiceType(const char* service_type,
- const char* physical_technology,
- ConnectionType expected_type) {
- SetManagerReply("/service/guest/network", true);
- SetServiceReply("/service/guest/network",
- service_type,
- physical_technology,
- shill::kTetheringNotDetectedState);
-
- ConnectionType type;
- ConnectionTethering tethering;
- EXPECT_TRUE(cmut_.GetConnectionProperties(&type, &tethering));
- EXPECT_EQ(expected_type, type);
- testing::Mock::VerifyAndClearExpectations(
- fake_shill_proxy_->GetManagerProxy());
-}
-
-void ConnectionManagerTest::TestWithServiceTethering(
- const char* service_tethering, ConnectionTethering expected_tethering) {
- SetManagerReply("/service/guest/network", true);
- SetServiceReply(
- "/service/guest/network", shill::kTypeWifi, nullptr, service_tethering);
-
- ConnectionType type;
- ConnectionTethering tethering;
- EXPECT_TRUE(cmut_.GetConnectionProperties(&type, &tethering));
- EXPECT_EQ(expected_tethering, tethering);
- testing::Mock::VerifyAndClearExpectations(
- fake_shill_proxy_->GetManagerProxy());
-}
-
-void ConnectionManagerTest::TestWithServiceDisconnected(
- ConnectionType expected_type) {
- SetManagerReply("/", true);
-
- ConnectionType type;
- ConnectionTethering tethering;
- EXPECT_TRUE(cmut_.GetConnectionProperties(&type, &tethering));
- EXPECT_EQ(expected_type, type);
- testing::Mock::VerifyAndClearExpectations(
- fake_shill_proxy_->GetManagerProxy());
-}
-
-TEST_F(ConnectionManagerTest, SimpleTest) {
- TestWithServiceType(shill::kTypeEthernet, nullptr, ConnectionType::kEthernet);
- TestWithServiceType(shill::kTypeWifi, nullptr, ConnectionType::kWifi);
- TestWithServiceType(shill::kTypeCellular, nullptr, ConnectionType::kCellular);
-}
-
-TEST_F(ConnectionManagerTest, PhysicalTechnologyTest) {
- TestWithServiceType(shill::kTypeVPN, nullptr, ConnectionType::kUnknown);
- TestWithServiceType(
- shill::kTypeVPN, shill::kTypeVPN, ConnectionType::kUnknown);
- TestWithServiceType(shill::kTypeVPN, shill::kTypeWifi, ConnectionType::kWifi);
-}
-
-TEST_F(ConnectionManagerTest, TetheringTest) {
- TestWithServiceTethering(shill::kTetheringConfirmedState,
- ConnectionTethering::kConfirmed);
- TestWithServiceTethering(shill::kTetheringNotDetectedState,
- ConnectionTethering::kNotDetected);
- TestWithServiceTethering(shill::kTetheringSuspectedState,
- ConnectionTethering::kSuspected);
- TestWithServiceTethering("I'm not a valid property value =)",
- ConnectionTethering::kUnknown);
-}
-
-TEST_F(ConnectionManagerTest, UnknownTest) {
- TestWithServiceType("foo", nullptr, ConnectionType::kUnknown);
-}
-
-TEST_F(ConnectionManagerTest, DisconnectTest) {
- TestWithServiceDisconnected(ConnectionType::kDisconnected);
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOverEthernetTest) {
- // Updates over Ethernet are allowed even if there's no policy.
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOverWifiTest) {
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOnlyOver3GPerPolicyTest) {
- policy::MockDevicePolicy allow_3g_policy;
-
- FakeSystemState::Get()->set_device_policy(&allow_3g_policy);
-
- // This test tests cellular (3G) being the only connection type being allowed.
- set<string> allowed_set;
- allowed_set.insert(StringForConnectionType(ConnectionType::kCellular));
-
- EXPECT_CALL(allow_3g_policy, GetAllowedConnectionTypesForUpdate(_))
- .Times(1)
- .WillOnce(DoAll(SetArgPointee<0>(allowed_set), Return(true)));
-
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOver3GAndOtherTypesPerPolicyTest) {
- policy::MockDevicePolicy allow_3g_policy;
-
- FakeSystemState::Get()->set_device_policy(&allow_3g_policy);
-
- // This test tests multiple connection types being allowed, with
- // 3G one among them. Only Cellular is currently enforced by the policy
- // setting.
- set<string> allowed_set;
- allowed_set.insert(StringForConnectionType(ConnectionType::kCellular));
-
- EXPECT_CALL(allow_3g_policy, GetAllowedConnectionTypesForUpdate(_))
- .Times(3)
- .WillRepeatedly(DoAll(SetArgPointee<0>(allowed_set), Return(true)));
-
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet,
- ConnectionTethering::kUnknown));
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet,
- ConnectionTethering::kNotDetected));
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
- ConnectionTethering::kUnknown));
-
- // Tethered networks are treated in the same way as Cellular networks and
- // thus allowed.
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet,
- ConnectionTethering::kConfirmed));
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
- ConnectionTethering::kConfirmed));
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOverCellularByDefaultTest) {
- policy::MockDevicePolicy device_policy;
- // Set an empty device policy.
- FakeSystemState::Get()->set_device_policy(&device_policy);
-
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOverTetheredNetworkByDefaultTest) {
- policy::MockDevicePolicy device_policy;
- // Set an empty device policy.
- FakeSystemState::Get()->set_device_policy(&device_policy);
-
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
- ConnectionTethering::kConfirmed));
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kEthernet,
- ConnectionTethering::kConfirmed));
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kWifi,
- ConnectionTethering::kSuspected));
-}
-
-TEST_F(ConnectionManagerTest, BlockUpdatesOver3GPerPolicyTest) {
- policy::MockDevicePolicy block_3g_policy;
-
- FakeSystemState::Get()->set_device_policy(&block_3g_policy);
-
- // Test that updates for 3G are blocked while updates are allowed
- // over several other types.
- set<string> allowed_set;
- allowed_set.insert(StringForConnectionType(ConnectionType::kEthernet));
- allowed_set.insert(StringForConnectionType(ConnectionType::kWifi));
-
- EXPECT_CALL(block_3g_policy, GetAllowedConnectionTypesForUpdate(_))
- .Times(1)
- .WillOnce(DoAll(SetArgPointee<0>(allowed_set), Return(true)));
-
- EXPECT_FALSE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOver3GIfPolicyIsNotSet) {
- policy::MockDevicePolicy device_policy;
-
- FakeSystemState::Get()->set_device_policy(&device_policy);
-
- // Return false for GetAllowedConnectionTypesForUpdate and see
- // that updates are allowed as device policy is not set. Further
- // check is left to |OmahaRequestAction|.
- EXPECT_CALL(device_policy, GetAllowedConnectionTypesForUpdate(_))
- .Times(1)
- .WillOnce(Return(false));
-
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, AllowUpdatesOverCellularIfPolicyFailsToBeLoaded) {
- FakeSystemState::Get()->set_device_policy(nullptr);
-
- EXPECT_TRUE(cmut_.IsUpdateAllowedOver(ConnectionType::kCellular,
- ConnectionTethering::kUnknown));
-}
-
-TEST_F(ConnectionManagerTest, StringForConnectionTypeTest) {
- EXPECT_STREQ(shill::kTypeEthernet,
- StringForConnectionType(ConnectionType::kEthernet));
- EXPECT_STREQ(shill::kTypeWifi,
- StringForConnectionType(ConnectionType::kWifi));
- EXPECT_STREQ(shill::kTypeCellular,
- StringForConnectionType(ConnectionType::kCellular));
- EXPECT_STREQ("Unknown", StringForConnectionType(ConnectionType::kUnknown));
- EXPECT_STREQ("Unknown",
- StringForConnectionType(static_cast<ConnectionType>(999999)));
-}
-
-TEST_F(ConnectionManagerTest, MalformedServiceList) {
- SetManagerReply("/service/guest/network", false);
-
- ConnectionType type;
- ConnectionTethering tethering;
- EXPECT_FALSE(cmut_.GetConnectionProperties(&type, &tethering));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/daemon_chromeos.cc b/cros/daemon_chromeos.cc
deleted file mode 100644
index 366fb9a9..00000000
--- a/cros/daemon_chromeos.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-//
-// Copyright (C) 2015 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/cros/daemon_chromeos.h"
-
-#include <sysexits.h>
-
-#include <base/bind.h>
-#include <base/location.h>
-
-#include "update_engine/cros/real_system_state.h"
-
-using brillo::Daemon;
-using std::unique_ptr;
-
-namespace chromeos_update_engine {
-
-unique_ptr<DaemonBase> DaemonBase::CreateInstance() {
- return std::make_unique<DaemonChromeOS>();
-}
-
-int DaemonChromeOS::OnInit() {
- // Register the |subprocess_| singleton with this Daemon as the signal
- // handler.
- subprocess_.Init(this);
-
- int exit_code = Daemon::OnInit();
- if (exit_code != EX_OK)
- return exit_code;
-
- // Initialize update engine global state.
- // TODO(deymo): Move the initialization to a factory method avoiding the
- // explicit re-usage of the |bus| instance, shared between D-Bus service and
- // D-Bus client calls.
- RealSystemState::SetInstance(&system_state_);
-
- // Create the DBus service.
- dbus_adaptor_.reset(new UpdateEngineAdaptor());
- SystemState::Get()->update_attempter()->AddObserver(dbus_adaptor_.get());
-
- dbus_adaptor_->RegisterAsync(
- base::Bind(&DaemonChromeOS::OnDBusRegistered, base::Unretained(this)));
- LOG(INFO) << "Waiting for DBus object to be registered.";
- return EX_OK;
-}
-
-void DaemonChromeOS::OnDBusRegistered(bool succeeded) {
- if (!succeeded) {
- LOG(ERROR) << "Registering the UpdateEngineAdaptor";
- QuitWithExitCode(1);
- return;
- }
-
- // Take ownership of the service now that everything is initialized. We need
- // to this now and not before to avoid exposing a well known DBus service
- // path that doesn't have the service it is supposed to implement.
- if (!dbus_adaptor_->RequestOwnership()) {
- LOG(ERROR) << "Unable to take ownership of the DBus service, is there "
- << "other update_engine daemon running?";
- QuitWithExitCode(1);
- return;
- }
- SystemState::Get()->update_attempter()->StartUpdater();
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/daemon_chromeos.h b/cros/daemon_chromeos.h
deleted file mode 100644
index b23c2a6f..00000000
--- a/cros/daemon_chromeos.h
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// Copyright (C) 2015 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_CROS_DAEMON_CHROMEOS_H_
-#define UPDATE_ENGINE_CROS_DAEMON_CHROMEOS_H_
-
-#include <memory>
-
-#include "update_engine/common/daemon_base.h"
-#include "update_engine/common/daemon_state_interface.h"
-#include "update_engine/common/subprocess.h"
-#include "update_engine/cros/dbus_service.h"
-#include "update_engine/cros/real_system_state.h"
-
-namespace chromeos_update_engine {
-
-class DaemonChromeOS : public DaemonBase {
- public:
- DaemonChromeOS() = default;
-
- protected:
- int OnInit() override;
-
- private:
- // Run from the main loop when the |dbus_adaptor_| object is registered. At
- // this point we can request ownership of the DBus service name and continue
- // initialization.
- void OnDBusRegistered(bool succeeded);
-
- // |SystemState| is a global context, but we can't have a static singleton of
- // its object because the style guide does not allow that (it has non-trivial
- // dtor). We need an instance of |SystemState| in this class instead and have
- // a global pointer to it. This is better to be defined as the first variable
- // of this class so it is initialized first and destructed last.
- RealSystemState system_state_;
-
- // Main D-Bus service adaptor.
- std::unique_ptr<UpdateEngineAdaptor> dbus_adaptor_;
-
- // The Subprocess singleton class requires a brillo::MessageLoop in the
- // current thread, so we need to initialize it from this class instead of
- // the main() function.
- Subprocess subprocess_;
-
- DISALLOW_COPY_AND_ASSIGN(DaemonChromeOS);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_DAEMON_CHROMEOS_H_
diff --git a/cros/dbus_connection.cc b/cros/dbus_connection.cc
deleted file mode 100644
index 6808bae6..00000000
--- a/cros/dbus_connection.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-// Copyright (C) 2016 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/cros/dbus_connection.h"
-
-#include <base/time/time.h>
-
-namespace chromeos_update_engine {
-
-namespace {
-const int kDBusSystemMaxWaitSeconds = 2 * 60;
-
-DBusConnection* dbus_connection_singleton = nullptr;
-} // namespace
-
-DBusConnection::DBusConnection() {
- // We wait for the D-Bus connection for up two minutes to avoid re-spawning
- // the daemon too fast causing thrashing if dbus-daemon is not running.
- bus_ = dbus_connection_.ConnectWithTimeout(
- base::TimeDelta::FromSeconds(kDBusSystemMaxWaitSeconds));
-
- if (!bus_) {
- // TODO(deymo): Make it possible to run update_engine even if dbus-daemon
- // is not running or constantly crashing.
- LOG(FATAL) << "Failed to initialize DBus, aborting.";
- }
-
- CHECK(bus_->SetUpAsyncOperations());
-}
-
-const scoped_refptr<dbus::Bus>& DBusConnection::GetDBus() {
- CHECK(bus_);
- return bus_;
-}
-
-DBusConnection* DBusConnection::Get() {
- if (!dbus_connection_singleton)
- dbus_connection_singleton = new DBusConnection();
- return dbus_connection_singleton;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/dbus_connection.h b/cros/dbus_connection.h
deleted file mode 100644
index 8f0d6f1f..00000000
--- a/cros/dbus_connection.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (C) 2016 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_CROS_DBUS_CONNECTION_H_
-#define UPDATE_ENGINE_CROS_DBUS_CONNECTION_H_
-
-#include <base/memory/ref_counted.h>
-#include <brillo/dbus/dbus_connection.h>
-#include <dbus/bus.h>
-
-namespace chromeos_update_engine {
-
-class DBusConnection {
- public:
- DBusConnection();
-
- const scoped_refptr<dbus::Bus>& GetDBus();
-
- static DBusConnection* Get();
-
- private:
- scoped_refptr<dbus::Bus> bus_;
-
- brillo::DBusConnection dbus_connection_;
-
- DISALLOW_COPY_AND_ASSIGN(DBusConnection);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_DBUS_CONNECTION_H_
diff --git a/cros/dbus_service.cc b/cros/dbus_service.cc
deleted file mode 100644
index 1eb7b3c0..00000000
--- a/cros/dbus_service.cc
+++ /dev/null
@@ -1,223 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/dbus_service.h"
-
-#include <string>
-#include <vector>
-
-#include <update_engine/dbus-constants.h>
-
-#include "update_engine/cros/dbus_connection.h"
-#include "update_engine/proto_bindings/update_engine.pb.h"
-#include "update_engine/update_status_utils.h"
-
-namespace chromeos_update_engine {
-
-using brillo::ErrorPtr;
-using chromeos_update_engine::UpdateEngineService;
-using std::string;
-using std::vector;
-using update_engine::Operation;
-using update_engine::StatusResult;
-using update_engine::UpdateEngineStatus;
-
-namespace {
-// Converts the internal |UpdateEngineStatus| to the protobuf |StatusResult|.
-void ConvertToStatusResult(const UpdateEngineStatus& ue_status,
- StatusResult* out_status) {
- out_status->set_last_checked_time(ue_status.last_checked_time);
- out_status->set_progress(ue_status.progress);
- out_status->set_current_operation(static_cast<Operation>(ue_status.status));
- out_status->set_new_version(ue_status.new_version);
- out_status->set_new_size(ue_status.new_size_bytes);
- out_status->set_is_enterprise_rollback(ue_status.is_enterprise_rollback);
- out_status->set_is_install(ue_status.is_install);
- out_status->set_eol_date(ue_status.eol_date);
- out_status->set_will_powerwash_after_reboot(
- ue_status.will_powerwash_after_reboot);
-}
-} // namespace
-
-DBusUpdateEngineService::DBusUpdateEngineService()
- : common_(new UpdateEngineService()) {}
-
-// org::chromium::UpdateEngineInterfaceInterface methods implementation.
-
-bool DBusUpdateEngineService::AttemptUpdate(ErrorPtr* error,
- const string& in_app_version,
- const string& in_omaha_url) {
- return AttemptUpdateWithFlags(
- error, in_app_version, in_omaha_url, 0 /* no flags */);
-}
-
-bool DBusUpdateEngineService::AttemptUpdateWithFlags(
- ErrorPtr* error,
- const string& in_app_version,
- const string& in_omaha_url,
- int32_t in_flags_as_int) {
- update_engine::AttemptUpdateFlags flags =
- static_cast<update_engine::AttemptUpdateFlags>(in_flags_as_int);
- bool interactive = !(flags & update_engine::kAttemptUpdateFlagNonInteractive);
- bool result;
- return common_->AttemptUpdate(
- error,
- in_app_version,
- in_omaha_url,
- interactive ? 0 : update_engine::UpdateAttemptFlags::kFlagNonInteractive,
- &result);
-}
-
-bool DBusUpdateEngineService::AttemptInstall(ErrorPtr* error,
- const string& in_omaha_url,
- const vector<string>& dlc_ids) {
- return common_->AttemptInstall(error, in_omaha_url, dlc_ids);
-}
-
-bool DBusUpdateEngineService::AttemptRollback(ErrorPtr* error,
- bool in_powerwash) {
- return common_->AttemptRollback(error, in_powerwash);
-}
-
-bool DBusUpdateEngineService::CanRollback(ErrorPtr* error,
- bool* out_can_rollback) {
- return common_->CanRollback(error, out_can_rollback);
-}
-
-bool DBusUpdateEngineService::ResetStatus(ErrorPtr* error) {
- return common_->ResetStatus(error);
-}
-
-bool DBusUpdateEngineService::SetDlcActiveValue(brillo::ErrorPtr* error,
- bool is_active,
- const string& dlc_id) {
- return common_->SetDlcActiveValue(error, is_active, dlc_id);
-}
-
-bool DBusUpdateEngineService::GetStatusAdvanced(ErrorPtr* error,
- StatusResult* out_status) {
- UpdateEngineStatus status;
- if (!common_->GetStatus(error, &status)) {
- return false;
- }
-
- ConvertToStatusResult(status, out_status);
- return true;
-}
-
-bool DBusUpdateEngineService::RebootIfNeeded(ErrorPtr* error) {
- return common_->RebootIfNeeded(error);
-}
-
-bool DBusUpdateEngineService::SetChannel(ErrorPtr* error,
- const string& in_target_channel,
- bool in_is_powerwash_allowed) {
- return common_->SetChannel(error, in_target_channel, in_is_powerwash_allowed);
-}
-
-bool DBusUpdateEngineService::GetChannel(ErrorPtr* error,
- bool in_get_current_channel,
- string* out_channel) {
- return common_->GetChannel(error, in_get_current_channel, out_channel);
-}
-
-bool DBusUpdateEngineService::GetCohortHint(ErrorPtr* error,
- string* out_cohort_hint) {
- return common_->GetCohortHint(error, out_cohort_hint);
-}
-
-bool DBusUpdateEngineService::SetCohortHint(ErrorPtr* error,
- const string& in_cohort_hint) {
- return common_->SetCohortHint(error, in_cohort_hint);
-}
-
-bool DBusUpdateEngineService::SetP2PUpdatePermission(ErrorPtr* error,
- bool in_enabled) {
- return common_->SetP2PUpdatePermission(error, in_enabled);
-}
-
-bool DBusUpdateEngineService::GetP2PUpdatePermission(ErrorPtr* error,
- bool* out_enabled) {
- return common_->GetP2PUpdatePermission(error, out_enabled);
-}
-
-bool DBusUpdateEngineService::SetUpdateOverCellularPermission(ErrorPtr* error,
- bool in_allowed) {
- return common_->SetUpdateOverCellularPermission(error, in_allowed);
-}
-
-bool DBusUpdateEngineService::SetUpdateOverCellularTarget(
- brillo::ErrorPtr* error,
- const std::string& target_version,
- int64_t target_size) {
- return common_->SetUpdateOverCellularTarget(
- error, target_version, target_size);
-}
-
-bool DBusUpdateEngineService::GetUpdateOverCellularPermission(
- ErrorPtr* error, bool* out_allowed) {
- return common_->GetUpdateOverCellularPermission(error, out_allowed);
-}
-
-bool DBusUpdateEngineService::GetDurationSinceUpdate(
- ErrorPtr* error, int64_t* out_usec_wallclock) {
- return common_->GetDurationSinceUpdate(error, out_usec_wallclock);
-}
-
-bool DBusUpdateEngineService::GetPrevVersion(ErrorPtr* error,
- string* out_prev_version) {
- return common_->GetPrevVersion(error, out_prev_version);
-}
-
-bool DBusUpdateEngineService::GetRollbackPartition(
- ErrorPtr* error, string* out_rollback_partition_name) {
- return common_->GetRollbackPartition(error, out_rollback_partition_name);
-}
-
-bool DBusUpdateEngineService::GetLastAttemptError(
- ErrorPtr* error, int32_t* out_last_attempt_error) {
- return common_->GetLastAttemptError(error, out_last_attempt_error);
-}
-
-UpdateEngineAdaptor::UpdateEngineAdaptor()
- : org::chromium::UpdateEngineInterfaceAdaptor(&dbus_service_),
- bus_(DBusConnection::Get()->GetDBus()),
- dbus_service_(),
- dbus_object_(nullptr,
- bus_,
- dbus::ObjectPath(update_engine::kUpdateEngineServicePath)) {}
-
-void UpdateEngineAdaptor::RegisterAsync(
- const base::Callback<void(bool)>& completion_callback) {
- RegisterWithDBusObject(&dbus_object_);
- dbus_object_.RegisterAsync(completion_callback);
-}
-
-bool UpdateEngineAdaptor::RequestOwnership() {
- return bus_->RequestOwnershipAndBlock(update_engine::kUpdateEngineServiceName,
- dbus::Bus::REQUIRE_PRIMARY);
-}
-
-void UpdateEngineAdaptor::SendStatusUpdate(
- const UpdateEngineStatus& update_engine_status) {
- StatusResult status;
- ConvertToStatusResult(update_engine_status, &status);
-
- // Send |StatusUpdateAdvanced| signal.
- SendStatusUpdateAdvancedSignal(status);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/dbus_service.h b/cros/dbus_service.h
deleted file mode 100644
index 3ad6589e..00000000
--- a/cros/dbus_service.h
+++ /dev/null
@@ -1,194 +0,0 @@
-//
-// Copyright (C) 2010 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_CROS_DBUS_SERVICE_H_
-#define UPDATE_ENGINE_CROS_DBUS_SERVICE_H_
-
-#include <inttypes.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/memory/ref_counted.h>
-#include <brillo/errors/error.h>
-#include <update_engine/proto_bindings/update_engine.pb.h>
-
-#include "update_engine/common/service_observer_interface.h"
-#include "update_engine/cros/common_service.h"
-#include "update_engine/cros/update_attempter.h"
-
-#include "dbus_bindings/org.chromium.UpdateEngineInterface.h"
-
-namespace chromeos_update_engine {
-
-class DBusUpdateEngineService
- : public org::chromium::UpdateEngineInterfaceInterface {
- public:
- DBusUpdateEngineService();
- virtual ~DBusUpdateEngineService() = default;
-
- // Implementation of org::chromium::UpdateEngineInterfaceInterface.
- bool AttemptUpdate(brillo::ErrorPtr* error,
- const std::string& in_app_version,
- const std::string& in_omaha_url) override;
-
- bool AttemptUpdateWithFlags(brillo::ErrorPtr* error,
- const std::string& in_app_version,
- const std::string& in_omaha_url,
- int32_t in_flags_as_int) override;
-
- bool AttemptInstall(brillo::ErrorPtr* error,
- const std::string& in_omaha_url,
- const std::vector<std::string>& dlc_ids) override;
-
- bool AttemptRollback(brillo::ErrorPtr* error, bool in_powerwash) override;
-
- // Checks if the system rollback is available by verifying if the secondary
- // system partition is valid and bootable.
- bool CanRollback(brillo::ErrorPtr* error, bool* out_can_rollback) override;
-
- // Resets the status of the update_engine to idle, ignoring any applied
- // update. This is used for development only.
- bool ResetStatus(brillo::ErrorPtr* error) override;
-
- // Sets the DLC as active or inactive. When set to active, the ping metadata
- // for the DLC is updated accordingly. When set to inactive, the metadata
- // for the DLC is deleted.
- bool SetDlcActiveValue(brillo::ErrorPtr* error,
- bool is_active,
- const std::string& dlc_id) override;
-
- // Similar to Above, but returns a protobuffer instead. In the future it will
- // have more features and is easily extendable.
- bool GetStatusAdvanced(brillo::ErrorPtr* error,
- update_engine::StatusResult* out_status) override;
-
- // Reboots the device if an update is applied and a reboot is required.
- bool RebootIfNeeded(brillo::ErrorPtr* error) override;
-
- // Changes the current channel of the device to the target channel. If the
- // target channel is a less stable channel than the current channel, then the
- // channel change happens immediately (at the next update check). If the
- // target channel is a more stable channel, then if is_powerwash_allowed is
- // set to true, then also the change happens immediately but with a powerwash
- // if required. Otherwise, the change takes effect eventually (when the
- // version on the target channel goes above the version number of what the
- // device currently has).
- bool SetChannel(brillo::ErrorPtr* error,
- const std::string& in_target_channel,
- bool in_is_powerwash_allowed) override;
-
- // If get_current_channel is set to true, populates |channel| with the name of
- // the channel that the device is currently on. Otherwise, it populates it
- // with the name of the channel the device is supposed to be (in case of a
- // pending channel change).
- bool GetChannel(brillo::ErrorPtr* error,
- bool in_get_current_channel,
- std::string* out_channel) override;
-
- bool SetCohortHint(brillo::ErrorPtr* error,
- const std::string& in_cohort_hint) override;
-
- bool GetCohortHint(brillo::ErrorPtr* error,
- std::string* out_cohort_hint) override;
-
- // Enables or disables the sharing and consuming updates over P2P feature
- // according to the |enabled| argument passed.
- bool SetP2PUpdatePermission(brillo::ErrorPtr* error,
- bool in_enabled) override;
-
- // Returns the current value for the P2P enabled setting. This involves both
- // sharing and consuming updates over P2P.
- bool GetP2PUpdatePermission(brillo::ErrorPtr* error,
- bool* out_enabled) override;
-
- // If there's no device policy installed, sets the update over cellular
- // networks permission to the |allowed| value. Otherwise, this method returns
- // with an error since this setting is overridden by the applied policy.
- bool SetUpdateOverCellularPermission(brillo::ErrorPtr* error,
- bool in_allowed) override;
-
- // If there's no device policy installed, sets the update over cellular
- // target. Otherwise, this method returns with an error.
- bool SetUpdateOverCellularTarget(brillo::ErrorPtr* error,
- const std::string& target_version,
- int64_t target_size) override;
-
- // Returns the current value of the update over cellular network setting,
- // either forced by the device policy if the device is enrolled or the current
- // user preference otherwise.
- bool GetUpdateOverCellularPermission(brillo::ErrorPtr* error,
- bool* out_allowed) override;
-
- // Returns the duration since the last successful update, as the
- // duration on the wallclock. Returns an error if the device has not
- // updated.
- bool GetDurationSinceUpdate(brillo::ErrorPtr* error,
- int64_t* out_usec_wallclock) override;
-
- // Returns the version string of OS that was used before the last reboot
- // into an updated version. This is available only when rebooting into an
- // update from previous version, otherwise an empty string is returned.
- bool GetPrevVersion(brillo::ErrorPtr* error,
- std::string* out_prev_version) override;
-
- // Returns the name of kernel partition that can be rolled back into.
- bool GetRollbackPartition(brillo::ErrorPtr* error,
- std::string* out_rollback_partition_name) override;
-
- // Returns the last UpdateAttempt error. If not updated yet, default success
- // ErrorCode will be returned.
- bool GetLastAttemptError(brillo::ErrorPtr* error,
- int32_t* out_last_attempt_error) override;
-
- private:
- std::unique_ptr<UpdateEngineService> common_;
-};
-
-// The UpdateEngineAdaptor class runs the UpdateEngineInterface in the fixed
-// object path, without an ObjectManager notifying the interfaces, since it is
-// all static and clients don't expect it to be implemented.
-class UpdateEngineAdaptor : public org::chromium::UpdateEngineInterfaceAdaptor,
- public ServiceObserverInterface {
- public:
- UpdateEngineAdaptor();
- ~UpdateEngineAdaptor() = default;
-
- // Register the DBus object with the update engine service asynchronously.
- // Calls |copmletion_callback| when done passing a boolean indicating if the
- // registration succeeded.
- void RegisterAsync(const base::Callback<void(bool)>& completion_callback);
-
- // Takes ownership of the well-known DBus name and returns whether it
- // succeeded.
- bool RequestOwnership();
-
- // ServiceObserverInterface overrides.
- void SendStatusUpdate(
- const update_engine::UpdateEngineStatus& update_engine_status) override;
-
- void SendPayloadApplicationComplete(ErrorCode error_code) override {}
-
- private:
- scoped_refptr<dbus::Bus> bus_;
- DBusUpdateEngineService dbus_service_;
- brillo::dbus_utils::DBusObject dbus_object_;
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_DBUS_SERVICE_H_
diff --git a/cros/dbus_test_utils.h b/cros/dbus_test_utils.h
deleted file mode 100644
index 1116c528..00000000
--- a/cros/dbus_test_utils.h
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-// Copyright (C) 2015 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_CROS_DBUS_TEST_UTILS_H_
-#define UPDATE_ENGINE_CROS_DBUS_TEST_UTILS_H_
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-
-#include <base/bind.h>
-#include <brillo/message_loops/message_loop.h>
-#include <gmock/gmock.h>
-
-namespace chromeos_update_engine {
-namespace dbus_test_utils {
-
-#define MOCK_SIGNAL_HANDLER_EXPECT_SIGNAL_HANDLER( \
- mock_signal_handler, mock_proxy, signal) \
- do { \
- EXPECT_CALL((mock_proxy), \
- DoRegister##signal##SignalHandler(::testing::_, ::testing::_)) \
- .WillOnce(::chromeos_update_engine::dbus_test_utils::GrabCallbacks( \
- &(mock_signal_handler))); \
- } while (false)
-
-template <typename T>
-class MockSignalHandler {
- public:
- MockSignalHandler() = default;
- ~MockSignalHandler() {
- if (callback_connected_task_ != brillo::MessageLoop::kTaskIdNull)
- brillo::MessageLoop::current()->CancelTask(callback_connected_task_);
- }
-
- // Returns whether the signal handler is registered.
- bool IsHandlerRegistered() const { return signal_callback_ != nullptr; }
-
- const base::Callback<T>& signal_callback() { return *signal_callback_.get(); }
-
- void GrabCallbacks(
- const base::Callback<T>& signal_callback,
- dbus::ObjectProxy::OnConnectedCallback* on_connected_callback) {
- signal_callback_.reset(new base::Callback<T>(signal_callback));
- on_connected_callback_.reset(new dbus::ObjectProxy::OnConnectedCallback(
- std::move(*on_connected_callback)));
- // Notify from the main loop that the callback was connected.
- callback_connected_task_ = brillo::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&MockSignalHandler<T>::OnCallbackConnected,
- base::Unretained(this)));
- }
-
- private:
- void OnCallbackConnected() {
- callback_connected_task_ = brillo::MessageLoop::kTaskIdNull;
- std::move(*on_connected_callback_).Run("", "", true);
- }
-
- brillo::MessageLoop::TaskId callback_connected_task_{
- brillo::MessageLoop::kTaskIdNull};
-
- std::unique_ptr<base::Callback<T>> signal_callback_;
- std::unique_ptr<dbus::ObjectProxy::OnConnectedCallback>
- on_connected_callback_;
-};
-
-// Defines the action that will call MockSignalHandler<T>::GrabCallbacks for the
-// right type.
-ACTION_P(GrabCallbacks, mock_signal_handler) {
- mock_signal_handler->GrabCallbacks(arg0, arg1);
-}
-
-} // namespace dbus_test_utils
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_DBUS_TEST_UTILS_H_
diff --git a/cros/dlcservice_chromeos.cc b/cros/dlcservice_chromeos.cc
deleted file mode 100644
index e510c1d1..00000000
--- a/cros/dlcservice_chromeos.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// Copyright (C) 2018 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/cros/dlcservice_chromeos.h"
-
-#include <brillo/errors/error.h>
-#include <dlcservice/proto_bindings/dlcservice.pb.h>
-// NOLINTNEXTLINE(build/include_alpha) "dbus-proxies.h" needs "dlcservice.pb.h"
-#include <dlcservice/dbus-proxies.h>
-
-#include "update_engine/cros/dbus_connection.h"
-
-using std::string;
-using std::vector;
-
-namespace chromeos_update_engine {
-
-namespace {
-org::chromium::DlcServiceInterfaceProxy GetDlcServiceProxy() {
- return {DBusConnection::Get()->GetDBus()};
-}
-} // namespace
-
-std::unique_ptr<DlcServiceInterface> CreateDlcService() {
- return std::make_unique<DlcServiceChromeOS>();
-}
-
-bool DlcServiceChromeOS::GetDlcsToUpdate(vector<string>* dlc_ids) {
- if (!dlc_ids)
- return false;
- dlc_ids->clear();
-
- brillo::ErrorPtr err;
- if (!GetDlcServiceProxy().GetDlcsToUpdate(dlc_ids, &err)) {
- LOG(ERROR) << "dlcservice failed to return DLCs that need to be updated. "
- << "ErrorCode=" << err->GetCode()
- << ", ErrMsg=" << err->GetMessage();
- dlc_ids->clear();
- return false;
- }
- return true;
-}
-
-bool DlcServiceChromeOS::InstallCompleted(const vector<string>& dlc_ids) {
- brillo::ErrorPtr err;
- if (!GetDlcServiceProxy().InstallCompleted(dlc_ids, &err)) {
- LOG(ERROR) << "dlcservice failed to complete install. ErrCode="
- << err->GetCode() << ", ErrMsg=" << err->GetMessage();
- return false;
- }
- return true;
-}
-
-bool DlcServiceChromeOS::UpdateCompleted(const vector<string>& dlc_ids) {
- brillo::ErrorPtr err;
- if (!GetDlcServiceProxy().UpdateCompleted(dlc_ids, &err)) {
- LOG(ERROR) << "dlcservice failed to complete updated. ErrCode="
- << err->GetCode() << ", ErrMsg=" << err->GetMessage();
- return false;
- }
- return true;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/dlcservice_chromeos.h b/cros/dlcservice_chromeos.h
deleted file mode 100644
index 3f11b126..00000000
--- a/cros/dlcservice_chromeos.h
+++ /dev/null
@@ -1,55 +0,0 @@
-//
-// Copyright (C) 2018 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_CROS_DLCSERVICE_CHROMEOS_H_
-#define UPDATE_ENGINE_CROS_DLCSERVICE_CHROMEOS_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "update_engine/common/dlcservice_interface.h"
-
-namespace chromeos_update_engine {
-
-// The Chrome OS implementation of the DlcServiceInterface. This interface
-// interacts with dlcservice via D-Bus.
-class DlcServiceChromeOS : public DlcServiceInterface {
- public:
- DlcServiceChromeOS() = default;
- ~DlcServiceChromeOS() = default;
-
- // DlcServiceInterface overrides.
-
- // Will clear the |dlc_ids|, passed to be modified. Clearing by default has
- // the added benefit of avoiding indeterminate behavior in the case that
- // |dlc_ids| wasn't empty to begin which would lead to possible duplicates and
- // cases when error was not checked it's still safe.
- bool GetDlcsToUpdate(std::vector<std::string>* dlc_ids) override;
-
- // Call into dlcservice for it to mark the DLC IDs as being installed.
- bool InstallCompleted(const std::vector<std::string>& dlc_ids) override;
-
- // Call into dlcservice for it to mark the DLC IDs as being updated.
- bool UpdateCompleted(const std::vector<std::string>& dlc_ids) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DlcServiceChromeOS);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_DLCSERVICE_CHROMEOS_H_
diff --git a/cros/download_action_chromeos.cc b/cros/download_action_chromeos.cc
deleted file mode 100644
index ee9c9a70..00000000
--- a/cros/download_action_chromeos.cc
+++ /dev/null
@@ -1,469 +0,0 @@
-//
-// 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/cros/download_action_chromeos.h"
-
-#include <errno.h>
-
-#include <algorithm>
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/metrics/statistics_recorder.h>
-#include <base/strings/stringprintf.h>
-
-#include "update_engine/common/action_pipe.h"
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/error_code_utils.h"
-#include "update_engine/common/multi_range_http_fetcher.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/p2p_manager.h"
-#include "update_engine/cros/payload_state_interface.h"
-
-using base::FilePath;
-using std::string;
-
-namespace chromeos_update_engine {
-
-DownloadActionChromeos::DownloadActionChromeos(
- PrefsInterface* prefs,
- BootControlInterface* boot_control,
- HardwareInterface* hardware,
- HttpFetcher* http_fetcher,
- bool interactive)
- : prefs_(prefs),
- boot_control_(boot_control),
- hardware_(hardware),
- http_fetcher_(new MultiRangeHttpFetcher(http_fetcher)),
- interactive_(interactive),
- writer_(nullptr),
- code_(ErrorCode::kSuccess),
- delegate_(nullptr),
- p2p_sharing_fd_(-1),
- p2p_visible_(true) {}
-
-DownloadActionChromeos::~DownloadActionChromeos() {}
-
-void DownloadActionChromeos::CloseP2PSharingFd(bool delete_p2p_file) {
- if (p2p_sharing_fd_ != -1) {
- if (close(p2p_sharing_fd_) != 0) {
- PLOG(ERROR) << "Error closing p2p sharing fd";
- }
- p2p_sharing_fd_ = -1;
- }
-
- if (delete_p2p_file) {
- FilePath path =
- SystemState::Get()->p2p_manager()->FileGetPath(p2p_file_id_);
- if (unlink(path.value().c_str()) != 0) {
- PLOG(ERROR) << "Error deleting p2p file " << path.value();
- } else {
- LOG(INFO) << "Deleted p2p file " << path.value();
- }
- }
-
- // Don't use p2p from this point onwards.
- p2p_file_id_.clear();
-}
-
-bool DownloadActionChromeos::SetupP2PSharingFd() {
- P2PManager* p2p_manager = SystemState::Get()->p2p_manager();
-
- if (!p2p_manager->FileShare(p2p_file_id_, payload_->size)) {
- LOG(ERROR) << "Unable to share file via p2p";
- CloseP2PSharingFd(true); // delete p2p file
- return false;
- }
-
- // File has already been created (and allocated, xattrs been
- // populated etc.) by FileShare() so just open it for writing.
- FilePath path = p2p_manager->FileGetPath(p2p_file_id_);
- p2p_sharing_fd_ = open(path.value().c_str(), O_WRONLY);
- if (p2p_sharing_fd_ == -1) {
- PLOG(ERROR) << "Error opening file " << path.value();
- CloseP2PSharingFd(true); // Delete p2p file.
- return false;
- }
-
- // Ensure file to share is world-readable, otherwise
- // p2p-server and p2p-http-server can't access it.
- //
- // (Q: Why doesn't the file have mode 0644 already? A: Because
- // the process-wide umask is set to 0700 in main.cc.)
- if (fchmod(p2p_sharing_fd_, 0644) != 0) {
- PLOG(ERROR) << "Error setting mode 0644 on " << path.value();
- CloseP2PSharingFd(true); // Delete p2p file.
- return false;
- }
-
- // All good.
- LOG(INFO) << "Writing payload contents to " << path.value();
- p2p_manager->FileGetVisible(p2p_file_id_, &p2p_visible_);
- return true;
-}
-
-void DownloadActionChromeos::WriteToP2PFile(const void* data,
- size_t length,
- off_t file_offset) {
- if (p2p_sharing_fd_ == -1) {
- if (!SetupP2PSharingFd())
- return;
- }
-
- // Check that the file is at least |file_offset| bytes long - if
- // it's not something is wrong and we must immediately delete the
- // file to avoid propagating this problem to other peers.
- //
- // How can this happen? It could be that we're resuming an update
- // after a system crash... in this case, it could be that
- //
- // 1. the p2p file didn't get properly synced to stable storage; or
- // 2. the file was deleted at bootup (it's in /var/cache after all); or
- // 3. other reasons
- off_t p2p_size = utils::FileSize(p2p_sharing_fd_);
- if (p2p_size < 0) {
- PLOG(ERROR) << "Error getting file status for p2p file";
- CloseP2PSharingFd(true); // Delete p2p file.
- return;
- }
- if (p2p_size < file_offset) {
- LOG(ERROR) << "Wanting to write to file offset " << file_offset
- << " but existing p2p file is only " << p2p_size << " bytes.";
- CloseP2PSharingFd(true); // Delete p2p file.
- return;
- }
-
- off_t cur_file_offset = lseek(p2p_sharing_fd_, file_offset, SEEK_SET);
- if (cur_file_offset != static_cast<off_t>(file_offset)) {
- PLOG(ERROR) << "Error seeking to position " << file_offset
- << " in p2p file";
- CloseP2PSharingFd(true); // Delete p2p file.
- } else {
- // OK, seeking worked, now write the data
- ssize_t bytes_written = write(p2p_sharing_fd_, data, length);
- if (bytes_written != static_cast<ssize_t>(length)) {
- PLOG(ERROR) << "Error writing " << length << " bytes at file offset "
- << file_offset << " in p2p file";
- CloseP2PSharingFd(true); // Delete p2p file.
- }
- }
-}
-
-void DownloadActionChromeos::PerformAction() {
- http_fetcher_->set_delegate(this);
-
- // Get the InstallPlan and read it
- CHECK(HasInputObject());
- install_plan_ = GetInputObject();
- install_plan_.Dump();
-
- bytes_received_ = 0;
- bytes_received_previous_payloads_ = 0;
- bytes_total_ = 0;
- for (const auto& payload : install_plan_.payloads)
- bytes_total_ += payload.size;
-
- if (install_plan_.is_resume) {
- int64_t payload_index = 0;
- if (prefs_->GetInt64(kPrefsUpdateStatePayloadIndex, &payload_index) &&
- static_cast<size_t>(payload_index) < install_plan_.payloads.size()) {
- // Save the index for the resume payload before downloading any previous
- // payload, otherwise it will be overwritten.
- resume_payload_index_ = payload_index;
- for (int i = 0; i < payload_index; i++)
- install_plan_.payloads[i].already_applied = true;
- }
- }
- // TODO(senj): check that install plan has at least one payload.
- if (!payload_)
- payload_ = &install_plan_.payloads[0];
-
- LOG(INFO) << "Marking new slot as unbootable";
- if (!boot_control_->MarkSlotUnbootable(install_plan_.target_slot)) {
- LOG(WARNING) << "Unable to mark new slot "
- << BootControlInterface::SlotName(install_plan_.target_slot)
- << ". Proceeding with the update anyway.";
- }
-
- StartDownloading();
-}
-
-bool DownloadActionChromeos::LoadCachedManifest(int64_t manifest_size) {
- std::string cached_manifest_bytes;
- if (!prefs_->GetString(kPrefsManifestBytes, &cached_manifest_bytes) ||
- cached_manifest_bytes.size() <= 0) {
- LOG(INFO) << "Cached Manifest data not found";
- return false;
- }
- if (static_cast<int64_t>(cached_manifest_bytes.size()) != manifest_size) {
- LOG(WARNING) << "Cached metadata has unexpected size: "
- << cached_manifest_bytes.size() << " vs. " << manifest_size;
- return false;
- }
-
- ErrorCode error;
- const bool success =
- delta_performer_->Write(
- cached_manifest_bytes.data(), cached_manifest_bytes.size(), &error) &&
- delta_performer_->IsManifestValid();
- if (success) {
- LOG(INFO) << "Successfully parsed cached manifest";
- } else {
- // If parsing of cached data failed, fall back to fetch them using HTTP
- LOG(WARNING) << "Cached manifest data fails to load, error code:"
- << static_cast<int>(error) << "," << error;
- }
- return success;
-}
-
-void DownloadActionChromeos::StartDownloading() {
- download_active_ = true;
- http_fetcher_->ClearRanges();
-
- if (writer_ && writer_ != delta_performer_.get()) {
- LOG(INFO) << "Using writer for test.";
- } else {
- delta_performer_.reset(new DeltaPerformer(prefs_,
- boot_control_,
- hardware_,
- delegate_,
- &install_plan_,
- payload_,
- interactive_));
- writer_ = delta_performer_.get();
- }
-
- if (install_plan_.is_resume &&
- payload_ == &install_plan_.payloads[resume_payload_index_]) {
- // Resuming an update so parse the cached manifest first
- int64_t manifest_metadata_size = 0;
- int64_t manifest_signature_size = 0;
- prefs_->GetInt64(kPrefsManifestMetadataSize, &manifest_metadata_size);
- prefs_->GetInt64(kPrefsManifestSignatureSize, &manifest_signature_size);
-
- // TODO(zhangkelvin) Add unittest for success and fallback route
- if (!LoadCachedManifest(manifest_metadata_size + manifest_signature_size)) {
- if (delta_performer_) {
- // Create a new DeltaPerformer to reset all its state
- delta_performer_ = std::make_unique<DeltaPerformer>(prefs_,
- boot_control_,
- hardware_,
- delegate_,
- &install_plan_,
- payload_,
- interactive_);
- writer_ = delta_performer_.get();
- }
- http_fetcher_->AddRange(base_offset_,
- manifest_metadata_size + manifest_signature_size);
- }
-
- // If there're remaining unprocessed data blobs, fetch them. Be careful not
- // to request data beyond the end of the payload to avoid 416 HTTP response
- // error codes.
- int64_t next_data_offset = 0;
- prefs_->GetInt64(kPrefsUpdateStateNextDataOffset, &next_data_offset);
- uint64_t resume_offset =
- manifest_metadata_size + manifest_signature_size + next_data_offset;
- if (!payload_->size) {
- http_fetcher_->AddRange(base_offset_ + resume_offset);
- } else if (resume_offset < payload_->size) {
- http_fetcher_->AddRange(base_offset_ + resume_offset,
- payload_->size - resume_offset);
- }
- } else {
- if (payload_->size) {
- http_fetcher_->AddRange(base_offset_, payload_->size);
- } else {
- // If no payload size is passed we assume we read until the end of the
- // stream.
- http_fetcher_->AddRange(base_offset_);
- }
- }
-
- if (SystemState::Get() != nullptr) {
- const PayloadStateInterface* payload_state =
- SystemState::Get()->payload_state();
- string file_id = utils::CalculateP2PFileId(payload_->hash, payload_->size);
- if (payload_state->GetUsingP2PForSharing()) {
- // If we're sharing the update, store the file_id to convey
- // that we should write to the file.
- p2p_file_id_ = file_id;
- LOG(INFO) << "p2p file id: " << p2p_file_id_;
- } else {
- // Even if we're not sharing the update, it could be that
- // there's a partial file from a previous attempt with the same
- // hash. If this is the case, we NEED to clean it up otherwise
- // we're essentially timing out other peers downloading from us
- // (since we're never going to complete the file).
- FilePath path = SystemState::Get()->p2p_manager()->FileGetPath(file_id);
- if (!path.empty()) {
- if (unlink(path.value().c_str()) != 0) {
- PLOG(ERROR) << "Error deleting p2p file " << path.value();
- } else {
- LOG(INFO) << "Deleting partial p2p file " << path.value()
- << " since we're not using p2p to share.";
- }
- }
- }
-
- // Tweak timeouts on the HTTP fetcher if we're downloading from a
- // local peer.
- if (payload_state->GetUsingP2PForDownloading() &&
- payload_state->GetP2PUrl() == install_plan_.download_url) {
- LOG(INFO) << "Tweaking HTTP fetcher since we're downloading via p2p";
- http_fetcher_->set_low_speed_limit(kDownloadP2PLowSpeedLimitBps,
- kDownloadP2PLowSpeedTimeSeconds);
- http_fetcher_->set_max_retry_count(kDownloadP2PMaxRetryCount);
- http_fetcher_->set_connect_timeout(kDownloadP2PConnectTimeoutSeconds);
- }
- }
-
- http_fetcher_->BeginTransfer(install_plan_.download_url);
-}
-
-void DownloadActionChromeos::SuspendAction() {
- http_fetcher_->Pause();
-}
-
-void DownloadActionChromeos::ResumeAction() {
- http_fetcher_->Unpause();
-}
-
-void DownloadActionChromeos::TerminateProcessing() {
- if (writer_) {
- writer_->Close();
- writer_ = nullptr;
- }
- download_active_ = false;
- CloseP2PSharingFd(false); // Keep p2p file.
- // Terminates the transfer. The action is terminated, if necessary, when the
- // TransferTerminated callback is received.
- http_fetcher_->TerminateTransfer();
-}
-
-void DownloadActionChromeos::SeekToOffset(off_t offset) {
- bytes_received_ = offset;
-}
-
-bool DownloadActionChromeos::ReceivedBytes(HttpFetcher* fetcher,
- const void* bytes,
- size_t length) {
- // Note that bytes_received_ is the current offset.
- if (!p2p_file_id_.empty()) {
- WriteToP2PFile(bytes, length, bytes_received_);
- }
-
- bytes_received_ += length;
- uint64_t bytes_downloaded_total =
- bytes_received_previous_payloads_ + bytes_received_;
- if (delegate_ && download_active_) {
- delegate_->BytesReceived(length, bytes_downloaded_total, bytes_total_);
- }
- if (writer_ && !writer_->Write(bytes, length, &code_)) {
- if (code_ != ErrorCode::kSuccess) {
- LOG(ERROR) << "Error " << utils::ErrorCodeToString(code_) << " (" << code_
- << ") in DeltaPerformer's Write method when "
- << "processing the received payload -- Terminating processing";
- }
- // Delete p2p file, if applicable.
- if (!p2p_file_id_.empty())
- CloseP2PSharingFd(true);
- // Don't tell the action processor that the action is complete until we get
- // the TransferTerminated callback. Otherwise, this and the HTTP fetcher
- // objects may get destroyed before all callbacks are complete.
- TerminateProcessing();
- return false;
- }
-
- // Call p2p_manager_->FileMakeVisible() when we've successfully
- // verified the manifest!
- if (!p2p_visible_ && SystemState::Get() && delta_performer_.get() &&
- delta_performer_->IsManifestValid()) {
- LOG(INFO) << "Manifest has been validated. Making p2p file visible.";
- SystemState::Get()->p2p_manager()->FileMakeVisible(p2p_file_id_);
- p2p_visible_ = true;
- }
- return true;
-}
-
-void DownloadActionChromeos::TransferComplete(HttpFetcher* fetcher,
- bool successful) {
- if (writer_) {
- LOG_IF(WARNING, writer_->Close() != 0) << "Error closing the writer.";
- if (delta_performer_.get() == writer_) {
- // no delta_performer_ in tests, so leave the test writer in place
- writer_ = nullptr;
- }
- }
- download_active_ = false;
- ErrorCode code =
- successful ? ErrorCode::kSuccess : ErrorCode::kDownloadTransferError;
- if (code == ErrorCode::kSuccess) {
- if (delta_performer_ && !payload_->already_applied)
- code = delta_performer_->VerifyPayload(payload_->hash, payload_->size);
- if (code == ErrorCode::kSuccess) {
- if (payload_ < &install_plan_.payloads.back() &&
- SystemState::Get()->payload_state()->NextPayload()) {
- LOG(INFO) << "Incrementing to next payload";
- // No need to reset if this payload was already applied.
- if (delta_performer_ && !payload_->already_applied)
- DeltaPerformer::ResetUpdateProgress(prefs_, false);
- // Start downloading next payload.
- bytes_received_previous_payloads_ += payload_->size;
- payload_++;
- install_plan_.download_url =
- SystemState::Get()->payload_state()->GetCurrentUrl();
- StartDownloading();
- return;
- }
-
- // All payloads have been applied and verified.
- if (delegate_)
- delegate_->DownloadComplete();
-
- std::string histogram_output;
- base::StatisticsRecorder::WriteGraph(
- "UpdateEngine.DownloadActionChromeos.", &histogram_output);
- LOG(INFO) << histogram_output;
- } else {
- LOG(ERROR) << "Download of " << install_plan_.download_url
- << " failed due to payload verification error.";
- // Delete p2p file, if applicable.
- if (!p2p_file_id_.empty())
- CloseP2PSharingFd(true);
- }
- }
-
- // Write the path to the output pipe if we're successful.
- if (code == ErrorCode::kSuccess && HasOutputPipe())
- SetOutputObject(install_plan_);
- processor_->ActionComplete(this, code);
-}
-
-void DownloadActionChromeos::TransferTerminated(HttpFetcher* fetcher) {
- if (code_ != ErrorCode::kSuccess) {
- processor_->ActionComplete(this, code_);
- } else if (payload_->already_applied) {
- LOG(INFO) << "TransferTerminated with ErrorCode::kSuccess when the current "
- "payload has already applied, treating as TransferComplete.";
- TransferComplete(fetcher, true);
- }
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/download_action_chromeos.h b/cros/download_action_chromeos.h
deleted file mode 100644
index 068946a9..00000000
--- a/cros/download_action_chromeos.h
+++ /dev/null
@@ -1,174 +0,0 @@
-//
-// 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_COMMON_DOWNLOAD_ACTION_CHROMEOS_H_
-#define UPDATE_ENGINE_COMMON_DOWNLOAD_ACTION_CHROMEOS_H_
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <memory>
-#include <string>
-
-#include "update_engine/common/action.h"
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/download_action.h"
-#include "update_engine/common/http_fetcher.h"
-#include "update_engine/common/multi_range_http_fetcher.h"
-#include "update_engine/payload_consumer/delta_performer.h"
-#include "update_engine/payload_consumer/install_plan.h"
-
-// The Download Action downloads a specified url to disk. The url should point
-// to an update in a delta payload format. The payload will be piped into a
-// DeltaPerformer that will apply the delta to the disk.
-
-namespace chromeos_update_engine {
-
-class PrefsInterface;
-
-class DownloadActionChromeos : public InstallPlanAction,
- public HttpFetcherDelegate {
- public:
- static std::string StaticType() { return "DownloadActionChromeos"; }
-
- // Takes ownership of the passed in HttpFetcher. Useful for testing.
- // A good calling pattern is:
- // DownloadActionChromeos(prefs, boot_contol, hardware, system_state,
- // new WhateverHttpFetcher, false);
- DownloadActionChromeos(PrefsInterface* prefs,
- BootControlInterface* boot_control,
- HardwareInterface* hardware,
- HttpFetcher* http_fetcher,
- bool interactive);
- ~DownloadActionChromeos() override;
-
- // InstallPlanAction overrides.
- void PerformAction() override;
- void SuspendAction() override;
- void ResumeAction() override;
- void TerminateProcessing() override;
- std::string Type() const override { return StaticType(); }
-
- // Testing
- void SetTestFileWriter(FileWriter* writer) { writer_ = writer; }
-
- int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); }
-
- // HttpFetcherDelegate methods (see http_fetcher.h)
- bool ReceivedBytes(HttpFetcher* fetcher,
- const void* bytes,
- size_t length) override;
- void SeekToOffset(off_t offset) override;
- void TransferComplete(HttpFetcher* fetcher, bool successful) override;
- void TransferTerminated(HttpFetcher* fetcher) override;
-
- DownloadActionDelegate* delegate() const { return delegate_; }
- void set_delegate(DownloadActionDelegate* delegate) { delegate_ = delegate; }
-
- void set_base_offset(int64_t base_offset) { base_offset_ = base_offset; }
-
- HttpFetcher* http_fetcher() { return http_fetcher_.get(); }
-
- // Returns the p2p file id for the file being written or the empty
- // string if we're not writing to a p2p file.
- std::string p2p_file_id() { return p2p_file_id_; }
-
- private:
- // Closes the file descriptor for the p2p file being written and
- // clears |p2p_file_id_| to indicate that we're no longer sharing
- // the file. If |delete_p2p_file| is True, also deletes the file.
- // If there is no p2p file descriptor, this method does nothing.
- void CloseP2PSharingFd(bool delete_p2p_file);
-
- // Starts sharing the p2p file. Must be called before
- // WriteToP2PFile(). Returns True if this worked.
- bool SetupP2PSharingFd();
-
- // Writes |length| bytes of payload from |data| into |file_offset|
- // of the p2p file. Also does validation checks; for example ensures we
- // don't end up with a file with holes in it.
- //
- // This method does nothing if SetupP2PSharingFd() hasn't been
- // called or if CloseP2PSharingFd() has been called.
- void WriteToP2PFile(const void* data, size_t length, off_t file_offset);
-
- // Attempt to load cached manifest data from prefs
- // return true on success, false otherwise.
- bool LoadCachedManifest(int64_t manifest_size);
-
- // Start downloading the current payload using delta_performer.
- void StartDownloading();
-
- // Pointer to the current payload in install_plan_.payloads.
- InstallPlan::Payload* payload_{nullptr};
-
- PrefsInterface* prefs_;
- BootControlInterface* boot_control_;
- HardwareInterface* hardware_;
-
- // Pointer to the MultiRangeHttpFetcher that does the http work.
- std::unique_ptr<MultiRangeHttpFetcher> http_fetcher_;
-
- // If |true|, the update is user initiated (vs. periodic update checks). Hence
- // the |delta_performer_| can decide not to use O_DSYNC flag for faster
- // update.
- bool interactive_;
-
- // The FileWriter that downloaded data should be written to. It will
- // either point to *decompressing_file_writer_ or *delta_performer_.
- FileWriter* writer_;
-
- std::unique_ptr<DeltaPerformer> delta_performer_;
-
- // Used by TransferTerminated to figure if this action terminated itself or
- // was terminated by the action processor.
- ErrorCode code_;
-
- // For reporting status to outsiders
- DownloadActionDelegate* delegate_;
- uint64_t bytes_received_{0}; // per file/range
- uint64_t bytes_received_previous_payloads_{0};
- uint64_t bytes_total_{0};
- bool download_active_{false};
-
- // The file-id for the file we're sharing or the empty string
- // if we're not using p2p to share.
- std::string p2p_file_id_;
-
- // The file descriptor for the p2p file used for caching the payload or -1
- // if we're not using p2p to share.
- int p2p_sharing_fd_;
-
- // Set to |false| if p2p file is not visible.
- bool p2p_visible_;
-
- // Loaded from prefs before downloading any payload.
- size_t resume_payload_index_{0};
-
- // Offset of the payload in the download URL, used by UpdateAttempterAndroid.
- int64_t base_offset_{0};
-
- DISALLOW_COPY_AND_ASSIGN(DownloadActionChromeos);
-};
-
-// We want to be sure that we're compiled with large file support on linux,
-// just in case we find ourselves downloading large images.
-static_assert(8 == sizeof(off_t), "off_t not 64 bit");
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_COMMON_DOWNLOAD_ACTION_CHROMEOS_H_
diff --git a/cros/download_action_chromeos_unittest.cc b/cros/download_action_chromeos_unittest.cc
deleted file mode 100644
index 93c39ff4..00000000
--- a/cros/download_action_chromeos_unittest.cc
+++ /dev/null
@@ -1,697 +0,0 @@
-//
-// Copyright (C) 2011 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 <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/files/file_path.h>
-#include <base/files/file_util.h>
-#include <base/location.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-
-#include "update_engine/common/action_pipe.h"
-#include "update_engine/common/hash_calculator.h"
-#include "update_engine/common/mock_download_action.h"
-#include "update_engine/common/mock_http_fetcher.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/download_action_chromeos.h"
-#include "update_engine/cros/fake_p2p_manager_configuration.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/payload_consumer/mock_file_writer.h"
-#include "update_engine/update_manager/fake_update_manager.h"
-
-namespace chromeos_update_engine {
-
-using base::FilePath;
-using base::ReadFileToString;
-using base::WriteFile;
-using std::string;
-using std::unique_ptr;
-using testing::_;
-using testing::AtLeast;
-using testing::InSequence;
-using testing::Return;
-using testing::SetArgPointee;
-
-class DownloadActionChromeosTest : public ::testing::Test {
- void SetUp() { FakeSystemState::CreateInstance(); }
-};
-
-namespace {
-
-class DownloadActionTestProcessorDelegate : public ActionProcessorDelegate {
- public:
- DownloadActionTestProcessorDelegate()
- : processing_done_called_(false), expected_code_(ErrorCode::kSuccess) {}
- ~DownloadActionTestProcessorDelegate() override {
- EXPECT_TRUE(processing_done_called_);
- }
- void ProcessingDone(const ActionProcessor* processor,
- ErrorCode code) override {
- brillo::MessageLoop::current()->BreakLoop();
- brillo::Blob found_data;
- ASSERT_TRUE(utils::ReadFile(path_, &found_data));
- if (expected_code_ != ErrorCode::kDownloadWriteError) {
- ASSERT_EQ(expected_data_.size(), found_data.size());
- for (unsigned i = 0; i < expected_data_.size(); i++) {
- EXPECT_EQ(expected_data_[i], found_data[i]);
- }
- }
- processing_done_called_ = true;
- }
-
- void ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) override {
- const string type = action->Type();
- if (type == DownloadActionChromeos::StaticType()) {
- EXPECT_EQ(expected_code_, code);
- p2p_file_id_ =
- static_cast<DownloadActionChromeos*>(action)->p2p_file_id();
- } else {
- EXPECT_EQ(ErrorCode::kSuccess, code);
- }
- }
-
- string path_;
- brillo::Blob expected_data_;
- bool processing_done_called_;
- ErrorCode expected_code_;
- string p2p_file_id_;
-};
-
-class TestDirectFileWriter : public DirectFileWriter {
- public:
- TestDirectFileWriter() : fail_write_(0), current_write_(0) {}
- void set_fail_write(int fail_write) { fail_write_ = fail_write; }
-
- virtual bool Write(const void* bytes, size_t count) {
- if (++current_write_ == fail_write_) {
- return false;
- }
- return DirectFileWriter::Write(bytes, count);
- }
-
- private:
- // If positive, fail on the |fail_write_| call to Write.
- int fail_write_;
- int current_write_;
-};
-
-void StartProcessorInRunLoop(ActionProcessor* processor,
- MockHttpFetcher* http_fetcher) {
- processor->StartProcessing();
- http_fetcher->SetOffset(1);
-}
-
-void TestWithData(const brillo::Blob& data,
- int fail_write,
- bool use_download_delegate) {
- FakeSystemState::CreateInstance();
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
-
- ScopedTempFile output_temp_file;
- TestDirectFileWriter writer;
- EXPECT_EQ(
- 0, writer.Open(output_temp_file.path().c_str(), O_WRONLY | O_CREAT, 0));
- writer.set_fail_write(fail_write);
-
- uint64_t size = data.size() - 1;
- InstallPlan install_plan;
- install_plan.payloads.push_back(
- {.size = size, .type = InstallPayloadType::kDelta});
- // We pull off the first byte from data and seek past it.
- EXPECT_TRUE(HashCalculator::RawHashOfBytes(
- &data[1], data.size() - 1, &install_plan.payloads[0].hash));
- install_plan.source_slot = 0;
- install_plan.target_slot = 1;
- // We mark both slots as bootable. Only the target slot should be unbootable
- // after the download starts.
- FakeSystemState::Get()->fake_boot_control()->SetSlotBootable(
- install_plan.source_slot, true);
- FakeSystemState::Get()->fake_boot_control()->SetSlotBootable(
- install_plan.target_slot, true);
- auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
- feeder_action->set_obj(install_plan);
- MockPrefs prefs;
- MockHttpFetcher* http_fetcher =
- new MockHttpFetcher(data.data(), data.size(), nullptr);
- // takes ownership of passed in HttpFetcher
- auto download_action = std::make_unique<DownloadActionChromeos>(
- &prefs,
- FakeSystemState::Get()->boot_control(),
- FakeSystemState::Get()->hardware(),
- http_fetcher,
- false /* interactive */);
- download_action->SetTestFileWriter(&writer);
- BondActions(feeder_action.get(), download_action.get());
- MockDownloadActionDelegate download_delegate;
- if (use_download_delegate) {
- InSequence s;
- download_action->set_delegate(&download_delegate);
- if (data.size() > kMockHttpFetcherChunkSize)
- EXPECT_CALL(download_delegate,
- BytesReceived(_, kMockHttpFetcherChunkSize, _));
- EXPECT_CALL(download_delegate, BytesReceived(_, _, _)).Times(AtLeast(1));
- EXPECT_CALL(download_delegate, DownloadComplete())
- .Times(fail_write == 0 ? 1 : 0);
- }
- DownloadActionTestProcessorDelegate delegate;
- delegate.expected_code_ =
- (fail_write > 0) ? ErrorCode::kDownloadWriteError : ErrorCode::kSuccess;
- delegate.expected_data_ = brillo::Blob(data.begin() + 1, data.end());
- delegate.path_ = output_temp_file.path();
- ActionProcessor processor;
- processor.set_delegate(&delegate);
- processor.EnqueueAction(std::move(feeder_action));
- processor.EnqueueAction(std::move(download_action));
-
- loop.PostTask(FROM_HERE,
- base::Bind(&StartProcessorInRunLoop, &processor, http_fetcher));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
-
- EXPECT_TRUE(FakeSystemState::Get()->fake_boot_control()->IsSlotBootable(
- install_plan.source_slot));
- EXPECT_FALSE(FakeSystemState::Get()->fake_boot_control()->IsSlotBootable(
- install_plan.target_slot));
-}
-} // namespace
-
-TEST(DownloadActionTest, SimpleTest) {
- brillo::Blob small;
- const char* foo = "foo";
- small.insert(small.end(), foo, foo + strlen(foo));
- TestWithData(small,
- 0, // fail_write
- true); // use_download_delegate
-}
-
-TEST(DownloadActionTest, LargeTest) {
- brillo::Blob big(5 * kMockHttpFetcherChunkSize);
- char c = '0';
- for (unsigned int i = 0; i < big.size(); i++) {
- big[i] = c;
- c = ('9' == c) ? '0' : c + 1;
- }
- TestWithData(big,
- 0, // fail_write
- true); // use_download_delegate
-}
-
-TEST(DownloadActionTest, FailWriteTest) {
- brillo::Blob big(5 * kMockHttpFetcherChunkSize);
- char c = '0';
- for (unsigned int i = 0; i < big.size(); i++) {
- big[i] = c;
- c = ('9' == c) ? '0' : c + 1;
- }
- TestWithData(big,
- 2, // fail_write
- true); // use_download_delegate
-}
-
-TEST(DownloadActionTest, NoDownloadDelegateTest) {
- brillo::Blob small;
- const char* foo = "foofoo";
- small.insert(small.end(), foo, foo + strlen(foo));
- TestWithData(small,
- 0, // fail_write
- false); // use_download_delegate
-}
-
-TEST(DownloadActionTest, MultiPayloadProgressTest) {
- std::vector<brillo::Blob> payload_datas;
- // the first payload must be the largest, as it's the actual payload used by
- // the MockHttpFetcher for all downloaded data.
- payload_datas.emplace_back(4 * kMockHttpFetcherChunkSize + 256);
- payload_datas.emplace_back(2 * kMockHttpFetcherChunkSize);
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(), NextPayload())
- .WillOnce(Return(true));
-
- MockFileWriter mock_file_writer;
- EXPECT_CALL(mock_file_writer, Close()).WillRepeatedly(Return(0));
- EXPECT_CALL(mock_file_writer, Write(_, _, _))
- .WillRepeatedly(
- DoAll(SetArgPointee<2>(ErrorCode::kSuccess), Return(true)));
-
- InstallPlan install_plan;
- uint64_t total_expected_download_size{0};
- for (const auto& data : payload_datas) {
- uint64_t size = data.size();
- install_plan.payloads.push_back(
- {.size = size, .type = InstallPayloadType::kFull});
- total_expected_download_size += size;
- }
- auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
- feeder_action->set_obj(install_plan);
- MockPrefs prefs;
- MockHttpFetcher* http_fetcher = new MockHttpFetcher(
- payload_datas[0].data(), payload_datas[0].size(), nullptr);
- // takes ownership of passed in HttpFetcher
- auto download_action = std::make_unique<DownloadActionChromeos>(
- &prefs,
- FakeSystemState::Get()->boot_control(),
- FakeSystemState::Get()->hardware(),
- http_fetcher,
- false /* interactive */);
- download_action->SetTestFileWriter(&mock_file_writer);
- BondActions(feeder_action.get(), download_action.get());
- MockDownloadActionDelegate download_delegate;
- {
- InSequence s;
- download_action->set_delegate(&download_delegate);
- // these are hand-computed based on the payloads specified above
- EXPECT_CALL(download_delegate,
- BytesReceived(kMockHttpFetcherChunkSize,
- kMockHttpFetcherChunkSize,
- total_expected_download_size));
- EXPECT_CALL(download_delegate,
- BytesReceived(kMockHttpFetcherChunkSize,
- kMockHttpFetcherChunkSize * 2,
- total_expected_download_size));
- EXPECT_CALL(download_delegate,
- BytesReceived(kMockHttpFetcherChunkSize,
- kMockHttpFetcherChunkSize * 3,
- total_expected_download_size));
- EXPECT_CALL(download_delegate,
- BytesReceived(kMockHttpFetcherChunkSize,
- kMockHttpFetcherChunkSize * 4,
- total_expected_download_size));
- EXPECT_CALL(download_delegate,
- BytesReceived(256,
- kMockHttpFetcherChunkSize * 4 + 256,
- total_expected_download_size));
- EXPECT_CALL(download_delegate,
- BytesReceived(kMockHttpFetcherChunkSize,
- kMockHttpFetcherChunkSize * 5 + 256,
- total_expected_download_size));
- EXPECT_CALL(download_delegate,
- BytesReceived(kMockHttpFetcherChunkSize,
- total_expected_download_size,
- total_expected_download_size));
- }
- ActionProcessor processor;
- processor.EnqueueAction(std::move(feeder_action));
- processor.EnqueueAction(std::move(download_action));
-
- loop.PostTask(
- FROM_HERE,
- base::Bind(
- [](ActionProcessor* processor) { processor->StartProcessing(); },
- base::Unretained(&processor)));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
-}
-
-namespace {
-class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
- public:
- void ProcessingStopped(const ActionProcessor* processor) {
- brillo::MessageLoop::current()->BreakLoop();
- }
-};
-
-void TerminateEarlyTestStarter(ActionProcessor* processor) {
- processor->StartProcessing();
- CHECK(processor->IsRunning());
- processor->StopProcessing();
-}
-
-void TestTerminateEarly(bool use_download_delegate) {
- FakeSystemState::CreateInstance();
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
-
- brillo::Blob data(kMockHttpFetcherChunkSize + kMockHttpFetcherChunkSize / 2);
- memset(data.data(), 0, data.size());
-
- ScopedTempFile temp_file;
- {
- DirectFileWriter writer;
- EXPECT_EQ(0, writer.Open(temp_file.path().c_str(), O_WRONLY | O_CREAT, 0));
-
- // takes ownership of passed in HttpFetcher
- auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
- InstallPlan install_plan;
- install_plan.payloads.resize(1);
- feeder_action->set_obj(install_plan);
-
- MockPrefs prefs;
- auto download_action = std::make_unique<DownloadAction>(
- &prefs,
- FakeSystemState::Get()->boot_control(),
- FakeSystemState::Get()->hardware(),
- new MockHttpFetcher(data.data(), data.size(), nullptr),
- false /* interactive */);
- download_action->SetTestFileWriter(&writer);
- MockDownloadActionDelegate download_delegate;
- if (use_download_delegate) {
- download_action->set_delegate(&download_delegate);
- EXPECT_CALL(download_delegate, BytesReceived(_, _, _)).Times(0);
- }
- TerminateEarlyTestProcessorDelegate delegate;
- ActionProcessor processor;
- processor.set_delegate(&delegate);
- BondActions(feeder_action.get(), download_action.get());
- processor.EnqueueAction(std::move(feeder_action));
- processor.EnqueueAction(std::move(download_action));
-
- loop.PostTask(FROM_HERE,
- base::Bind(&TerminateEarlyTestStarter, &processor));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
- }
-
- // 1 or 0 chunks should have come through
- const off_t resulting_file_size(utils::FileSize(temp_file.path()));
- EXPECT_GE(resulting_file_size, 0);
- if (resulting_file_size != 0)
- EXPECT_EQ(kMockHttpFetcherChunkSize,
- static_cast<size_t>(resulting_file_size));
-}
-
-} // namespace
-
-TEST(DownloadActionTest, TerminateEarlyTest) {
- TestTerminateEarly(true);
-}
-
-TEST(DownloadActionTest, TerminateEarlyNoDownloadDelegateTest) {
- TestTerminateEarly(false);
-}
-
-class DownloadActionTestAction;
-
-template <>
-class ActionTraits<DownloadActionTestAction> {
- public:
- typedef InstallPlan OutputObjectType;
- typedef InstallPlan InputObjectType;
-};
-
-// This is a simple Action class for testing.
-class DownloadActionTestAction : public Action<DownloadActionTestAction> {
- public:
- DownloadActionTestAction() = default;
- typedef InstallPlan InputObjectType;
- typedef InstallPlan OutputObjectType;
- ActionPipe<InstallPlan>* in_pipe() { return in_pipe_.get(); }
- ActionPipe<InstallPlan>* out_pipe() { return out_pipe_.get(); }
- ActionProcessor* processor() { return processor_; }
- void PerformAction() {
- ASSERT_TRUE(HasInputObject());
- EXPECT_TRUE(expected_input_object_ == GetInputObject());
- ASSERT_TRUE(processor());
- processor()->ActionComplete(this, ErrorCode::kSuccess);
- }
- static std::string StaticType() { return "DownloadActionTestAction"; }
- string Type() const { return StaticType(); }
- InstallPlan expected_input_object_;
-};
-
-namespace {
-// This class is an ActionProcessorDelegate that simply terminates the
-// run loop when the ActionProcessor has completed processing. It's used
-// only by the test PassObjectOutTest.
-class PassObjectOutTestProcessorDelegate : public ActionProcessorDelegate {
- public:
- void ProcessingDone(const ActionProcessor* processor,
- ErrorCode code) override {
- brillo::MessageLoop::current()->BreakLoop();
- }
- void ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) override {
- if (action->Type() == DownloadActionTestAction::StaticType()) {
- did_test_action_run_ = true;
- }
- }
-
- bool did_test_action_run_ = false;
-};
-
-} // namespace
-
-TEST(DownloadActionTest, PassObjectOutTest) {
- FakeSystemState::CreateInstance();
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
-
- DirectFileWriter writer;
- EXPECT_EQ(0, writer.Open("/dev/null", O_WRONLY | O_CREAT, 0));
-
- // takes ownership of passed in HttpFetcher
- InstallPlan install_plan;
- install_plan.payloads.push_back({.size = 1});
- EXPECT_TRUE(
- HashCalculator::RawHashOfData({'x'}, &install_plan.payloads[0].hash));
- auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
- feeder_action->set_obj(install_plan);
- MockPrefs prefs;
- auto download_action =
- std::make_unique<DownloadAction>(&prefs,
- FakeSystemState::Get()->boot_control(),
- FakeSystemState::Get()->hardware(),
- new MockHttpFetcher("x", 1, nullptr),
- false /* interactive */);
- download_action->SetTestFileWriter(&writer);
-
- auto test_action = std::make_unique<DownloadActionTestAction>();
- test_action->expected_input_object_ = install_plan;
- BondActions(feeder_action.get(), download_action.get());
- BondActions(download_action.get(), test_action.get());
-
- ActionProcessor processor;
- PassObjectOutTestProcessorDelegate delegate;
- processor.set_delegate(&delegate);
- processor.EnqueueAction(std::move(feeder_action));
- processor.EnqueueAction(std::move(download_action));
- processor.EnqueueAction(std::move(test_action));
-
- loop.PostTask(
- FROM_HERE,
- base::Bind(
- [](ActionProcessor* processor) { processor->StartProcessing(); },
- base::Unretained(&processor)));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
-
- EXPECT_EQ(true, delegate.did_test_action_run_);
-}
-
-// Test fixture for P2P tests.
-class P2PDownloadActionTest : public testing::Test {
- protected:
- P2PDownloadActionTest() : start_at_offset_(0) {}
-
- ~P2PDownloadActionTest() override {}
-
- // Derived from testing::Test.
- void SetUp() override {
- loop_.SetAsCurrent();
- FakeSystemState::CreateInstance();
- }
-
- // Derived from testing::Test.
- void TearDown() override { EXPECT_FALSE(loop_.PendingTasks()); }
-
- // To be called by tests to setup the download. The
- // |starting_offset| parameter is for where to resume.
- void SetupDownload(off_t starting_offset) {
- start_at_offset_ = starting_offset;
- // Prepare data 10 kB of data.
- data_.clear();
- for (unsigned int i = 0; i < 10 * 1000; i++)
- data_ += 'a' + (i % 25);
-
- // Setup p2p.
- FakeP2PManagerConfiguration* test_conf = new FakeP2PManagerConfiguration();
- p2p_manager_.reset(P2PManager::Construct(
- test_conf, &fake_um_, "cros_au", 3, base::TimeDelta::FromDays(5)));
- }
-
- // To be called by tests to perform the download. The
- // |use_p2p_to_share| parameter is used to indicate whether the
- // payload should be shared via p2p.
- void StartDownload(bool use_p2p_to_share) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- GetUsingP2PForSharing())
- .WillRepeatedly(Return(use_p2p_to_share));
-
- ScopedTempFile output_temp_file;
- TestDirectFileWriter writer;
- EXPECT_EQ(
- 0, writer.Open(output_temp_file.path().c_str(), O_WRONLY | O_CREAT, 0));
- InstallPlan install_plan;
- install_plan.payloads.push_back(
- {.size = data_.length(),
- .hash = {'1', '2', '3', '4', 'h', 'a', 's', 'h'}});
- auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
- feeder_action->set_obj(install_plan);
- MockPrefs prefs;
- // Note that DownloadAction takes ownership of the passed in HttpFetcher.
- auto download_action = std::make_unique<DownloadAction>(
- &prefs,
- FakeSystemState::Get()->boot_control(),
- FakeSystemState::Get()->hardware(),
- new MockHttpFetcher(data_.c_str(), data_.length(), nullptr),
- false /* interactive */);
- auto http_fetcher = download_action->http_fetcher();
- download_action->SetTestFileWriter(&writer);
- BondActions(feeder_action.get(), download_action.get());
- delegate_.expected_data_ =
- brillo::Blob(data_.begin() + start_at_offset_, data_.end());
- delegate_.path_ = output_temp_file.path();
- processor_.set_delegate(&delegate_);
- processor_.EnqueueAction(std::move(feeder_action));
- processor_.EnqueueAction(std::move(download_action));
-
- loop_.PostTask(
- FROM_HERE,
- base::Bind(
- [](P2PDownloadActionTest* action_test, HttpFetcher* http_fetcher) {
- action_test->processor_.StartProcessing();
- http_fetcher->SetOffset(action_test->start_at_offset_);
- },
- base::Unretained(this),
- base::Unretained(http_fetcher)));
- loop_.Run();
- }
-
- // Mainloop used to make StartDownload() synchronous.
- brillo::FakeMessageLoop loop_{nullptr};
-
- // Delegate that is passed to the ActionProcessor.
- DownloadActionTestProcessorDelegate delegate_;
-
- // The P2PManager used in the test.
- unique_ptr<P2PManager> p2p_manager_;
-
- // The ActionProcessor used for running the actions.
- ActionProcessor processor_;
-
- // The data being downloaded.
- string data_;
-
- private:
- // The requested starting offset passed to SetupDownload().
- off_t start_at_offset_;
-
- chromeos_update_manager::FakeUpdateManager fake_um_;
-};
-
-TEST_F(P2PDownloadActionTest, IsWrittenTo) {
- SetupDownload(0); // starting_offset
- StartDownload(true); // use_p2p_to_share
-
- // Check the p2p file and its content matches what was sent.
- string file_id = delegate_.p2p_file_id_;
- EXPECT_NE("", file_id);
- EXPECT_EQ(static_cast<int>(data_.length()),
- p2p_manager_->FileGetSize(file_id));
- EXPECT_EQ(static_cast<int>(data_.length()),
- p2p_manager_->FileGetExpectedSize(file_id));
- string p2p_file_contents;
- EXPECT_TRUE(
- ReadFileToString(p2p_manager_->FileGetPath(file_id), &p2p_file_contents));
- EXPECT_EQ(data_, p2p_file_contents);
-}
-
-TEST_F(P2PDownloadActionTest, DeleteIfHoleExists) {
- SetupDownload(1000); // starting_offset
- StartDownload(true); // use_p2p_to_share
-
- // DownloadAction should convey that the file is not being shared.
- // and that we don't have any p2p files.
- EXPECT_EQ(delegate_.p2p_file_id_, "");
- EXPECT_EQ(p2p_manager_->CountSharedFiles(), 0);
-}
-
-TEST_F(P2PDownloadActionTest, CanAppend) {
- SetupDownload(1000); // starting_offset
-
- // Prepare the file with existing data before starting to write to
- // it via DownloadAction.
- string file_id = utils::CalculateP2PFileId(
- {'1', '2', '3', '4', 'h', 'a', 's', 'h'}, data_.length());
- ASSERT_TRUE(p2p_manager_->FileShare(file_id, data_.length()));
- string existing_data;
- for (unsigned int i = 0; i < 1000; i++)
- existing_data += '0' + (i % 10);
- ASSERT_EQ(
- WriteFile(
- p2p_manager_->FileGetPath(file_id), existing_data.c_str(), 1000),
- 1000);
-
- StartDownload(true); // use_p2p_to_share
-
- // DownloadAction should convey the same file_id and the file should
- // have the expected size.
- EXPECT_EQ(delegate_.p2p_file_id_, file_id);
- EXPECT_EQ(static_cast<ssize_t>(data_.length()),
- p2p_manager_->FileGetSize(file_id));
- EXPECT_EQ(static_cast<ssize_t>(data_.length()),
- p2p_manager_->FileGetExpectedSize(file_id));
- string p2p_file_contents;
- // Check that the first 1000 bytes wasn't touched and that we
- // appended the remaining as appropriate.
- EXPECT_TRUE(
- ReadFileToString(p2p_manager_->FileGetPath(file_id), &p2p_file_contents));
- EXPECT_EQ(existing_data, p2p_file_contents.substr(0, 1000));
- EXPECT_EQ(data_.substr(1000), p2p_file_contents.substr(1000));
-}
-
-TEST_F(P2PDownloadActionTest, DeletePartialP2PFileIfResumingWithoutP2P) {
- SetupDownload(1000); // starting_offset
-
- // Prepare the file with all existing data before starting to write
- // to it via DownloadAction.
- string file_id = utils::CalculateP2PFileId(
- {'1', '2', '3', '4', 'h', 'a', 's', 'h'}, data_.length());
- ASSERT_TRUE(p2p_manager_->FileShare(file_id, data_.length()));
- string existing_data;
- for (unsigned int i = 0; i < 1000; i++)
- existing_data += '0' + (i % 10);
- ASSERT_EQ(
- WriteFile(
- p2p_manager_->FileGetPath(file_id), existing_data.c_str(), 1000),
- 1000);
-
- // Check that the file is there.
- EXPECT_EQ(1000, p2p_manager_->FileGetSize(file_id));
- EXPECT_EQ(1, p2p_manager_->CountSharedFiles());
-
- StartDownload(false); // use_p2p_to_share
-
- // DownloadAction should have deleted the p2p file. Check that it's gone.
- EXPECT_EQ(-1, p2p_manager_->FileGetSize(file_id));
- EXPECT_EQ(0, p2p_manager_->CountSharedFiles());
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/excluder_chromeos.cc b/cros/excluder_chromeos.cc
deleted file mode 100644
index 35154d6a..00000000
--- a/cros/excluder_chromeos.cc
+++ /dev/null
@@ -1,63 +0,0 @@
-//
-// 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/cros/excluder_chromeos.h"
-
-#include <memory>
-#include <vector>
-
-#include <base/logging.h>
-#include <base/strings/string_piece.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_split.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/system_state.h"
-
-using std::string;
-using std::vector;
-
-namespace chromeos_update_engine {
-
-std::unique_ptr<ExcluderInterface> CreateExcluder() {
- return std::make_unique<ExcluderChromeOS>();
-}
-
-bool ExcluderChromeOS::Exclude(const string& name) {
- auto* prefs = SystemState::Get()->prefs();
- auto key = prefs->CreateSubKey({kExclusionPrefsSubDir, name});
- return prefs->SetString(key, "");
-}
-
-bool ExcluderChromeOS::IsExcluded(const string& name) {
- auto* prefs = SystemState::Get()->prefs();
- auto key = prefs->CreateSubKey({kExclusionPrefsSubDir, name});
- return prefs->Exists(key);
-}
-
-bool ExcluderChromeOS::Reset() {
- auto* prefs = SystemState::Get()->prefs();
- bool ret = true;
- vector<string> keys;
- if (!prefs->GetSubKeys(kExclusionPrefsSubDir, &keys))
- return false;
- for (const auto& key : keys)
- if (!(ret &= prefs->Delete(key)))
- LOG(ERROR) << "Failed to delete exclusion pref for " << key;
- return ret;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/excluder_chromeos.h b/cros/excluder_chromeos.h
deleted file mode 100644
index 7d3efc9e..00000000
--- a/cros/excluder_chromeos.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// 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_CROS_EXCLUDER_CHROMEOS_H_
-#define UPDATE_ENGINE_CROS_EXCLUDER_CHROMEOS_H_
-
-#include <string>
-
-#include "update_engine/common/excluder_interface.h"
-#include "update_engine/common/prefs_interface.h"
-
-namespace chromeos_update_engine {
-
-class SystemState;
-
-// The Chrome OS implementation of the |ExcluderInterface|.
-class ExcluderChromeOS : public ExcluderInterface {
- public:
- ExcluderChromeOS() = default;
- ~ExcluderChromeOS() = default;
-
- // |ExcluderInterface| overrides.
- bool Exclude(const std::string& name) override;
- bool IsExcluded(const std::string& name) override;
- bool Reset() override;
-
- // Not copyable or movable.
- ExcluderChromeOS(const ExcluderChromeOS&) = delete;
- ExcluderChromeOS& operator=(const ExcluderChromeOS&) = delete;
- ExcluderChromeOS(ExcluderChromeOS&&) = delete;
- ExcluderChromeOS& operator=(ExcluderChromeOS&&) = delete;
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_EXCLUDER_CHROMEOS_H_
diff --git a/cros/excluder_chromeos_unittest.cc b/cros/excluder_chromeos_unittest.cc
deleted file mode 100644
index fd708186..00000000
--- a/cros/excluder_chromeos_unittest.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// 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/cros/excluder_chromeos.h"
-
-#include <gtest/gtest.h>
-
-#include "update_engine/cros/fake_system_state.h"
-
-namespace chromeos_update_engine {
-
-namespace {
-constexpr char kFakeHash[] =
- "71ff43d76e2488e394e46872f5b066cc25e394c2c3e3790dd319517883b33db1";
-} // namespace
-
-class ExcluderChromeOSTest : public ::testing::Test {
- protected:
- void SetUp() override { FakeSystemState::CreateInstance(); }
-
- ExcluderChromeOS excluder_;
-};
-
-TEST_F(ExcluderChromeOSTest, ExclusionCheck) {
- EXPECT_FALSE(excluder_.IsExcluded(kFakeHash));
- EXPECT_TRUE(excluder_.Exclude(kFakeHash));
- EXPECT_TRUE(excluder_.IsExcluded(kFakeHash));
-}
-
-TEST_F(ExcluderChromeOSTest, ResetFlow) {
- EXPECT_TRUE(excluder_.Exclude("abc"));
- EXPECT_TRUE(excluder_.Exclude(kFakeHash));
- EXPECT_TRUE(excluder_.IsExcluded("abc"));
- EXPECT_TRUE(excluder_.IsExcluded(kFakeHash));
-
- EXPECT_TRUE(excluder_.Reset());
- EXPECT_FALSE(excluder_.IsExcluded("abc"));
- EXPECT_FALSE(excluder_.IsExcluded(kFakeHash));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/fake_p2p_manager.h b/cros/fake_p2p_manager.h
deleted file mode 100644
index 1011b7ed..00000000
--- a/cros/fake_p2p_manager.h
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// Copyright (C) 2013 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_CROS_FAKE_P2P_MANAGER_H_
-#define UPDATE_ENGINE_CROS_FAKE_P2P_MANAGER_H_
-
-#include <string>
-
-#include "update_engine/cros/p2p_manager.h"
-
-namespace chromeos_update_engine {
-
-// A fake implementation of P2PManager.
-class FakeP2PManager : public P2PManager {
- public:
- FakeP2PManager()
- : is_p2p_enabled_(false),
- ensure_p2p_running_result_(false),
- ensure_p2p_not_running_result_(false),
- perform_housekeeping_result_(false),
- count_shared_files_result_(0) {}
-
- // P2PManager overrides.
- void SetDevicePolicy(const policy::DevicePolicy* device_policy) override {}
-
- bool IsP2PEnabled() override { return is_p2p_enabled_; }
-
- bool EnsureP2PRunning() override { return ensure_p2p_running_result_; }
-
- bool EnsureP2PNotRunning() override { return ensure_p2p_not_running_result_; }
-
- bool PerformHousekeeping() override { return perform_housekeeping_result_; }
-
- void LookupUrlForFile(const std::string& file_id,
- size_t minimum_size,
- base::TimeDelta max_time_to_wait,
- LookupCallback callback) override {
- callback.Run(lookup_url_for_file_result_);
- }
-
- bool FileShare(const std::string& file_id, size_t expected_size) override {
- return false;
- }
-
- base::FilePath FileGetPath(const std::string& file_id) override {
- return base::FilePath();
- }
-
- ssize_t FileGetSize(const std::string& file_id) override { return -1; }
-
- ssize_t FileGetExpectedSize(const std::string& file_id) override {
- return -1;
- }
-
- bool FileGetVisible(const std::string& file_id, bool* out_result) override {
- return false;
- }
-
- bool FileMakeVisible(const std::string& file_id) override { return false; }
-
- int CountSharedFiles() override { return count_shared_files_result_; }
-
- // Methods for controlling what the fake returns and how it acts.
- void SetP2PEnabled(bool is_p2p_enabled) { is_p2p_enabled_ = is_p2p_enabled; }
-
- void SetEnsureP2PRunningResult(bool ensure_p2p_running_result) {
- ensure_p2p_running_result_ = ensure_p2p_running_result;
- }
-
- void SetEnsureP2PNotRunningResult(bool ensure_p2p_not_running_result) {
- ensure_p2p_not_running_result_ = ensure_p2p_not_running_result;
- }
-
- void SetPerformHousekeepingResult(bool perform_housekeeping_result) {
- perform_housekeeping_result_ = perform_housekeeping_result;
- }
-
- void SetCountSharedFilesResult(int count_shared_files_result) {
- count_shared_files_result_ = count_shared_files_result;
- }
-
- void SetLookupUrlForFileResult(const std::string& url) {
- lookup_url_for_file_result_ = url;
- }
-
- private:
- bool is_p2p_enabled_;
- bool ensure_p2p_running_result_;
- bool ensure_p2p_not_running_result_;
- bool perform_housekeeping_result_;
- int count_shared_files_result_;
- std::string lookup_url_for_file_result_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeP2PManager);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_FAKE_P2P_MANAGER_H_
diff --git a/cros/fake_p2p_manager_configuration.h b/cros/fake_p2p_manager_configuration.h
deleted file mode 100644
index 8d50ac85..00000000
--- a/cros/fake_p2p_manager_configuration.h
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// Copyright (C) 2013 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_CROS_FAKE_P2P_MANAGER_CONFIGURATION_H_
-#define UPDATE_ENGINE_CROS_FAKE_P2P_MANAGER_CONFIGURATION_H_
-
-#include "update_engine/cros/p2p_manager.h"
-
-#include <string>
-#include <vector>
-
-#include <base/files/scoped_temp_dir.h>
-#include <base/strings/string_util.h>
-#include <gtest/gtest.h>
-
-namespace chromeos_update_engine {
-
-// Configuration for P2PManager for use in unit tests. Instead of
-// /var/cache/p2p, a temporary directory is used.
-class FakeP2PManagerConfiguration : public P2PManager::Configuration {
- public:
- FakeP2PManagerConfiguration() { EXPECT_TRUE(p2p_dir_.CreateUniqueTempDir()); }
-
- // P2PManager::Configuration override
- base::FilePath GetP2PDir() override { return p2p_dir_.GetPath(); }
-
- // P2PManager::Configuration override
- std::vector<std::string> GetInitctlArgs(bool is_start) override {
- return is_start ? initctl_start_args_ : initctl_stop_args_;
- }
-
- // P2PManager::Configuration override
- std::vector<std::string> GetP2PClientArgs(const std::string& file_id,
- size_t minimum_size) override {
- std::vector<std::string> formatted_command = p2p_client_cmd_format_;
- // Replace {variable} on the passed string.
- std::string str_minimum_size = std::to_string(minimum_size);
- for (std::string& arg : formatted_command) {
- base::ReplaceSubstringsAfterOffset(&arg, 0, "{file_id}", file_id);
- base::ReplaceSubstringsAfterOffset(
- &arg, 0, "{minsize}", str_minimum_size);
- }
- return formatted_command;
- }
-
- // Use |command_line| instead of "initctl start p2p" when attempting
- // to start the p2p service.
- void SetInitctlStartCommand(const std::vector<std::string>& command) {
- initctl_start_args_ = command;
- }
-
- // Use |command_line| instead of "initctl stop p2p" when attempting
- // to stop the p2p service.
- void SetInitctlStopCommand(const std::vector<std::string>& command) {
- initctl_stop_args_ = command;
- }
-
- // Use |command_format| instead of "p2p-client --get-url={file_id}
- // --minimum-size={minsize}" when attempting to look up a file using
- // p2p-client(1).
- //
- // The passed |command_format| argument can have "{file_id}" and "{minsize}"
- // as substrings of any of its elements, that will be replaced by the
- // corresponding values passed to GetP2PClientArgs().
- void SetP2PClientCommand(const std::vector<std::string>& command_format) {
- p2p_client_cmd_format_ = command_format;
- }
-
- private:
- // The temporary directory used for p2p.
- base::ScopedTempDir p2p_dir_;
-
- // Argument vector for starting p2p.
- std::vector<std::string> initctl_start_args_{"initctl", "start", "p2p"};
-
- // Argument vector for stopping p2p.
- std::vector<std::string> initctl_stop_args_{"initctl", "stop", "p2p"};
-
- // A string for generating the p2p-client command. See the
- // SetP2PClientCommandLine() for details.
- std::vector<std::string> p2p_client_cmd_format_{
- "p2p-client", "--get-url={file_id}", "--minimum-size={minsize}"};
-
- DISALLOW_COPY_AND_ASSIGN(FakeP2PManagerConfiguration);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_FAKE_P2P_MANAGER_CONFIGURATION_H_
diff --git a/cros/fake_shill_proxy.cc b/cros/fake_shill_proxy.cc
deleted file mode 100644
index 2d05a6b1..00000000
--- a/cros/fake_shill_proxy.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// Copyright (C) 2015 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/cros/fake_shill_proxy.h"
-
-#include <utility>
-
-using org::chromium::flimflam::ManagerProxyMock;
-using org::chromium::flimflam::ServiceProxyInterface;
-
-namespace chromeos_update_engine {
-
-FakeShillProxy::FakeShillProxy()
- : manager_proxy_mock_(new ManagerProxyMock()) {}
-
-ManagerProxyMock* FakeShillProxy::GetManagerProxy() {
- return manager_proxy_mock_.get();
-}
-
-std::unique_ptr<ServiceProxyInterface> FakeShillProxy::GetServiceForPath(
- const dbus::ObjectPath& path) {
- auto it = service_proxy_mocks_.find(path.value());
- CHECK(it != service_proxy_mocks_.end())
- << "No ServiceProxyMock set for " << path.value();
- std::unique_ptr<ServiceProxyInterface> result = std::move(it->second);
- service_proxy_mocks_.erase(it);
- return result;
-}
-
-void FakeShillProxy::SetServiceForPath(
- const dbus::ObjectPath& path,
- std::unique_ptr<ServiceProxyInterface> service_proxy) {
- service_proxy_mocks_[path.value()] = std::move(service_proxy);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/fake_shill_proxy.h b/cros/fake_shill_proxy.h
deleted file mode 100644
index 8c15a9dc..00000000
--- a/cros/fake_shill_proxy.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright (C) 2015 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_CROS_FAKE_SHILL_PROXY_H_
-#define UPDATE_ENGINE_CROS_FAKE_SHILL_PROXY_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include <base/macros.h>
-#include <shill/dbus-proxies.h>
-#include <shill/dbus-proxy-mocks.h>
-
-#include "update_engine/cros/shill_proxy_interface.h"
-
-namespace chromeos_update_engine {
-
-// This class implements the connection to shill using real DBus calls.
-class FakeShillProxy : public ShillProxyInterface {
- public:
- FakeShillProxy();
- ~FakeShillProxy() override = default;
-
- // ShillProxyInterface overrides.
-
- // GetManagerProxy returns the subclass ManagerProxyMock so tests can easily
- // use it. Mocks for the return value of GetServiceForPath() can be provided
- // with SetServiceForPath().
- org::chromium::flimflam::ManagerProxyMock* GetManagerProxy() override;
- std::unique_ptr<org::chromium::flimflam::ServiceProxyInterface>
- GetServiceForPath(const dbus::ObjectPath& path) override;
-
- // Sets the service_proxy that will be returned by GetServiceForPath().
- void SetServiceForPath(
- const dbus::ObjectPath& path,
- std::unique_ptr<org::chromium::flimflam::ServiceProxyInterface>
- service_proxy);
-
- private:
- std::unique_ptr<org::chromium::flimflam::ManagerProxyMock>
- manager_proxy_mock_;
-
- std::map<std::string,
- std::unique_ptr<org::chromium::flimflam::ServiceProxyInterface>>
- service_proxy_mocks_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeShillProxy);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_FAKE_SHILL_PROXY_H_
diff --git a/cros/fake_system_state.cc b/cros/fake_system_state.cc
deleted file mode 100644
index 7673b1de..00000000
--- a/cros/fake_system_state.cc
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/fake_system_state.h"
-
-namespace chromeos_update_engine {
-
-// Mock the SystemStateInterface so that we could lie that
-// OOBE is completed even when there's no such marker file, etc.
-FakeSystemState::FakeSystemState()
- : mock_update_attempter_(nullptr),
- clock_(&fake_clock_),
- connection_manager_(&mock_connection_manager_),
- hardware_(&fake_hardware_),
- metrics_reporter_(&mock_metrics_reporter_),
- prefs_(&fake_prefs_),
- powerwash_safe_prefs_(&fake_powerwash_safe_prefs_),
- payload_state_(&mock_payload_state_),
- update_attempter_(&mock_update_attempter_),
- request_params_(&mock_request_params_),
- p2p_manager_(&mock_p2p_manager_),
- update_manager_(&fake_update_manager_),
- device_policy_(nullptr),
- fake_system_rebooted_(false) {
- mock_payload_state_.Initialize();
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/fake_system_state.h b/cros/fake_system_state.h
deleted file mode 100644
index da36306a..00000000
--- a/cros/fake_system_state.h
+++ /dev/null
@@ -1,308 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_FAKE_SYSTEM_STATE_H_
-#define UPDATE_ENGINE_CROS_FAKE_SYSTEM_STATE_H_
-
-#include <memory>
-
-#include <base/logging.h>
-#include <gmock/gmock.h>
-#include <policy/mock_device_policy.h>
-
-#include "metrics/metrics_library_mock.h"
-#include "update_engine/common/fake_boot_control.h"
-#include "update_engine/common/fake_clock.h"
-#include "update_engine/common/fake_hardware.h"
-#include "update_engine/common/fake_prefs.h"
-#include "update_engine/common/mock_metrics_reporter.h"
-#include "update_engine/common/mock_prefs.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/cros/mock_connection_manager.h"
-#include "update_engine/cros/mock_omaha_request_params.h"
-#include "update_engine/cros/mock_p2p_manager.h"
-#include "update_engine/cros/mock_payload_state.h"
-#include "update_engine/cros/mock_power_manager.h"
-#include "update_engine/cros/mock_update_attempter.h"
-#include "update_engine/update_manager/fake_update_manager.h"
-
-namespace chromeos_update_engine {
-
-// Mock the SystemStateInterface so that we could lie that
-// OOBE is completed even when there's no such marker file, etc.
-class FakeSystemState : public SystemState {
- public:
- static void CreateInstance() {
- static std::unique_ptr<FakeSystemState> system_state;
- system_state.reset(new FakeSystemState());
- g_pointer_ = system_state.get();
- }
-
- static FakeSystemState* Get() {
- return reinterpret_cast<FakeSystemState*>(g_pointer_);
- }
-
- // Base class overrides. All getters return the current implementation of
- // various members, either the default (fake/mock) or the one set to override
- // it by client code.
-
- BootControlInterface* boot_control() override { return boot_control_; }
-
- inline ClockInterface* clock() override { return clock_; }
-
- inline void set_device_policy(
- const policy::DevicePolicy* device_policy) override {
- device_policy_ = device_policy;
- }
-
- inline const policy::DevicePolicy* device_policy() override {
- return device_policy_;
- }
-
- inline ConnectionManagerInterface* connection_manager() override {
- return connection_manager_;
- }
-
- inline HardwareInterface* hardware() override { return hardware_; }
-
- inline MetricsReporterInterface* metrics_reporter() override {
- CHECK(metrics_reporter_ != nullptr);
- return metrics_reporter_;
- }
-
- inline PrefsInterface* prefs() override { return prefs_; }
-
- inline PrefsInterface* powerwash_safe_prefs() override {
- return powerwash_safe_prefs_;
- }
-
- inline PayloadStateInterface* payload_state() override {
- return payload_state_;
- }
-
- inline UpdateAttempter* update_attempter() override {
- return update_attempter_;
- }
-
- inline OmahaRequestParams* request_params() override {
- return request_params_;
- }
-
- inline P2PManager* p2p_manager() override { return p2p_manager_; }
-
- inline chromeos_update_manager::UpdateManager* update_manager() override {
- return update_manager_;
- }
-
- inline PowerManagerInterface* power_manager() override {
- return power_manager_;
- }
-
- inline DlcServiceInterface* dlcservice() override { return dlcservice_; }
-
- inline bool system_rebooted() override { return fake_system_rebooted_; }
-
- // Setters for the various members, can be used for overriding the default
- // implementations. For convenience, setting to a null pointer will restore
- // the default implementation.
-
- void set_boot_control(BootControlInterface* boot_control) {
- boot_control_ = boot_control ? boot_control : &fake_boot_control_;
- }
-
- inline void set_clock(ClockInterface* clock) {
- clock_ = clock ? clock : &fake_clock_;
- }
-
- inline void set_connection_manager(
- ConnectionManagerInterface* connection_manager) {
- connection_manager_ =
- (connection_manager ? connection_manager : &mock_connection_manager_);
- }
-
- inline void set_hardware(HardwareInterface* hardware) {
- hardware_ = hardware ? hardware : &fake_hardware_;
- }
-
- inline void set_metrics_reporter(MetricsReporterInterface* metrics_reporter) {
- metrics_reporter_ =
- metrics_reporter ? metrics_reporter : &mock_metrics_reporter_;
- }
-
- inline void set_prefs(PrefsInterface* prefs) {
- prefs_ = prefs ? prefs : &mock_prefs_;
- }
-
- inline void set_powerwash_safe_prefs(PrefsInterface* powerwash_safe_prefs) {
- powerwash_safe_prefs_ =
- (powerwash_safe_prefs ? powerwash_safe_prefs
- : &mock_powerwash_safe_prefs_);
- }
-
- inline void set_payload_state(PayloadStateInterface* payload_state) {
- payload_state_ = payload_state ? payload_state : &mock_payload_state_;
- }
-
- inline void set_update_attempter(UpdateAttempter* update_attempter) {
- update_attempter_ =
- (update_attempter ? update_attempter : &mock_update_attempter_);
- }
-
- inline void set_request_params(OmahaRequestParams* request_params) {
- request_params_ = (request_params ? request_params : &mock_request_params_);
- }
-
- inline void set_p2p_manager(P2PManager* p2p_manager) {
- p2p_manager_ = p2p_manager ? p2p_manager : &mock_p2p_manager_;
- }
-
- inline void set_update_manager(
- chromeos_update_manager::UpdateManager* update_manager) {
- update_manager_ = update_manager ? update_manager : &fake_update_manager_;
- }
-
- inline void set_system_rebooted(bool system_rebooted) {
- fake_system_rebooted_ = system_rebooted;
- }
-
- inline void set_dlcservice(DlcServiceInterface* dlcservice) {
- dlcservice_ = dlcservice;
- }
-
- // Getters for the built-in default implementations. These return the actual
- // concrete type of each implementation. For additional safety, they will fail
- // whenever the requested default was overridden by a different
- // implementation.
-
- inline FakeBootControl* fake_boot_control() {
- CHECK(boot_control_ == &fake_boot_control_);
- return &fake_boot_control_;
- }
-
- inline FakeClock* fake_clock() {
- CHECK(clock_ == &fake_clock_);
- return &fake_clock_;
- }
-
- inline testing::NiceMock<MockConnectionManager>* mock_connection_manager() {
- CHECK(connection_manager_ == &mock_connection_manager_);
- return &mock_connection_manager_;
- }
-
- inline FakeHardware* fake_hardware() {
- CHECK(hardware_ == &fake_hardware_);
- return &fake_hardware_;
- }
-
- inline FakePrefs* fake_prefs() {
- CHECK(prefs_ == &fake_prefs_);
- return &fake_prefs_;
- }
-
- inline FakePrefs* fake_powerwash_safe_prefs() {
- CHECK(powerwash_safe_prefs_ == &fake_powerwash_safe_prefs_);
- return &fake_powerwash_safe_prefs_;
- }
-
- inline testing::NiceMock<MockMetricsReporter>* mock_metrics_reporter() {
- CHECK(metrics_reporter_ == &mock_metrics_reporter_);
- return &mock_metrics_reporter_;
- }
-
- inline testing::NiceMock<MockPrefs>* mock_prefs() {
- CHECK(prefs_ == &mock_prefs_);
- return &mock_prefs_;
- }
-
- inline testing::NiceMock<MockPrefs>* mock_powerwash_safe_prefs() {
- CHECK(powerwash_safe_prefs_ == &mock_powerwash_safe_prefs_);
- return &mock_powerwash_safe_prefs_;
- }
-
- inline testing::NiceMock<MockPayloadState>* mock_payload_state() {
- CHECK(payload_state_ == &mock_payload_state_);
- return &mock_payload_state_;
- }
-
- inline testing::NiceMock<MockUpdateAttempter>* mock_update_attempter() {
- CHECK(update_attempter_ == &mock_update_attempter_);
- return &mock_update_attempter_;
- }
-
- inline testing::NiceMock<MockOmahaRequestParams>* mock_request_params() {
- CHECK(request_params_ == &mock_request_params_);
- return &mock_request_params_;
- }
-
- inline testing::NiceMock<MockP2PManager>* mock_p2p_manager() {
- CHECK(p2p_manager_ == &mock_p2p_manager_);
- return &mock_p2p_manager_;
- }
-
- inline chromeos_update_manager::FakeUpdateManager* fake_update_manager() {
- CHECK(update_manager_ == &fake_update_manager_);
- return &fake_update_manager_;
- }
-
- private:
- // Don't allow for direct initialization of this class.
- FakeSystemState();
-
- // Default mock/fake implementations (owned).
- chromeos_update_manager::FakeUpdateManager fake_update_manager_;
- FakeBootControl fake_boot_control_;
- FakeClock fake_clock_;
- FakeHardware fake_hardware_;
- FakePrefs fake_prefs_;
- FakePrefs fake_powerwash_safe_prefs_;
-
- testing::NiceMock<MockConnectionManager> mock_connection_manager_;
- testing::NiceMock<MockMetricsReporter> mock_metrics_reporter_;
- testing::NiceMock<MockPrefs> mock_prefs_;
- testing::NiceMock<MockPrefs> mock_powerwash_safe_prefs_;
- testing::NiceMock<MockPayloadState> mock_payload_state_;
- testing::NiceMock<MockUpdateAttempter> mock_update_attempter_;
- testing::NiceMock<MockOmahaRequestParams> mock_request_params_;
- testing::NiceMock<MockP2PManager> mock_p2p_manager_;
- testing::NiceMock<MockPowerManager> mock_power_manager_;
-
- // Pointers to objects that client code can override. They are initialized to
- // the default implementations above.
- BootControlInterface* boot_control_{&fake_boot_control_};
- ClockInterface* clock_;
- ConnectionManagerInterface* connection_manager_;
- HardwareInterface* hardware_;
- MetricsReporterInterface* metrics_reporter_;
- PrefsInterface* prefs_;
- PrefsInterface* powerwash_safe_prefs_;
- PayloadStateInterface* payload_state_;
- UpdateAttempter* update_attempter_;
- OmahaRequestParams* request_params_;
- P2PManager* p2p_manager_;
- chromeos_update_manager::UpdateManager* update_manager_;
- PowerManagerInterface* power_manager_{&mock_power_manager_};
- DlcServiceInterface* dlcservice_;
-
- // Other object pointers (not preinitialized).
- const policy::DevicePolicy* device_policy_;
-
- // Other data members.
- bool fake_system_rebooted_;
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_FAKE_SYSTEM_STATE_H_
diff --git a/cros/hardware_chromeos.cc b/cros/hardware_chromeos.cc
deleted file mode 100644
index ad0a64dc..00000000
--- a/cros/hardware_chromeos.cc
+++ /dev/null
@@ -1,371 +0,0 @@
-//
-// Copyright (C) 2013 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/cros/hardware_chromeos.h"
-
-#include <utility>
-
-#include <base/files/file_path.h>
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <brillo/key_value_store.h>
-#include <debugd/dbus-constants.h>
-#include <vboot/crossystem.h>
-
-extern "C" {
-#include "vboot/vboot_host.h"
-}
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/hardware.h"
-#include "update_engine/common/hwid_override.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/subprocess.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/dbus_connection.h"
-#if USE_CFM
-#include "update_engine/cros/requisition_util.h"
-#endif
-
-using std::string;
-using std::vector;
-
-namespace {
-
-const char kOOBECompletedMarker[] = "/home/chronos/.oobe_completed";
-
-// The stateful directory used by update_engine to store powerwash-safe files.
-// The files stored here must be added to the powerwash script allowlist.
-const char kPowerwashSafeDirectory[] =
- "/mnt/stateful_partition/unencrypted/preserve";
-
-// The powerwash_count marker file contains the number of times the device was
-// powerwashed. This value is incremented by the clobber-state script when
-// a powerwash is performed.
-const char kPowerwashCountMarker[] = "powerwash_count";
-
-// The name of the marker file used to trigger powerwash when post-install
-// completes successfully so that the device is powerwashed on next reboot.
-const char kPowerwashMarkerFile[] =
- "/mnt/stateful_partition/factory_install_reset";
-
-// The name of the marker file used to trigger a save of rollback data
-// during the next shutdown.
-const char kRollbackSaveMarkerFile[] =
- "/mnt/stateful_partition/.save_rollback_data";
-
-// The contents of the powerwash marker file for the non-rollback case.
-const char kPowerwashCommand[] = "safe fast keepimg reason=update_engine\n";
-
-// The contents of the powerwas marker file for the rollback case.
-const char kRollbackPowerwashCommand[] =
- "safe fast keepimg rollback reason=update_engine\n";
-
-// UpdateManager config path.
-const char* kConfigFilePath = "/etc/update_manager.conf";
-
-// UpdateManager config options:
-const char* kConfigOptsIsOOBEEnabled = "is_oobe_enabled";
-
-const char* kActivePingKey = "first_active_omaha_ping_sent";
-
-} // namespace
-
-namespace chromeos_update_engine {
-
-namespace hardware {
-
-// Factory defined in hardware.h.
-std::unique_ptr<HardwareInterface> CreateHardware() {
- std::unique_ptr<HardwareChromeOS> hardware(new HardwareChromeOS());
- hardware->Init();
- return std::move(hardware);
-}
-
-} // namespace hardware
-
-void HardwareChromeOS::Init() {
- LoadConfig("" /* root_prefix */, IsNormalBootMode());
- debugd_proxy_.reset(
- new org::chromium::debugdProxy(DBusConnection::Get()->GetDBus()));
-}
-
-bool HardwareChromeOS::IsOfficialBuild() const {
- return VbGetSystemPropertyInt("debug_build") == 0;
-}
-
-bool HardwareChromeOS::IsNormalBootMode() const {
- bool dev_mode = VbGetSystemPropertyInt("devsw_boot") != 0;
- return !dev_mode;
-}
-
-bool HardwareChromeOS::AreDevFeaturesEnabled() const {
- // Even though the debugd tools are also gated on devmode, checking here can
- // save us a D-Bus call so it's worth doing explicitly.
- if (IsNormalBootMode())
- return false;
-
- int32_t dev_features = debugd::DEV_FEATURES_DISABLED;
- brillo::ErrorPtr error;
- // Some boards may not include debugd so it's expected that this may fail,
- // in which case we treat it as disabled.
- if (debugd_proxy_ && debugd_proxy_->QueryDevFeatures(&dev_features, &error) &&
- !(dev_features & debugd::DEV_FEATURES_DISABLED)) {
- LOG(INFO) << "Debugd dev tools enabled.";
- return true;
- }
- return false;
-}
-
-bool HardwareChromeOS::IsOOBEEnabled() const {
- return is_oobe_enabled_;
-}
-
-bool HardwareChromeOS::IsOOBEComplete(base::Time* out_time_of_oobe) const {
- if (!is_oobe_enabled_) {
- LOG(WARNING) << "OOBE is not enabled but IsOOBEComplete() was called";
- }
- struct stat statbuf;
- if (stat(kOOBECompletedMarker, &statbuf) != 0) {
- if (errno != ENOENT) {
- PLOG(ERROR) << "Error getting information about " << kOOBECompletedMarker;
- }
- return false;
- }
-
- if (out_time_of_oobe != nullptr)
- *out_time_of_oobe = base::Time::FromTimeT(statbuf.st_mtime);
- return true;
-}
-
-static string ReadValueFromCrosSystem(const string& key) {
- char value_buffer[VB_MAX_STRING_PROPERTY];
-
- const char* rv = VbGetSystemPropertyString(
- key.c_str(), value_buffer, sizeof(value_buffer));
- if (rv != nullptr) {
- string return_value(value_buffer);
- base::TrimWhitespaceASCII(return_value, base::TRIM_ALL, &return_value);
- return return_value;
- }
-
- LOG(ERROR) << "Unable to read crossystem key " << key;
- return "";
-}
-
-string HardwareChromeOS::GetHardwareClass() const {
- if (USE_HWID_OVERRIDE) {
- return HwidOverride::Read(base::FilePath("/"));
- }
- return ReadValueFromCrosSystem("hwid");
-}
-
-string HardwareChromeOS::GetDeviceRequisition() const {
-#if USE_CFM
- const char* kLocalStatePath = "/home/chronos/Local State";
- return ReadDeviceRequisition(base::FilePath(kLocalStatePath));
-#else
- return "";
-#endif
-}
-
-int HardwareChromeOS::GetMinKernelKeyVersion() const {
- return VbGetSystemPropertyInt("tpm_kernver");
-}
-
-int HardwareChromeOS::GetMaxFirmwareKeyRollforward() const {
- return VbGetSystemPropertyInt("firmware_max_rollforward");
-}
-
-bool HardwareChromeOS::SetMaxFirmwareKeyRollforward(
- int firmware_max_rollforward) {
- // Not all devices have this field yet. So first try to read
- // it and if there is an error just fail.
- if (GetMaxFirmwareKeyRollforward() == -1)
- return false;
-
- return VbSetSystemPropertyInt("firmware_max_rollforward",
- firmware_max_rollforward) == 0;
-}
-
-int HardwareChromeOS::GetMinFirmwareKeyVersion() const {
- return VbGetSystemPropertyInt("tpm_fwver");
-}
-
-bool HardwareChromeOS::SetMaxKernelKeyRollforward(int kernel_max_rollforward) {
- return VbSetSystemPropertyInt("kernel_max_rollforward",
- kernel_max_rollforward) == 0;
-}
-
-int HardwareChromeOS::GetPowerwashCount() const {
- int powerwash_count;
- base::FilePath marker_path =
- base::FilePath(kPowerwashSafeDirectory).Append(kPowerwashCountMarker);
- string contents;
- if (!utils::ReadFile(marker_path.value(), &contents))
- return -1;
- base::TrimWhitespaceASCII(contents, base::TRIM_TRAILING, &contents);
- if (!base::StringToInt(contents, &powerwash_count))
- return -1;
- return powerwash_count;
-}
-
-bool HardwareChromeOS::SchedulePowerwash(bool save_rollback_data) {
- if (save_rollback_data) {
- if (!utils::WriteFile(kRollbackSaveMarkerFile, nullptr, 0)) {
- PLOG(ERROR) << "Error in creating rollback save marker file: "
- << kRollbackSaveMarkerFile << ". Rollback will not"
- << " preserve any data.";
- } else {
- LOG(INFO) << "Rollback data save has been scheduled on next shutdown.";
- }
- }
-
- const char* powerwash_command =
- save_rollback_data ? kRollbackPowerwashCommand : kPowerwashCommand;
- bool result = utils::WriteFile(
- kPowerwashMarkerFile, powerwash_command, strlen(powerwash_command));
- if (result) {
- LOG(INFO) << "Created " << kPowerwashMarkerFile
- << " to powerwash on next reboot ("
- << "save_rollback_data=" << save_rollback_data << ")";
- } else {
- PLOG(ERROR) << "Error in creating powerwash marker file: "
- << kPowerwashMarkerFile;
- }
-
- return result;
-}
-
-bool HardwareChromeOS::CancelPowerwash() {
- bool result = base::DeleteFile(base::FilePath(kPowerwashMarkerFile));
-
- if (result) {
- LOG(INFO) << "Successfully deleted the powerwash marker file : "
- << kPowerwashMarkerFile;
- } else {
- PLOG(ERROR) << "Could not delete the powerwash marker file : "
- << kPowerwashMarkerFile;
- }
-
- // Delete the rollback save marker file if it existed.
- if (!base::DeleteFile(base::FilePath(kRollbackSaveMarkerFile))) {
- PLOG(ERROR) << "Could not remove rollback save marker";
- }
-
- return result;
-}
-
-bool HardwareChromeOS::GetNonVolatileDirectory(base::FilePath* path) const {
- *path = base::FilePath(constants::kNonVolatileDirectory);
- return true;
-}
-
-bool HardwareChromeOS::GetPowerwashSafeDirectory(base::FilePath* path) const {
- *path = base::FilePath(kPowerwashSafeDirectory);
- return true;
-}
-
-int64_t HardwareChromeOS::GetBuildTimestamp() const {
- // TODO(senj): implement this in Chrome OS.
- return 0;
-}
-
-void HardwareChromeOS::LoadConfig(const string& root_prefix, bool normal_mode) {
- brillo::KeyValueStore store;
-
- if (normal_mode) {
- store.Load(base::FilePath(root_prefix + kConfigFilePath));
- } else {
- if (store.Load(base::FilePath(root_prefix + kStatefulPartition +
- kConfigFilePath))) {
- LOG(INFO) << "UpdateManager Config loaded from stateful partition.";
- } else {
- store.Load(base::FilePath(root_prefix + kConfigFilePath));
- }
- }
-
- if (!store.GetBoolean(kConfigOptsIsOOBEEnabled, &is_oobe_enabled_))
- is_oobe_enabled_ = true; // Default value.
-}
-
-bool HardwareChromeOS::GetFirstActiveOmahaPingSent() const {
- string active_ping_str;
- if (!utils::GetVpdValue(kActivePingKey, &active_ping_str)) {
- return false;
- }
-
- int active_ping;
- if (active_ping_str.empty() ||
- !base::StringToInt(active_ping_str, &active_ping)) {
- LOG(INFO) << "Failed to parse active_ping value: " << active_ping_str;
- return false;
- }
- return static_cast<bool>(active_ping);
-}
-
-bool HardwareChromeOS::SetFirstActiveOmahaPingSent() {
- int exit_code = 0;
- string output, error;
- vector<string> vpd_set_cmd = {
- "vpd", "-i", "RW_VPD", "-s", string(kActivePingKey) + "=1"};
- if (!Subprocess::SynchronousExec(vpd_set_cmd, &exit_code, &output, &error) ||
- exit_code) {
- LOG(ERROR) << "Failed to set vpd key for " << kActivePingKey
- << " with exit code: " << exit_code << " with output: " << output
- << " and error: " << error;
- return false;
- } else if (!error.empty()) {
- LOG(INFO) << "vpd succeeded but with error logs: " << error;
- }
-
- vector<string> vpd_dump_cmd = {"dump_vpd_log", "--force"};
- if (!Subprocess::SynchronousExec(vpd_dump_cmd, &exit_code, &output, &error) ||
- exit_code) {
- LOG(ERROR) << "Failed to cache " << kActivePingKey << " using dump_vpd_log"
- << " with exit code: " << exit_code << " with output: " << output
- << " and error: " << error;
- return false;
- } else if (!error.empty()) {
- LOG(INFO) << "dump_vpd_log succeeded but with error logs: " << error;
- }
- return true;
-}
-
-void HardwareChromeOS::SetWarmReset(bool warm_reset) {}
-
-void HardwareChromeOS::SetVbmetaDigestForInactiveSlot(bool reset) {}
-
-std::string HardwareChromeOS::GetVersionForLogging(
- const std::string& partition_name) const {
- // TODO(zhangkelvin) Implement per-partition timestamp for Chrome OS.
- return "";
-}
-
-ErrorCode HardwareChromeOS::IsPartitionUpdateValid(
- const std::string& partition_name, const std::string& new_version) const {
- // TODO(zhangkelvin) Implement per-partition timestamp for Chrome OS.
- return ErrorCode::kSuccess;
-}
-
-const char* HardwareChromeOS::GetPartitionMountOptions(
- const std::string& partition_name) const {
- return "";
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/hardware_chromeos.h b/cros/hardware_chromeos.h
deleted file mode 100644
index a64f8049..00000000
--- a/cros/hardware_chromeos.h
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-// Copyright (C) 2013 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_CROS_HARDWARE_CHROMEOS_H_
-#define UPDATE_ENGINE_CROS_HARDWARE_CHROMEOS_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-#include <base/time/time.h>
-#include <debugd/dbus-proxies.h>
-
-#include "update_engine/common/error_code.h"
-#include "update_engine/common/hardware_interface.h"
-
-namespace chromeos_update_engine {
-
-// Implements the real interface with Chrome OS verified boot and recovery
-// process.
-class HardwareChromeOS final : public HardwareInterface {
- public:
- HardwareChromeOS() = default;
- ~HardwareChromeOS() override = default;
-
- void Init();
-
- // HardwareInterface methods.
- bool IsOfficialBuild() const override;
- bool IsNormalBootMode() const override;
- bool AreDevFeaturesEnabled() const override;
- bool IsOOBEEnabled() const override;
- bool IsOOBEComplete(base::Time* out_time_of_oobe) const override;
- std::string GetHardwareClass() const override;
- std::string GetDeviceRequisition() const override;
- int GetMinKernelKeyVersion() const override;
- int GetMinFirmwareKeyVersion() const override;
- int GetMaxFirmwareKeyRollforward() const override;
- bool SetMaxFirmwareKeyRollforward(int firmware_max_rollforward) override;
- bool SetMaxKernelKeyRollforward(int kernel_max_rollforward) override;
- int GetPowerwashCount() const override;
- bool SchedulePowerwash(bool save_rollback_data) override;
- bool CancelPowerwash() override;
- bool GetNonVolatileDirectory(base::FilePath* path) const override;
- bool GetPowerwashSafeDirectory(base::FilePath* path) const override;
- int64_t GetBuildTimestamp() const override;
- bool AllowDowngrade() const override { return false; }
- bool GetFirstActiveOmahaPingSent() const override;
- bool SetFirstActiveOmahaPingSent() override;
- void SetWarmReset(bool warm_reset) override;
- void SetVbmetaDigestForInactiveSlot(bool reset) override;
- std::string GetVersionForLogging(
- const std::string& partition_name) const override;
- ErrorCode IsPartitionUpdateValid(
- const std::string& partition_name,
- const std::string& new_version) const override;
- const char* GetPartitionMountOptions(
- const std::string& partition_name) const override;
-
- private:
- friend class HardwareChromeOSTest;
-
- // Load the update manager config flags (is_oobe_enabled flag) from the
- // appropriate location based on whether we are in a normal mode boot (as
- // passed in |normal_mode|) prefixing the paths with |root_prefix|.
- void LoadConfig(const std::string& root_prefix, bool normal_mode);
-
- bool is_oobe_enabled_;
-
- std::unique_ptr<org::chromium::debugdProxyInterface> debugd_proxy_;
-
- DISALLOW_COPY_AND_ASSIGN(HardwareChromeOS);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_HARDWARE_CHROMEOS_H_
diff --git a/cros/hardware_chromeos_unittest.cc b/cros/hardware_chromeos_unittest.cc
deleted file mode 100644
index 50bced6e..00000000
--- a/cros/hardware_chromeos_unittest.cc
+++ /dev/null
@@ -1,90 +0,0 @@
-//
-// Copyright (C) 2016 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/cros/hardware_chromeos.h"
-
-#include <memory>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/fake_hardware.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/update_manager/umtest_utils.h"
-
-using chromeos_update_engine::test_utils::WriteFileString;
-using std::string;
-
-namespace chromeos_update_engine {
-
-class HardwareChromeOSTest : public ::testing::Test {
- protected:
- void SetUp() override { ASSERT_TRUE(root_dir_.CreateUniqueTempDir()); }
-
- void WriteStatefulConfig(const string& config) {
- base::FilePath kFile(root_dir_.GetPath().value() + kStatefulPartition +
- "/etc/update_manager.conf");
- ASSERT_TRUE(base::CreateDirectory(kFile.DirName()));
- ASSERT_TRUE(WriteFileString(kFile.value(), config));
- }
-
- void WriteRootfsConfig(const string& config) {
- base::FilePath kFile(root_dir_.GetPath().value() +
- "/etc/update_manager.conf");
- ASSERT_TRUE(base::CreateDirectory(kFile.DirName()));
- ASSERT_TRUE(WriteFileString(kFile.value(), config));
- }
-
- // Helper method to call HardwareChromeOS::LoadConfig with the test directory.
- void CallLoadConfig(bool normal_mode) {
- hardware_.LoadConfig(root_dir_.GetPath().value(), normal_mode);
- }
-
- HardwareChromeOS hardware_;
- base::ScopedTempDir root_dir_;
-};
-
-TEST_F(HardwareChromeOSTest, NoFileFoundReturnsDefault) {
- CallLoadConfig(true /* normal_mode */);
- EXPECT_TRUE(hardware_.IsOOBEEnabled());
-}
-
-TEST_F(HardwareChromeOSTest, DontReadStatefulInNormalMode) {
- WriteStatefulConfig("is_oobe_enabled=false");
-
- CallLoadConfig(true /* normal_mode */);
- EXPECT_TRUE(hardware_.IsOOBEEnabled());
-}
-
-TEST_F(HardwareChromeOSTest, ReadStatefulInDevMode) {
- WriteRootfsConfig("is_oobe_enabled=true");
- // Since the stateful is present, we should read that one.
- WriteStatefulConfig("is_oobe_enabled=false");
-
- CallLoadConfig(false /* normal_mode */);
- EXPECT_FALSE(hardware_.IsOOBEEnabled());
-}
-
-TEST_F(HardwareChromeOSTest, ReadRootfsIfStatefulNotFound) {
- WriteRootfsConfig("is_oobe_enabled=false");
-
- CallLoadConfig(false /* normal_mode */);
- EXPECT_FALSE(hardware_.IsOOBEEnabled());
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/image_properties.h b/cros/image_properties.h
deleted file mode 100644
index 12975473..00000000
--- a/cros/image_properties.h
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// Copyright (C) 2015 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.
-//
-
-// This module abstracts the properties tied to the current running image. These
-// properties are meant to be constant during the life of this daemon, but can
-// be modified in dev-move or non-official builds.
-
-#ifndef UPDATE_ENGINE_CROS_IMAGE_PROPERTIES_H_
-#define UPDATE_ENGINE_CROS_IMAGE_PROPERTIES_H_
-
-#include <string>
-
-namespace chromeos_update_engine {
-
-// The read-only system properties of the running image.
-struct ImageProperties {
- // The product id of the image used for all channels, except canary.
- std::string product_id;
- // The canary-channel product id.
- std::string canary_product_id;
-
- // The product version of this image.
- std::string 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;
-
- // The Android build type, should be either 'user', 'userdebug' or 'eng'.
- // It's empty string on other platform.
- std::string build_type;
-
- // The board name this image was built for.
- std::string board;
-
- // The release channel this image was obtained from.
- std::string current_channel;
-
- // Whether we allow arbitrary channels instead of just the ones listed in
- // kChannelsByStability.
- bool allow_arbitrary_channels = false;
-
- // The Omaha URL this image should get updates from.
- std::string omaha_url;
-};
-
-// The mutable image properties are read-write image properties, initialized
-// with values from the image but can be modified by storing them in the
-// stateful partition.
-struct MutableImageProperties {
- // The release channel we are tracking.
- std::string target_channel;
-
- // Whether powerwash is allowed when downloading an update for the selected
- // target_channel.
- bool is_powerwash_allowed{false};
-};
-
-// Loads all the image properties from the running system. In case of error
-// loading any of these properties from the read-only system image a default
-// value may be returned instead.
-ImageProperties LoadImageProperties();
-
-// Loads the mutable image properties from the stateful partition if found or
-// the system image otherwise.
-MutableImageProperties LoadMutableImageProperties();
-
-// Stores the mutable image properties in the stateful partition. Returns
-// whether the operation succeeded.
-bool StoreMutableImageProperties(const MutableImageProperties& properties);
-
-// Logs the image properties.
-void LogImageProperties();
-
-// Sets the root_prefix used to load files from during unittests to
-// |test_root_prefix|. Passing a nullptr value resets it to the default.
-namespace test {
-void SetImagePropertiesRootPrefix(const char* test_root_prefix);
-} // namespace test
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_IMAGE_PROPERTIES_H_
diff --git a/cros/image_properties_chromeos.cc b/cros/image_properties_chromeos.cc
deleted file mode 100644
index 79155b5d..00000000
--- a/cros/image_properties_chromeos.cc
+++ /dev/null
@@ -1,167 +0,0 @@
-//
-// Copyright (C) 2015 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/cros/image_properties.h"
-
-#include <string>
-#include <vector>
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <brillo/key_value_store.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-
-namespace {
-
-const char kLsbRelease[] = "/etc/lsb-release";
-
-const char kLsbReleaseAppIdKey[] = "CHROMEOS_RELEASE_APPID";
-const char kLsbReleaseAutoUpdateServerKey[] = "CHROMEOS_AUSERVER";
-const char kLsbReleaseBoardAppIdKey[] = "CHROMEOS_BOARD_APPID";
-const char kLsbReleaseBoardKey[] = "CHROMEOS_RELEASE_BOARD";
-const char kLsbReleaseCanaryAppIdKey[] = "CHROMEOS_CANARY_APPID";
-const char kLsbReleaseIsPowerwashAllowedKey[] = "CHROMEOS_IS_POWERWASH_ALLOWED";
-const char kLsbReleaseUpdateChannelKey[] = "CHROMEOS_RELEASE_TRACK";
-const char kLsbReleaseVersionKey[] = "CHROMEOS_RELEASE_VERSION";
-
-const char kDefaultAppId[] = "{87efface-864d-49a5-9bb3-4b050a7c227a}";
-
-// A prefix added to the path, used for testing.
-const char* root_prefix = nullptr;
-
-std::string GetStringWithDefault(const brillo::KeyValueStore& store,
- const std::string& key,
- const std::string& default_value) {
- std::string result;
- if (store.GetString(key, &result))
- return result;
- LOG(INFO) << "Cannot load ImageProperty " << key << ", using default value "
- << default_value;
- return default_value;
-}
-
-enum class LsbReleaseSource {
- kSystem,
- kStateful,
-};
-
-// Loads the lsb-release properties into the key-value |store| reading the file
-// from either the system image or the stateful partition as specified by
-// |source|. The loaded values are added to the store, possibly overriding
-// existing values.
-void LoadLsbRelease(LsbReleaseSource source, brillo::KeyValueStore* store) {
- std::string path;
- if (root_prefix)
- path = root_prefix;
- if (source == LsbReleaseSource::kStateful)
- path += chromeos_update_engine::kStatefulPartition;
- store->Load(base::FilePath(path + kLsbRelease));
-}
-
-} // namespace
-
-namespace chromeos_update_engine {
-
-namespace test {
-void SetImagePropertiesRootPrefix(const char* test_root_prefix) {
- root_prefix = test_root_prefix;
-}
-} // namespace test
-
-ImageProperties LoadImageProperties() {
- ImageProperties result;
-
- brillo::KeyValueStore lsb_release;
- LoadLsbRelease(LsbReleaseSource::kSystem, &lsb_release);
- result.current_channel = GetStringWithDefault(
- lsb_release, kLsbReleaseUpdateChannelKey, "stable-channel");
-
- // In dev-mode and unofficial build we can override the image properties set
- // in the system image with the ones from the stateful partition, except the
- // channel of the current image.
- HardwareInterface* const hardware = SystemState::Get()->hardware();
- if (!hardware->IsOfficialBuild() || !hardware->IsNormalBootMode())
- LoadLsbRelease(LsbReleaseSource::kStateful, &lsb_release);
-
- // The release_app_id is used as the default appid, but can be override by
- // the board appid in the general case or the canary appid for the canary
- // channel only.
- std::string release_app_id =
- GetStringWithDefault(lsb_release, kLsbReleaseAppIdKey, kDefaultAppId);
-
- result.product_id = GetStringWithDefault(
- lsb_release, kLsbReleaseBoardAppIdKey, release_app_id);
- result.canary_product_id = GetStringWithDefault(
- lsb_release, kLsbReleaseCanaryAppIdKey, release_app_id);
- result.board = GetStringWithDefault(lsb_release, kLsbReleaseBoardKey, "");
- result.version = GetStringWithDefault(lsb_release, kLsbReleaseVersionKey, "");
- result.omaha_url =
- GetStringWithDefault(lsb_release,
- kLsbReleaseAutoUpdateServerKey,
- constants::kOmahaDefaultProductionURL);
- // Build fingerprint not used in Chrome OS.
- result.build_fingerprint = "";
- result.allow_arbitrary_channels = false;
-
- return result;
-}
-
-MutableImageProperties LoadMutableImageProperties() {
- MutableImageProperties result;
- brillo::KeyValueStore lsb_release;
- LoadLsbRelease(LsbReleaseSource::kSystem, &lsb_release);
- LoadLsbRelease(LsbReleaseSource::kStateful, &lsb_release);
- result.target_channel = GetStringWithDefault(
- lsb_release, kLsbReleaseUpdateChannelKey, "stable-channel");
- if (!lsb_release.GetBoolean(kLsbReleaseIsPowerwashAllowedKey,
- &result.is_powerwash_allowed))
- result.is_powerwash_allowed = false;
- return result;
-}
-
-bool StoreMutableImageProperties(const MutableImageProperties& properties) {
- brillo::KeyValueStore lsb_release;
- LoadLsbRelease(LsbReleaseSource::kStateful, &lsb_release);
- lsb_release.SetString(kLsbReleaseUpdateChannelKey, properties.target_channel);
- lsb_release.SetBoolean(kLsbReleaseIsPowerwashAllowedKey,
- properties.is_powerwash_allowed);
-
- std::string root_prefix_str = root_prefix ? root_prefix : "";
- base::FilePath path(root_prefix_str + kStatefulPartition + kLsbRelease);
- if (!base::DirectoryExists(path.DirName()))
- base::CreateDirectory(path.DirName());
- return lsb_release.Save(path);
-}
-
-void LogImageProperties() {
- std::string lsb_release;
- if (utils::ReadFile(kLsbRelease, &lsb_release)) {
- LOG(INFO) << "lsb-release inside the old rootfs:\n" << lsb_release;
- }
-
- std::string stateful_lsb_release;
- if (utils::ReadFile(std::string(kStatefulPartition) + kLsbRelease,
- &stateful_lsb_release)) {
- LOG(INFO) << "stateful lsb-release:\n" << stateful_lsb_release;
- }
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/image_properties_chromeos_unittest.cc b/cros/image_properties_chromeos_unittest.cc
deleted file mode 100644
index 497554e2..00000000
--- a/cros/image_properties_chromeos_unittest.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-//
-// Copyright (C) 2016 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/cros/image_properties.h"
-
-#include <string>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/cros/fake_system_state.h"
-
-using chromeos_update_engine::test_utils::WriteFileString;
-using std::string;
-
-namespace chromeos_update_engine {
-
-class ImagePropertiesTest : public ::testing::Test {
- protected:
- void SetUp() override {
- // Create a uniquely named test directory.
- ASSERT_TRUE(tempdir_.CreateUniqueTempDir());
- EXPECT_TRUE(base::CreateDirectory(tempdir_.GetPath().Append("etc")));
- EXPECT_TRUE(base::CreateDirectory(base::FilePath(
- tempdir_.GetPath().value() + kStatefulPartition + "/etc")));
- test::SetImagePropertiesRootPrefix(tempdir_.GetPath().value().c_str());
- FakeSystemState::CreateInstance();
- SetLockDown(false);
- }
-
- void SetLockDown(bool locked_down) {
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(locked_down);
- FakeSystemState::Get()->fake_hardware()->SetIsNormalBootMode(locked_down);
- }
-
- base::ScopedTempDir tempdir_;
-};
-
-TEST_F(ImagePropertiesTest, SimpleTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_BOARD=arm-generic\n"
- "CHROMEOS_RELEASE_FOO=bar\n"
- "CHROMEOS_RELEASE_VERSION=0.2.2.3\n"
- "CHROMEOS_RELEASE_TRACK=dev-channel\n"
- "CHROMEOS_AUSERVER=http://www.google.com"));
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("arm-generic", props.board);
- EXPECT_EQ("{87efface-864d-49a5-9bb3-4b050a7c227a}", props.product_id);
- EXPECT_EQ("0.2.2.3", props.version);
- EXPECT_EQ("dev-channel", props.current_channel);
- EXPECT_EQ("http://www.google.com", props.omaha_url);
-}
-
-TEST_F(ImagePropertiesTest, AppIDTest) {
- ASSERT_TRUE(WriteFileString(
- tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_APPID={58c35cef-9d30-476e-9098-ce20377d535d}"));
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("{58c35cef-9d30-476e-9098-ce20377d535d}", props.product_id);
-}
-
-TEST_F(ImagePropertiesTest, ConfusingReleaseTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_FOO=CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
- "CHROMEOS_RELEASE_VERSION=0.2.2.3"));
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("0.2.2.3", props.version);
-}
-
-TEST_F(ImagePropertiesTest, MissingVersionTest) {
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("", props.version);
-}
-
-TEST_F(ImagePropertiesTest, OverrideTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_BOARD=arm-generic\n"
- "CHROMEOS_RELEASE_FOO=bar\n"
- "CHROMEOS_RELEASE_TRACK=dev-channel\n"
- "CHROMEOS_AUSERVER=http://www.google.com"));
- ASSERT_TRUE(WriteFileString(
- tempdir_.GetPath().value() + kStatefulPartition + "/etc/lsb-release",
- "CHROMEOS_RELEASE_BOARD=x86-generic\n"
- "CHROMEOS_RELEASE_TRACK=beta-channel\n"
- "CHROMEOS_AUSERVER=https://www.google.com"));
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("x86-generic", props.board);
- EXPECT_EQ("dev-channel", props.current_channel);
- EXPECT_EQ("https://www.google.com", props.omaha_url);
- MutableImageProperties mutable_props = LoadMutableImageProperties();
- EXPECT_EQ("beta-channel", mutable_props.target_channel);
-}
-
-TEST_F(ImagePropertiesTest, OverrideLockDownTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_BOARD=arm-generic\n"
- "CHROMEOS_RELEASE_FOO=bar\n"
- "CHROMEOS_RELEASE_TRACK=dev-channel\n"
- "CHROMEOS_AUSERVER=https://www.google.com"));
- ASSERT_TRUE(WriteFileString(
- tempdir_.GetPath().value() + kStatefulPartition + "/etc/lsb-release",
- "CHROMEOS_RELEASE_BOARD=x86-generic\n"
- "CHROMEOS_RELEASE_TRACK=stable-channel\n"
- "CHROMEOS_AUSERVER=http://www.google.com"));
- SetLockDown(true);
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("arm-generic", props.board);
- EXPECT_EQ("dev-channel", props.current_channel);
- EXPECT_EQ("https://www.google.com", props.omaha_url);
- MutableImageProperties mutable_props = LoadMutableImageProperties();
- EXPECT_EQ("stable-channel", mutable_props.target_channel);
-}
-
-TEST_F(ImagePropertiesTest, BoardAppIdUsedForNonCanaryChannelTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_APPID=r\n"
- "CHROMEOS_BOARD_APPID=b\n"
- "CHROMEOS_CANARY_APPID=c\n"
- "CHROMEOS_RELEASE_TRACK=stable-channel\n"));
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("stable-channel", props.current_channel);
- EXPECT_EQ("b", props.product_id);
-}
-
-TEST_F(ImagePropertiesTest, CanaryAppIdUsedForCanaryChannelTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_APPID=r\n"
- "CHROMEOS_BOARD_APPID=b\n"
- "CHROMEOS_CANARY_APPID=c\n"
- "CHROMEOS_RELEASE_TRACK=canary-channel\n"));
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("canary-channel", props.current_channel);
- EXPECT_EQ("c", props.canary_product_id);
-}
-
-TEST_F(ImagePropertiesTest, ReleaseAppIdUsedAsDefaultTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append("etc/lsb-release").value(),
- "CHROMEOS_RELEASE_APPID=r\n"
- "CHROMEOS_CANARY_APPID=c\n"
- "CHROMEOS_RELEASE_TRACK=stable-channel\n"));
- ImageProperties props = LoadImageProperties();
- EXPECT_EQ("stable-channel", props.current_channel);
- EXPECT_EQ("r", props.product_id);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/logging.cc b/cros/logging.cc
deleted file mode 100644
index 8b6c556b..00000000
--- a/cros/logging.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-//
-// 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 <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-
-#include "update_engine/common/logging.h"
-#include "update_engine/common/utils.h"
-
-using std::string;
-
-namespace chromeos_update_engine {
-
-namespace {
-
-constexpr char kSystemLogsRoot[] = "/var/log";
-
-void SetupLogSymlink(const string& symlink_path, const string& log_path) {
- // TODO(petkov): To ensure a smooth transition between non-timestamped and
- // timestamped logs, move an existing log to start the first timestamped
- // one. This code can go away once all clients are switched to this version or
- // we stop caring about the old-style logs.
- if (utils::FileExists(symlink_path.c_str()) &&
- !utils::IsSymlink(symlink_path.c_str())) {
- base::ReplaceFile(
- base::FilePath(symlink_path), base::FilePath(log_path), nullptr);
- }
- base::DeletePathRecursively(base::FilePath(symlink_path));
- if (symlink(log_path.c_str(), symlink_path.c_str()) == -1) {
- PLOG(ERROR) << "Unable to create symlink " << symlink_path
- << " pointing at " << log_path;
- }
-}
-
-string SetupLogFile(const string& kLogsRoot) {
- const string kLogSymlink = kLogsRoot + "/update_engine.log";
- const string kLogsDir = kLogsRoot + "/update_engine";
- const string kLogPath =
- base::StringPrintf("%s/update_engine.%s",
- kLogsDir.c_str(),
- utils::GetTimeAsString(::time(nullptr)).c_str());
- mkdir(kLogsDir.c_str(), 0755);
- SetupLogSymlink(kLogSymlink, kLogPath);
- return kLogSymlink;
-}
-
-} // namespace
-
-void SetupLogging(bool log_to_system, bool log_to_file) {
- logging::LoggingSettings log_settings;
- log_settings.lock_log = logging::DONT_LOCK_LOG_FILE;
- log_settings.logging_dest = static_cast<logging::LoggingDestination>(
- (log_to_system ? logging::LOG_TO_SYSTEM_DEBUG_LOG : 0) |
- (log_to_file ? logging::LOG_TO_FILE : 0));
- log_settings.log_file = nullptr;
-
- string log_file;
- if (log_to_file) {
- log_file = SetupLogFile(kSystemLogsRoot);
- log_settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
-#if BASE_VER < 780000
- log_settings.log_file = log_file.c_str();
-#else
- log_settings.log_file_path = log_file.c_str();
-#endif
- }
- logging::InitLogging(log_settings);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/metrics_reporter_omaha.cc b/cros/metrics_reporter_omaha.cc
deleted file mode 100644
index 69cdb19b..00000000
--- a/cros/metrics_reporter_omaha.cc
+++ /dev/null
@@ -1,593 +0,0 @@
-//
-// Copyright (C) 2014 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/cros/metrics_reporter_omaha.h"
-
-#include <memory>
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <metrics/metrics_library.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/prefs_interface.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/metrics_utils.h"
-
-using base::Time;
-using base::TimeDelta;
-using std::string;
-
-namespace chromeos_update_engine {
-namespace metrics {
-
-// UpdateEngine.Daily.* metrics.
-const char kMetricDailyOSAgeDays[] = "UpdateEngine.Daily.OSAgeDays";
-
-// UpdateEngine.Check.* metrics.
-const char kMetricCheckDownloadErrorCode[] =
- "UpdateEngine.Check.DownloadErrorCode";
-const char kMetricCheckReaction[] = "UpdateEngine.Check.Reaction";
-const char kMetricCheckResult[] = "UpdateEngine.Check.Result";
-const char kMetricCheckTargetVersion[] = "UpdateEngine.Check.TargetVersion";
-const char kMetricCheckRollbackTargetVersion[] =
- "UpdateEngine.Check.RollbackTargetVersion";
-const char kMetricCheckTimeSinceLastCheckMinutes[] =
- "UpdateEngine.Check.TimeSinceLastCheckMinutes";
-const char kMetricCheckTimeSinceLastCheckUptimeMinutes[] =
- "UpdateEngine.Check.TimeSinceLastCheckUptimeMinutes";
-
-// UpdateEngine.Attempt.* metrics.
-const char kMetricAttemptNumber[] = "UpdateEngine.Attempt.Number";
-const char kMetricAttemptPayloadType[] = "UpdateEngine.Attempt.PayloadType";
-const char kMetricAttemptPayloadSizeMiB[] =
- "UpdateEngine.Attempt.PayloadSizeMiB";
-const char kMetricAttemptConnectionType[] =
- "UpdateEngine.Attempt.ConnectionType";
-const char kMetricAttemptDurationMinutes[] =
- "UpdateEngine.Attempt.DurationMinutes";
-const char kMetricAttemptDurationUptimeMinutes[] =
- "UpdateEngine.Attempt.DurationUptimeMinutes";
-const char kMetricAttemptTimeSinceLastAttemptMinutes[] =
- "UpdateEngine.Attempt.TimeSinceLastAttemptMinutes";
-const char kMetricAttemptTimeSinceLastAttemptUptimeMinutes[] =
- "UpdateEngine.Attempt.TimeSinceLastAttemptUptimeMinutes";
-const char kMetricAttemptPayloadBytesDownloadedMiB[] =
- "UpdateEngine.Attempt.PayloadBytesDownloadedMiB";
-const char kMetricAttemptPayloadDownloadSpeedKBps[] =
- "UpdateEngine.Attempt.PayloadDownloadSpeedKBps";
-const char kMetricAttemptDownloadSource[] =
- "UpdateEngine.Attempt.DownloadSource";
-const char kMetricAttemptResult[] = "UpdateEngine.Attempt.Result";
-const char kMetricAttemptInternalErrorCode[] =
- "UpdateEngine.Attempt.InternalErrorCode";
-const char kMetricAttemptDownloadErrorCode[] =
- "UpdateEngine.Attempt.DownloadErrorCode";
-
-// UpdateEngine.SuccessfulUpdate.* metrics.
-const char kMetricSuccessfulUpdateAttemptCount[] =
- "UpdateEngine.SuccessfulUpdate.AttemptCount";
-const char kMetricSuccessfulUpdateBytesDownloadedMiB[] =
- "UpdateEngine.SuccessfulUpdate.BytesDownloadedMiB";
-const char kMetricSuccessfulUpdateDownloadOverheadPercentage[] =
- "UpdateEngine.SuccessfulUpdate.DownloadOverheadPercentage";
-const char kMetricSuccessfulUpdateDownloadSourcesUsed[] =
- "UpdateEngine.SuccessfulUpdate.DownloadSourcesUsed";
-const char kMetricSuccessfulUpdateDurationFromSeenDays[] =
- "UpdateEngine.SuccessfulUpdate.DurationFromSeenDays.NoTimeRestriction";
-const char kMetricSuccessfulUpdateDurationFromSeenTimeRestrictedDays[] =
- "UpdateEngine.SuccessfulUpdate.DurationFromSeenDays.TimeRestricted";
-const char kMetricSuccessfulUpdatePayloadType[] =
- "UpdateEngine.SuccessfulUpdate.PayloadType";
-const char kMetricSuccessfulUpdatePayloadSizeMiB[] =
- "UpdateEngine.SuccessfulUpdate.PayloadSizeMiB";
-const char kMetricSuccessfulUpdateRebootCount[] =
- "UpdateEngine.SuccessfulUpdate.RebootCount";
-const char kMetricSuccessfulUpdateTotalDurationMinutes[] =
- "UpdateEngine.SuccessfulUpdate.TotalDurationMinutes";
-const char kMetricSuccessfulUpdateTotalDurationUptimeMinutes[] =
- "UpdateEngine.SuccessfulUpdate.TotalDurationUptimeMinutes";
-const char kMetricSuccessfulUpdateUpdatesAbandonedCount[] =
- "UpdateEngine.SuccessfulUpdate.UpdatesAbandonedCount";
-const char kMetricSuccessfulUpdateUrlSwitchCount[] =
- "UpdateEngine.SuccessfulUpdate.UrlSwitchCount";
-
-// UpdateEngine.Rollback.* metric.
-const char kMetricRollbackResult[] = "UpdateEngine.Rollback.Result";
-
-// UpdateEngine.EnterpriseRollback.* metrics.
-const char kMetricEnterpriseRollbackFailure[] =
- "UpdateEngine.EnterpriseRollback.Failure";
-const char kMetricEnterpriseRollbackSuccess[] =
- "UpdateEngine.EnterpriseRollback.Success";
-
-// UpdateEngine.CertificateCheck.* metrics.
-const char kMetricCertificateCheckUpdateCheck[] =
- "UpdateEngine.CertificateCheck.UpdateCheck";
-const char kMetricCertificateCheckDownload[] =
- "UpdateEngine.CertificateCheck.Download";
-
-// UpdateEngine.KernelKey.* metrics.
-const char kMetricKernelMinVersion[] = "UpdateEngine.KernelKey.MinVersion";
-const char kMetricKernelMaxRollforwardVersion[] =
- "UpdateEngine.KernelKey.MaxRollforwardVersion";
-const char kMetricKernelMaxRollforwardSetSuccess[] =
- "UpdateEngine.KernelKey.MaxRollforwardSetSuccess";
-
-// UpdateEngine.* metrics.
-const char kMetricFailedUpdateCount[] = "UpdateEngine.FailedUpdateCount";
-const char kMetricInstallDateProvisioningSource[] =
- "UpdateEngine.InstallDateProvisioningSource";
-const char kMetricTimeToRebootMinutes[] = "UpdateEngine.TimeToRebootMinutes";
-
-std::unique_ptr<MetricsReporterInterface> CreateMetricsReporter(
- DynamicPartitionControlInterface* dynamic_partition_control) {
- return std::make_unique<MetricsReporterOmaha>();
-}
-
-} // namespace metrics
-
-MetricsReporterOmaha::MetricsReporterOmaha()
- : metrics_lib_(new MetricsLibrary()) {}
-
-void MetricsReporterOmaha::ReportDailyMetrics(base::TimeDelta os_age) {
- string metric = metrics::kMetricDailyOSAgeDays;
- metrics_lib_->SendToUMA(metric,
- static_cast<int>(os_age.InDays()),
- 0, // min: 0 days
- 6 * 30, // max: 6 months (approx)
- 50); // num_buckets
-}
-
-void MetricsReporterOmaha::ReportUpdateCheckMetrics(
- metrics::CheckResult result,
- metrics::CheckReaction reaction,
- metrics::DownloadErrorCode download_error_code) {
- string metric;
- int value;
- int max_value;
-
- if (result != metrics::CheckResult::kUnset) {
- metric = metrics::kMetricCheckResult;
- value = static_cast<int>(result);
- max_value = static_cast<int>(metrics::CheckResult::kNumConstants) - 1;
- 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;
- metrics_lib_->SendEnumToUMA(metric, value, max_value);
- }
- if (download_error_code != metrics::DownloadErrorCode::kUnset) {
- metric = metrics::kMetricCheckDownloadErrorCode;
- value = static_cast<int>(download_error_code);
- metrics_lib_->SendSparseToUMA(metric, value);
- }
-
- base::TimeDelta time_since_last;
- if (WallclockDurationHelper(kPrefsMetricsCheckLastReportingTime,
- &time_since_last)) {
- metric = metrics::kMetricCheckTimeSinceLastCheckMinutes;
- metrics_lib_->SendToUMA(metric,
- time_since_last.InMinutes(),
- 0, // min: 0 min
- 30 * 24 * 60, // max: 30 days
- 50); // num_buckets
- }
-
- base::TimeDelta uptime_since_last;
- static int64_t uptime_since_last_storage = 0;
- if (MonotonicDurationHelper(&uptime_since_last_storage, &uptime_since_last)) {
- metric = metrics::kMetricCheckTimeSinceLastCheckUptimeMinutes;
- metrics_lib_->SendToUMA(metric,
- uptime_since_last.InMinutes(),
- 0, // min: 0 min
- 30 * 24 * 60, // max: 30 days
- 50); // num_buckets
- }
-
- // First section of target version specified for the update.
- if (SystemState::Get()->request_params()) {
- string target_version =
- SystemState::Get()->request_params()->target_version_prefix();
- value = utils::VersionPrefix(target_version);
- if (value != 0) {
- metric = metrics::kMetricCheckTargetVersion;
- metrics_lib_->SendSparseToUMA(metric, value);
- if (SystemState::Get()->request_params()->rollback_allowed()) {
- metric = metrics::kMetricCheckRollbackTargetVersion;
- metrics_lib_->SendSparseToUMA(metric, value);
- }
- }
- }
-}
-
-void MetricsReporterOmaha::ReportAbnormallyTerminatedUpdateAttemptMetrics() {
- string metric = metrics::kMetricAttemptResult;
- metrics::AttemptResult attempt_result =
- metrics::AttemptResult::kAbnormalTermination;
-
- metrics_lib_->SendEnumToUMA(
- metric,
- static_cast<int>(attempt_result),
- static_cast<int>(metrics::AttemptResult::kNumConstants));
-}
-
-void MetricsReporterOmaha::ReportUpdateAttemptMetrics(
- 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) {
- string metric = metrics::kMetricAttemptNumber;
- metrics_lib_->SendToUMA(metric,
- attempt_number,
- 0, // min: 0 attempts
- 49, // max: 49 attempts
- 50); // num_buckets
-
- metric = metrics::kMetricAttemptPayloadType;
- metrics_lib_->SendEnumToUMA(metric, payload_type, kNumPayloadTypes);
-
- metric = metrics::kMetricAttemptDurationMinutes;
- metrics_lib_->SendToUMA(metric,
- duration.InMinutes(),
- 0, // min: 0 min
- 10 * 24 * 60, // max: 10 days
- 50); // num_buckets
-
- metric = metrics::kMetricAttemptDurationUptimeMinutes;
- metrics_lib_->SendToUMA(metric,
- duration_uptime.InMinutes(),
- 0, // min: 0 min
- 10 * 24 * 60, // max: 10 days
- 50); // num_buckets
-
- metric = metrics::kMetricAttemptPayloadSizeMiB;
- int64_t payload_size_mib = payload_size / kNumBytesInOneMiB;
- metrics_lib_->SendToUMA(metric,
- payload_size_mib,
- 0, // min: 0 MiB
- 1024, // max: 1024 MiB = 1 GiB
- 50); // num_buckets
-
- metric = metrics::kMetricAttemptResult;
- metrics_lib_->SendEnumToUMA(
- metric,
- static_cast<int>(attempt_result),
- static_cast<int>(metrics::AttemptResult::kNumConstants));
-
- if (internal_error_code != ErrorCode::kSuccess) {
- ReportInternalErrorCode(internal_error_code);
- }
-
- base::TimeDelta time_since_last;
- if (WallclockDurationHelper(kPrefsMetricsAttemptLastReportingTime,
- &time_since_last)) {
- metric = metrics::kMetricAttemptTimeSinceLastAttemptMinutes;
- metrics_lib_->SendToUMA(metric,
- time_since_last.InMinutes(),
- 0, // min: 0 min
- 30 * 24 * 60, // max: 30 days
- 50); // num_buckets
- }
-
- static int64_t uptime_since_last_storage = 0;
- base::TimeDelta uptime_since_last;
- if (MonotonicDurationHelper(&uptime_since_last_storage, &uptime_since_last)) {
- metric = metrics::kMetricAttemptTimeSinceLastAttemptUptimeMinutes;
- metrics_lib_->SendToUMA(metric,
- uptime_since_last.InMinutes(),
- 0, // min: 0 min
- 30 * 24 * 60, // max: 30 days
- 50); // num_buckets
- }
-}
-
-void MetricsReporterOmaha::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) {
- string metric = metrics::kMetricAttemptPayloadBytesDownloadedMiB;
- int64_t payload_bytes_downloaded_mib =
- payload_bytes_downloaded / kNumBytesInOneMiB;
- metrics_lib_->SendToUMA(metric,
- payload_bytes_downloaded_mib,
- 0, // min: 0 MiB
- 1024, // max: 1024 MiB = 1 GiB
- 50); // num_buckets
-
- metric = metrics::kMetricAttemptPayloadDownloadSpeedKBps;
- int64_t payload_download_speed_kbps = payload_download_speed_bps / 1000;
- metrics_lib_->SendToUMA(metric,
- payload_download_speed_kbps,
- 0, // min: 0 kB/s
- 10 * 1000, // max: 10000 kB/s = 10 MB/s
- 50); // num_buckets
-
- metric = metrics::kMetricAttemptDownloadSource;
- metrics_lib_->SendEnumToUMA(metric, download_source, kNumDownloadSources);
-
- if (payload_download_error_code != metrics::DownloadErrorCode::kUnset) {
- metric = metrics::kMetricAttemptDownloadErrorCode;
- metrics_lib_->SendSparseToUMA(
- metric, static_cast<int>(payload_download_error_code));
- }
-
- metric = metrics::kMetricAttemptConnectionType;
- metrics_lib_->SendEnumToUMA(
- metric,
- static_cast<int>(connection_type),
- static_cast<int>(metrics::ConnectionType::kNumConstants));
-}
-
-void MetricsReporterOmaha::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,
- base::TimeDelta total_duration_uptime,
- int reboot_count,
- int url_switch_count) {
- string metric = metrics::kMetricSuccessfulUpdatePayloadSizeMiB;
- int64_t mbs = payload_size / kNumBytesInOneMiB;
- metrics_lib_->SendToUMA(metric,
- mbs,
- 0, // min: 0 MiB
- 1024, // max: 1024 MiB = 1 GiB
- 50); // num_buckets
-
- int64_t total_bytes = 0;
- int download_sources_used = 0;
- for (int i = 0; i < kNumDownloadSources + 1; i++) {
- DownloadSource source = static_cast<DownloadSource>(i);
-
- // Only consider this download source (and send byte counts) as
- // having been used if we downloaded a non-trivial amount of bytes
- // (e.g. at least 1 MiB) that contributed to the
- // update. Otherwise we're going to end up with a lot of zero-byte
- // events in the histogram.
-
- metric = metrics::kMetricSuccessfulUpdateBytesDownloadedMiB;
- if (i < kNumDownloadSources) {
- metric += utils::ToString(source);
- mbs = num_bytes_downloaded[i] / kNumBytesInOneMiB;
- total_bytes += num_bytes_downloaded[i];
- if (mbs > 0)
- download_sources_used |= (1 << i);
- } else {
- mbs = total_bytes / kNumBytesInOneMiB;
- }
-
- if (mbs > 0) {
- metrics_lib_->SendToUMA(metric,
- mbs,
- 0, // min: 0 MiB
- 1024, // max: 1024 MiB = 1 GiB
- 50); // num_buckets
- }
- }
-
- metric = metrics::kMetricSuccessfulUpdateDownloadSourcesUsed;
- metrics_lib_->SendToUMA(metric,
- download_sources_used,
- 0, // min
- (1 << kNumDownloadSources) - 1, // max
- 1 << kNumDownloadSources); // num_buckets
-
- metric = metrics::kMetricSuccessfulUpdateDownloadOverheadPercentage;
- metrics_lib_->SendToUMA(metric,
- download_overhead_percentage,
- 0, // min: 0% overhead
- 1000, // max: 1000% overhead
- 50); // num_buckets
-
- metric = metrics::kMetricSuccessfulUpdateUrlSwitchCount;
- metrics_lib_->SendToUMA(metric,
- url_switch_count,
- 0, // min: 0 URL switches
- 49, // max: 49 URL switches
- 50); // num_buckets
-
- metric = metrics::kMetricSuccessfulUpdateTotalDurationMinutes;
- metrics_lib_->SendToUMA(metric,
- static_cast<int>(total_duration.InMinutes()),
- 0, // min: 0 min
- 365 * 24 * 60, // max: 365 days ~= 1 year
- 50); // num_buckets
-
- metric = metrics::kMetricSuccessfulUpdateTotalDurationUptimeMinutes;
- metrics_lib_->SendToUMA(metric,
- static_cast<int>(total_duration_uptime.InMinutes()),
- 0, // min: 0 min
- 30 * 24 * 60, // max: 30 days
- 50); // num_buckets
-
- metric = metrics::kMetricSuccessfulUpdateRebootCount;
- metrics_lib_->SendToUMA(metric,
- reboot_count,
- 0, // min: 0 reboots
- 49, // max: 49 reboots
- 50); // num_buckets
-
- metric = metrics::kMetricSuccessfulUpdatePayloadType;
- metrics_lib_->SendEnumToUMA(metric, payload_type, kNumPayloadTypes);
-
- metric = metrics::kMetricSuccessfulUpdateAttemptCount;
- metrics_lib_->SendToUMA(metric,
- attempt_count,
- 1, // min: 1 attempt
- 50, // max: 50 attempts
- 50); // num_buckets
-
- metric = metrics::kMetricSuccessfulUpdateUpdatesAbandonedCount;
- metrics_lib_->SendToUMA(metric,
- updates_abandoned_count,
- 0, // min: 0 counts
- 49, // max: 49 counts
- 50); // num_buckets
-}
-
-void MetricsReporterOmaha::ReportRollbackMetrics(
- metrics::RollbackResult result) {
- string metric = metrics::kMetricRollbackResult;
- int value = static_cast<int>(result);
- metrics_lib_->SendEnumToUMA(
- metric, value, static_cast<int>(metrics::RollbackResult::kNumConstants));
-}
-
-void MetricsReporterOmaha::ReportEnterpriseRollbackMetrics(
- bool success, const string& rollback_version) {
- int value = utils::VersionPrefix(rollback_version);
- string metric = metrics::kMetricEnterpriseRollbackSuccess;
- if (!success)
- metric = metrics::kMetricEnterpriseRollbackFailure;
- metrics_lib_->SendSparseToUMA(metric, value);
-}
-
-void MetricsReporterOmaha::ReportCertificateCheckMetrics(
- ServerToCheck server_to_check, CertificateCheckResult result) {
- string metric;
- switch (server_to_check) {
- case ServerToCheck::kUpdate:
- metric = metrics::kMetricCertificateCheckUpdateCheck;
- break;
- case ServerToCheck::kDownload:
- metric = metrics::kMetricCertificateCheckDownload;
- break;
- case ServerToCheck::kNone:
- return;
- }
- metrics_lib_->SendEnumToUMA(
- metric,
- static_cast<int>(result),
- static_cast<int>(CertificateCheckResult::kNumConstants));
-}
-
-void MetricsReporterOmaha::ReportFailedUpdateCount(int target_attempt) {
- string metric = metrics::kMetricFailedUpdateCount;
- metrics_lib_->SendToUMA(metric,
- target_attempt,
- 1, // min value
- 50, // max value
- kNumDefaultUmaBuckets);
-}
-
-void MetricsReporterOmaha::ReportTimeToReboot(int time_to_reboot_minutes) {
- string metric = metrics::kMetricTimeToRebootMinutes;
- metrics_lib_->SendToUMA(metric,
- time_to_reboot_minutes,
- 0, // min: 0 minute
- 30 * 24 * 60, // max: 1 month (approx)
- kNumDefaultUmaBuckets);
-}
-
-void MetricsReporterOmaha::ReportInstallDateProvisioningSource(int source,
- int max) {
- metrics_lib_->SendEnumToUMA(metrics::kMetricInstallDateProvisioningSource,
- source, // Sample.
- max);
-}
-
-void MetricsReporterOmaha::ReportInternalErrorCode(ErrorCode error_code) {
- auto metric = metrics::kMetricAttemptInternalErrorCode;
- metrics_lib_->SendEnumToUMA(metric,
- static_cast<int>(error_code),
- static_cast<int>(ErrorCode::kUmaReportedMax));
-}
-
-void MetricsReporterOmaha::ReportKeyVersionMetrics(
- int kernel_min_version,
- int kernel_max_rollforward_version,
- bool kernel_max_rollforward_success) {
- int value = kernel_min_version;
- string metric = metrics::kMetricKernelMinVersion;
- metrics_lib_->SendSparseToUMA(metric, value);
-
- value = kernel_max_rollforward_version;
- metric = metrics::kMetricKernelMaxRollforwardVersion;
- metrics_lib_->SendSparseToUMA(metric, value);
-
- bool bool_value = kernel_max_rollforward_success;
- metric = metrics::kMetricKernelMaxRollforwardSetSuccess;
- metrics_lib_->SendBoolToUMA(metric, bool_value);
-}
-
-void MetricsReporterOmaha::ReportEnterpriseUpdateSeenToDownloadDays(
- bool has_time_restriction_policy, int time_to_update_days) {
- string metric =
- has_time_restriction_policy
- ? metrics::kMetricSuccessfulUpdateDurationFromSeenTimeRestrictedDays
- : metrics::kMetricSuccessfulUpdateDurationFromSeenDays;
-
- metrics_lib_->SendToUMA(metric,
- time_to_update_days,
- 1, // min: 1 days
- 6 * 30, // max: 6 months (approx)
- 50); // num_buckets
-}
-
-bool MetricsReporterOmaha::WallclockDurationHelper(
- const std::string& state_variable_key,
- TimeDelta* out_duration) {
- bool ret = false;
- Time now = SystemState::Get()->clock()->GetWallclockTime();
- int64_t stored_value;
- if (SystemState::Get()->prefs()->GetInt64(state_variable_key,
- &stored_value)) {
- Time stored_time = Time::FromInternalValue(stored_value);
- if (stored_time > now) {
- LOG(ERROR) << "Stored time-stamp used for " << state_variable_key
- << " is in the future.";
- } else {
- *out_duration = now - stored_time;
- ret = true;
- }
- }
-
- if (!SystemState::Get()->prefs()->SetInt64(state_variable_key,
- now.ToInternalValue())) {
- LOG(ERROR) << "Error storing time-stamp in " << state_variable_key;
- }
-
- return ret;
-}
-
-bool MetricsReporterOmaha::MonotonicDurationHelper(int64_t* storage,
- TimeDelta* out_duration) {
- bool ret = false;
- Time now = SystemState::Get()->clock()->GetMonotonicTime();
- if (*storage != 0) {
- Time stored_time = Time::FromInternalValue(*storage);
- *out_duration = now - stored_time;
- ret = true;
- }
- *storage = now.ToInternalValue();
-
- return ret;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/metrics_reporter_omaha.h b/cros/metrics_reporter_omaha.h
deleted file mode 100644
index b6ffccee..00000000
--- a/cros/metrics_reporter_omaha.h
+++ /dev/null
@@ -1,202 +0,0 @@
-//
-// 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_CROS_METRICS_REPORTER_OMAHA_H_
-#define UPDATE_ENGINE_CROS_METRICS_REPORTER_OMAHA_H_
-
-#include <memory>
-#include <string>
-
-#include <base/time/time.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-#include <metrics/metrics_library.h>
-
-#include "update_engine/certificate_checker.h"
-#include "update_engine/common/constants.h"
-#include "update_engine/common/error_code.h"
-#include "update_engine/common/metrics_constants.h"
-#include "update_engine/common/metrics_reporter_interface.h"
-
-namespace chromeos_update_engine {
-
-class SystemState;
-
-namespace metrics {
-
-// UpdateEngine.Daily.* metrics.
-extern const char kMetricDailyOSAgeDays[];
-
-// UpdateEngine.Check.* metrics.
-extern const char kMetricCheckDownloadErrorCode[];
-extern const char kMetricCheckReaction[];
-extern const char kMetricCheckResult[];
-extern const char kMetricCheckTargetVersion[];
-extern const char kMetricCheckRollbackTargetVersion[];
-extern const char kMetricCheckTimeSinceLastCheckMinutes[];
-extern const char kMetricCheckTimeSinceLastCheckUptimeMinutes[];
-
-// UpdateEngine.Attempt.* metrics.
-extern const char kMetricAttemptNumber[];
-extern const char kMetricAttemptPayloadType[];
-extern const char kMetricAttemptPayloadSizeMiB[];
-extern const char kMetricAttemptConnectionType[];
-extern const char kMetricAttemptDurationMinutes[];
-extern const char kMetricAttemptDurationUptimeMinutes[];
-extern const char kMetricAttemptTimeSinceLastAttemptMinutes[];
-extern const char kMetricAttemptTimeSinceLastAttemptUptimeMinutes[];
-extern const char kMetricAttemptPayloadBytesDownloadedMiB[];
-extern const char kMetricAttemptPayloadDownloadSpeedKBps[];
-extern const char kMetricAttemptDownloadSource[];
-extern const char kMetricAttemptResult[];
-extern const char kMetricAttemptInternalErrorCode[];
-extern const char kMetricAttemptDownloadErrorCode[];
-
-// UpdateEngine.SuccessfulUpdate.* metrics.
-extern const char kMetricSuccessfulUpdateAttemptCount[];
-extern const char kMetricSuccessfulUpdateBytesDownloadedMiB[];
-extern const char kMetricSuccessfulUpdateDownloadOverheadPercentage[];
-extern const char kMetricSuccessfulUpdateDownloadSourcesUsed[];
-extern const char kMetricSuccessfulUpdateDurationFromSeenDays[];
-extern const char kMetricSuccessfulUpdateDurationFromSeenTimeRestrictedDays[];
-extern const char kMetricSuccessfulUpdatePayloadType[];
-extern const char kMetricSuccessfulUpdatePayloadSizeMiB[];
-extern const char kMetricSuccessfulUpdateRebootCount[];
-extern const char kMetricSuccessfulUpdateTotalDurationMinutes[];
-extern const char kMetricSuccessfulUpdateTotalDurationUptimeMinutes[];
-extern const char kMetricSuccessfulUpdateUpdatesAbandonedCount[];
-extern const char kMetricSuccessfulUpdateUrlSwitchCount[];
-
-// UpdateEngine.Rollback.* metric.
-extern const char kMetricRollbackResult[];
-
-// UpdateEngine.EnterpriseRollback.* metrics.
-extern const char kMetricEnterpriseRollbackFailure[];
-extern const char kMetricEnterpriseRollbackSuccess[];
-
-// UpdateEngine.CertificateCheck.* metrics.
-extern const char kMetricCertificateCheckUpdateCheck[];
-extern const char kMetricCertificateCheckDownload[];
-
-// UpdateEngine.KernelKey.* metrics.
-extern const char kMetricKernelMinVersion[];
-extern const char kMetricKernelMaxRollforwardVersion[];
-extern const char kMetricKernelMaxRollforwardSetSuccess[];
-
-// UpdateEngine.* metrics.
-extern const char kMetricFailedUpdateCount[];
-extern const char kMetricInstallDateProvisioningSource[];
-extern const char kMetricTimeToRebootMinutes[];
-
-} // namespace metrics
-
-class MetricsReporterOmaha : public MetricsReporterInterface {
- public:
- MetricsReporterOmaha();
-
- ~MetricsReporterOmaha() override = default;
-
- void ReportRollbackMetrics(metrics::RollbackResult result) override;
-
- void ReportEnterpriseRollbackMetrics(
- bool success, const std::string& rollback_version) override;
-
- void ReportDailyMetrics(base::TimeDelta os_age) override;
-
- void ReportUpdateCheckMetrics(
- metrics::CheckResult result,
- metrics::CheckReaction reaction,
- metrics::DownloadErrorCode download_error_code) override;
-
- void ReportUpdateAttemptMetrics(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,
- base::TimeDelta total_duration_uptime,
- 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;
-
- void ReportInternalErrorCode(ErrorCode error_code) override;
-
- void ReportKeyVersionMetrics(int kernel_min_version,
- int kernel_max_rollforward_version,
- bool kernel_max_rollforward_success) override;
-
- void ReportEnterpriseUpdateSeenToDownloadDays(
- bool has_time_restriction_policy, int time_to_update_days) override;
-
- private:
- friend class MetricsReporterOmahaTest;
- FRIEND_TEST(MetricsReporterOmahaTest, WallclockDurationHelper);
- FRIEND_TEST(MetricsReporterOmahaTest, MonotonicDurationHelper);
-
- // This function returns the duration on the wallclock since the last
- // time it was called for the same |state_variable_key| value.
- //
- // If the function returns |true|, the duration (always non-negative)
- // is returned in |out_duration|. If the function returns |false|
- // something went wrong or there was no previous measurement.
- bool WallclockDurationHelper(const std::string& state_variable_key,
- base::TimeDelta* out_duration);
-
- // This function returns the duration on the monotonic clock since the
- // last time it was called for the same |storage| pointer.
- //
- // You should pass a pointer to a 64-bit integer in |storage| which
- // should be initialized to 0.
- //
- // If the function returns |true|, the duration (always non-negative)
- // is returned in |out_duration|. If the function returns |false|
- // something went wrong or there was no previous measurement.
- bool MonotonicDurationHelper(int64_t* storage, base::TimeDelta* out_duration);
-
- std::unique_ptr<MetricsLibraryInterface> metrics_lib_;
-
- DISALLOW_COPY_AND_ASSIGN(MetricsReporterOmaha);
-}; // class metrics
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_METRICS_REPORTER_OMAHA_H_
diff --git a/cros/metrics_reporter_omaha_unittest.cc b/cros/metrics_reporter_omaha_unittest.cc
deleted file mode 100644
index cdc44cdc..00000000
--- a/cros/metrics_reporter_omaha_unittest.cc
+++ /dev/null
@@ -1,607 +0,0 @@
-//
-// 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/cros/metrics_reporter_omaha.h"
-
-#include <memory>
-#include <string>
-
-#include <base/time/time.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <metrics/metrics_library_mock.h>
-
-#include "update_engine/common/fake_clock.h"
-#include "update_engine/cros/fake_system_state.h"
-
-using base::TimeDelta;
-using testing::_;
-using testing::AnyNumber;
-using testing::Return;
-
-namespace chromeos_update_engine {
-class MetricsReporterOmahaTest : public ::testing::Test {
- protected:
- MetricsReporterOmahaTest() = default;
-
- // Reset the metrics_lib_ to a mock library.
- void SetUp() override {
- FakeSystemState::CreateInstance();
- fake_clock_ = FakeSystemState::Get()->fake_clock();
- mock_metrics_lib_ = new testing::NiceMock<MetricsLibraryMock>();
- reporter_.metrics_lib_.reset(mock_metrics_lib_);
- }
-
- testing::NiceMock<MetricsLibraryMock>* mock_metrics_lib_;
- MetricsReporterOmaha reporter_;
-
- FakeClock* fake_clock_;
-};
-
-TEST_F(MetricsReporterOmahaTest, ReportDailyMetrics) {
- TimeDelta age = TimeDelta::FromDays(10);
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricDailyOSAgeDays, _, _, _, _))
- .Times(1);
-
- reporter_.ReportDailyMetrics(age);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetrics) {
- // We need to execute the report twice to test the time since last report.
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(1000000));
- fake_clock_->SetMonotonicTime(base::Time::FromInternalValue(1000000));
-
- metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
- metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
- metrics::DownloadErrorCode error_code =
- metrics::DownloadErrorCode::kHttpStatus200;
-
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricCheckResult, static_cast<int>(result), _))
- .Times(2);
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(
- metrics::kMetricCheckReaction, static_cast<int>(reaction), _))
- .Times(2);
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode,
- static_cast<int>(error_code)))
- .Times(2);
-
- // Not pinned nor rollback
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckTargetVersion, _))
- .Times(0);
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
- .Times(0);
-
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricCheckTimeSinceLastCheckMinutes, 1, _, _, _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricCheckTimeSinceLastCheckUptimeMinutes, 1, _, _, _))
- .Times(1);
-
- reporter_.ReportUpdateCheckMetrics(result, reaction, error_code);
-
- // Advance the clock by 1 minute and report the same metrics again.
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(61000000));
- fake_clock_->SetMonotonicTime(base::Time::FromInternalValue(61000000));
- // Allow rollback
- reporter_.ReportUpdateCheckMetrics(result, reaction, error_code);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsPinned) {
- OmahaRequestParams params;
- params.set_target_version_prefix("10575.");
- params.set_rollback_allowed(false);
- FakeSystemState::Get()->set_request_params(&params);
-
- metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
- metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
- metrics::DownloadErrorCode error_code =
- metrics::DownloadErrorCode::kHttpStatus200;
-
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
- // Target version set, but not a rollback.
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, _))
- .Times(0);
-
- reporter_.ReportUpdateCheckMetrics(result, reaction, error_code);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportUpdateCheckMetricsRollback) {
- OmahaRequestParams params;
- params.set_target_version_prefix("10575.");
- params.set_rollback_allowed(true);
- FakeSystemState::Get()->set_request_params(&params);
-
- metrics::CheckResult result = metrics::CheckResult::kUpdateAvailable;
- metrics::CheckReaction reaction = metrics::CheckReaction::kIgnored;
- metrics::DownloadErrorCode error_code =
- metrics::DownloadErrorCode::kHttpStatus200;
-
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckDownloadErrorCode, _));
- // Rollback.
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckTargetVersion, 10575))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricCheckRollbackTargetVersion, 10575))
- .Times(1);
-
- reporter_.ReportUpdateCheckMetrics(result, reaction, error_code);
-}
-
-TEST_F(MetricsReporterOmahaTest,
- ReportAbnormallyTerminatedUpdateAttemptMetrics) {
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricAttemptResult,
- static_cast<int>(
- metrics::AttemptResult::kAbnormalTermination),
- _))
- .Times(1);
-
- reporter_.ReportAbnormallyTerminatedUpdateAttemptMetrics();
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportUpdateAttemptMetrics) {
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(1000000));
- fake_clock_->SetMonotonicTime(base::Time::FromInternalValue(1000000));
-
- int attempt_number = 1;
- PayloadType payload_type = kPayloadTypeFull;
- TimeDelta duration = TimeDelta::FromMinutes(1000);
- TimeDelta duration_uptime = TimeDelta::FromMinutes(1000);
-
- int64_t payload_size = 100 * kNumBytesInOneMiB;
-
- metrics::AttemptResult attempt_result =
- metrics::AttemptResult::kInternalError;
- ErrorCode internal_error_code = ErrorCode::kDownloadInvalidMetadataSignature;
-
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricAttemptNumber, attempt_number, _, _, _))
- .Times(2);
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricAttemptPayloadType,
- static_cast<int>(payload_type),
- _))
- .Times(2);
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricAttemptDurationMinutes,
- duration.InMinutes(),
- _,
- _,
- _))
- .Times(2);
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricAttemptDurationUptimeMinutes,
- duration_uptime.InMinutes(),
- _,
- _,
- _))
- .Times(2);
-
- // Check the report of attempt result.
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendEnumToUMA(
- metrics::kMetricAttemptResult, static_cast<int>(attempt_result), _))
- .Times(2);
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricAttemptInternalErrorCode,
- static_cast<int>(internal_error_code),
- _))
- .Times(2);
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricAttemptPayloadSizeMiB, 100, _, _, _))
- .Times(2);
-
- // Check the duration between two reports.
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricAttemptTimeSinceLastAttemptMinutes, 1, _, _, _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricAttemptTimeSinceLastAttemptUptimeMinutes, 1, _, _, _))
- .Times(1);
-
- reporter_.ReportUpdateAttemptMetrics(attempt_number,
- payload_type,
- duration,
- duration_uptime,
- payload_size,
- attempt_result,
- internal_error_code);
-
- // Advance the clock by 1 minute and report the same metrics again.
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(61000000));
- fake_clock_->SetMonotonicTime(base::Time::FromInternalValue(61000000));
- reporter_.ReportUpdateAttemptMetrics(attempt_number,
- payload_type,
- duration,
- duration_uptime,
- payload_size,
- attempt_result,
- internal_error_code);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportUpdateAttemptDownloadMetrics) {
- int64_t payload_bytes_downloaded = 200 * kNumBytesInOneMiB;
- int64_t payload_download_speed_bps = 100 * 1000;
- DownloadSource download_source = kDownloadSourceHttpServer;
- metrics::DownloadErrorCode payload_download_error_code =
- metrics::DownloadErrorCode::kDownloadError;
- metrics::ConnectionType connection_type = metrics::ConnectionType::kCellular;
-
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricAttemptPayloadBytesDownloadedMiB, 200, _, _, _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricAttemptPayloadDownloadSpeedKBps, 100, _, _, _))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricAttemptDownloadSource,
- static_cast<int>(download_source),
- _))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricAttemptDownloadErrorCode,
- static_cast<int>(payload_download_error_code)))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricAttemptConnectionType,
- static_cast<int>(connection_type),
- _))
- .Times(1);
-
- reporter_.ReportUpdateAttemptDownloadMetrics(payload_bytes_downloaded,
- payload_download_speed_bps,
- download_source,
- payload_download_error_code,
- connection_type);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportSuccessfulUpdateMetrics) {
- int attempt_count = 3;
- int updates_abandoned_count = 2;
- PayloadType payload_type = kPayloadTypeDelta;
- int64_t payload_size = 200 * kNumBytesInOneMiB;
- int64_t num_bytes_downloaded[kNumDownloadSources] = {};
- // 200MiB payload downloaded from HttpsServer.
- num_bytes_downloaded[0] = 200 * kNumBytesInOneMiB;
- int download_overhead_percentage = 20;
- TimeDelta total_duration = TimeDelta::FromMinutes(30);
- TimeDelta total_duration_uptime = TimeDelta::FromMinutes(20);
- int reboot_count = 2;
- int url_switch_count = 2;
-
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricSuccessfulUpdatePayloadSizeMiB, 200, _, _, _))
- .Times(1);
-
- // Check the report to both BytesDownloadedMiBHttpsServer and
- // BytesDownloadedMiB
- std::string DownloadedMiBMetric =
- metrics::kMetricSuccessfulUpdateBytesDownloadedMiB;
- DownloadedMiBMetric += "HttpsServer";
- EXPECT_CALL(*mock_metrics_lib_, SendToUMA(DownloadedMiBMetric, 200, _, _, _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricSuccessfulUpdateBytesDownloadedMiB, 200, _, _, _))
- .Times(1);
-
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricSuccessfulUpdateDownloadSourcesUsed, 1, _, _, _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricSuccessfulUpdateDownloadOverheadPercentage,
- 20,
- _,
- _,
- _));
-
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricSuccessfulUpdateUrlSwitchCount,
- url_switch_count,
- _,
- _,
- _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricSuccessfulUpdateTotalDurationMinutes, 30, _, _, _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricSuccessfulUpdateTotalDurationUptimeMinutes,
- 20,
- _,
- _,
- _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricSuccessfulUpdateRebootCount, reboot_count, _, _, _))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(
- metrics::kMetricSuccessfulUpdatePayloadType, payload_type, _))
- .Times(1);
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricSuccessfulUpdateAttemptCount, attempt_count, _, _, _))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricSuccessfulUpdateUpdatesAbandonedCount,
- updates_abandoned_count,
- _,
- _,
- _))
- .Times(1);
-
- reporter_.ReportSuccessfulUpdateMetrics(attempt_count,
- updates_abandoned_count,
- payload_type,
- payload_size,
- num_bytes_downloaded,
- download_overhead_percentage,
- total_duration,
- total_duration_uptime,
- reboot_count,
- url_switch_count);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportRollbackMetrics) {
- metrics::RollbackResult result = metrics::RollbackResult::kSuccess;
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(
- metrics::kMetricRollbackResult, static_cast<int>(result), _))
- .Times(1);
-
- reporter_.ReportRollbackMetrics(result);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportEnterpriseRollbackMetrics) {
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricEnterpriseRollbackSuccess, 10575))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricEnterpriseRollbackFailure, 10323))
- .Times(1);
-
- reporter_.ReportEnterpriseRollbackMetrics(/*success=*/true, "10575.39.2");
- reporter_.ReportEnterpriseRollbackMetrics(/*success=*/false, "10323.67.7");
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportCertificateCheckMetrics) {
- ServerToCheck server_to_check = ServerToCheck::kUpdate;
- CertificateCheckResult result = CertificateCheckResult::kValid;
- EXPECT_CALL(*mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricCertificateCheckUpdateCheck,
- static_cast<int>(result),
- _))
- .Times(1);
-
- reporter_.ReportCertificateCheckMetrics(server_to_check, result);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportFailedUpdateCount) {
- int target_attempt = 3;
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(metrics::kMetricFailedUpdateCount, target_attempt, _, _, _))
- .Times(1);
-
- reporter_.ReportFailedUpdateCount(target_attempt);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportTimeToReboot) {
- int time_to_reboot_minutes = 1000;
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricTimeToRebootMinutes, time_to_reboot_minutes, _, _, _))
- .Times(1);
-
- reporter_.ReportTimeToReboot(time_to_reboot_minutes);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportInstallDateProvisioningSource) {
- int source = 2;
- int max = 5;
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendEnumToUMA(metrics::kMetricInstallDateProvisioningSource, source, max))
- .Times(1);
-
- reporter_.ReportInstallDateProvisioningSource(source, max);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportKeyVersionMetrics) {
- int kernel_min_version = 0x00040002;
- int kernel_max_rollforward_version = 0xfffffffe;
- bool kernel_max_rollforward_success = true;
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricKernelMinVersion, kernel_min_version))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendSparseToUMA(metrics::kMetricKernelMaxRollforwardVersion,
- kernel_max_rollforward_version))
- .Times(1);
- EXPECT_CALL(*mock_metrics_lib_,
- SendBoolToUMA(metrics::kMetricKernelMaxRollforwardSetSuccess,
- kernel_max_rollforward_success))
- .Times(1);
-
- reporter_.ReportKeyVersionMetrics(kernel_min_version,
- kernel_max_rollforward_version,
- kernel_max_rollforward_success);
-}
-
-TEST_F(MetricsReporterOmahaTest, ReportEnterpriseUpdateSeenToDownloadDays) {
- constexpr int kDaysToUpdate = 10;
- constexpr int kMinBucket = 1;
- constexpr int kMaxBucket = 6 * 30; // approximately 6 months
- constexpr int kNumBuckets = 50;
-
- EXPECT_CALL(*mock_metrics_lib_,
- SendToUMA(metrics::kMetricSuccessfulUpdateDurationFromSeenDays,
- kDaysToUpdate,
- kMinBucket,
- kMaxBucket,
- kNumBuckets))
- .Times(1);
-
- reporter_.ReportEnterpriseUpdateSeenToDownloadDays(
- false /* has_time_restriction_policy */, kDaysToUpdate);
-}
-
-TEST_F(MetricsReporterOmahaTest,
- ReportEnterpriseTimeRestrictedUpdateSeenToDownloadTime) {
- const int kDaysToUpdate = 15;
- constexpr int kMinBucket = 1;
- constexpr int kMaxBucket = 6 * 30; // approximately 6 months
- constexpr int kNumBuckets = 50;
-
- EXPECT_CALL(
- *mock_metrics_lib_,
- SendToUMA(
- metrics::kMetricSuccessfulUpdateDurationFromSeenTimeRestrictedDays,
- kDaysToUpdate,
- kMinBucket,
- kMaxBucket,
- kNumBuckets))
- .Times(1);
-
- reporter_.ReportEnterpriseUpdateSeenToDownloadDays(
- true /* has_time_restriction_policy */, kDaysToUpdate);
-}
-
-TEST_F(MetricsReporterOmahaTest, WallclockDurationHelper) {
- base::TimeDelta duration;
- const std::string state_variable_key = "test-prefs";
-
- // Initialize wallclock to 1 sec.
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(1000000));
-
- // First time called so no previous measurement available.
- EXPECT_FALSE(
- reporter_.WallclockDurationHelper(state_variable_key, &duration));
-
- // Next time, we should get zero since the clock didn't advance.
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-
- // We can also call it as many times as we want with it being
- // considered a failure.
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-
- // Advance the clock one second, then we should get 1 sec on the
- // next call and 0 sec on the subsequent call.
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(2000000));
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 1);
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-
- // Advance clock two seconds and we should get 2 sec and then 0 sec.
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(4000000));
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 2);
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-
- // There's a possibility that the wallclock can go backwards (NTP
- // adjustments, for example) so check that we properly handle this
- // case.
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(3000000));
- EXPECT_FALSE(
- reporter_.WallclockDurationHelper(state_variable_key, &duration));
- fake_clock_->SetWallclockTime(base::Time::FromInternalValue(4000000));
- EXPECT_TRUE(reporter_.WallclockDurationHelper(state_variable_key, &duration));
- EXPECT_EQ(duration.InSeconds(), 1);
-}
-
-TEST_F(MetricsReporterOmahaTest, MonotonicDurationHelper) {
- int64_t storage = 0;
- base::TimeDelta duration;
-
- // Initialize monotonic clock to 1 sec.
- fake_clock_->SetMonotonicTime(base::Time::FromInternalValue(1000000));
-
- // First time called so no previous measurement available.
- EXPECT_FALSE(reporter_.MonotonicDurationHelper(&storage, &duration));
-
- // Next time, we should get zero since the clock didn't advance.
- EXPECT_TRUE(reporter_.MonotonicDurationHelper(&storage, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-
- // We can also call it as many times as we want with it being
- // considered a failure.
- EXPECT_TRUE(reporter_.MonotonicDurationHelper(&storage, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
- EXPECT_TRUE(reporter_.MonotonicDurationHelper(&storage, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-
- // Advance the clock one second, then we should get 1 sec on the
- // next call and 0 sec on the subsequent call.
- fake_clock_->SetMonotonicTime(base::Time::FromInternalValue(2000000));
- EXPECT_TRUE(reporter_.MonotonicDurationHelper(&storage, &duration));
- EXPECT_EQ(duration.InSeconds(), 1);
- EXPECT_TRUE(reporter_.MonotonicDurationHelper(&storage, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-
- // Advance clock two seconds and we should get 2 sec and then 0 sec.
- fake_clock_->SetMonotonicTime(base::Time::FromInternalValue(4000000));
- EXPECT_TRUE(reporter_.MonotonicDurationHelper(&storage, &duration));
- EXPECT_EQ(duration.InSeconds(), 2);
- EXPECT_TRUE(reporter_.MonotonicDurationHelper(&storage, &duration));
- EXPECT_EQ(duration.InSeconds(), 0);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/mock_connection_manager.h b/cros/mock_connection_manager.h
deleted file mode 100644
index 899a49b1..00000000
--- a/cros/mock_connection_manager.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_MOCK_CONNECTION_MANAGER_H_
-#define UPDATE_ENGINE_CROS_MOCK_CONNECTION_MANAGER_H_
-
-#include <gmock/gmock.h>
-
-#include "update_engine/cros/connection_manager_interface.h"
-
-namespace chromeos_update_engine {
-
-// This class mocks the generic interface to the connection manager
-// (e.g FlimFlam, Shill, etc.) to consolidate all connection-related
-// logic in update_engine.
-class MockConnectionManager : public ConnectionManagerInterface {
- public:
- MockConnectionManager() = default;
-
- MOCK_METHOD2(GetConnectionProperties,
- bool(ConnectionType* out_type,
- ConnectionTethering* out_tethering));
-
- MOCK_CONST_METHOD2(IsUpdateAllowedOver,
- bool(ConnectionType type, ConnectionTethering tethering));
- MOCK_CONST_METHOD0(IsAllowedConnectionTypesForUpdateSet, bool());
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_MOCK_CONNECTION_MANAGER_H_
diff --git a/cros/mock_omaha_request_params.h b/cros/mock_omaha_request_params.h
deleted file mode 100644
index 1e218124..00000000
--- a/cros/mock_omaha_request_params.h
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-// Copyright (C) 2014 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_CROS_MOCK_OMAHA_REQUEST_PARAMS_H_
-#define UPDATE_ENGINE_CROS_MOCK_OMAHA_REQUEST_PARAMS_H_
-
-#include <string>
-
-#include <gmock/gmock.h>
-
-#include "update_engine/cros/omaha_request_params.h"
-
-namespace chromeos_update_engine {
-
-class MockOmahaRequestParams : public OmahaRequestParams {
- public:
- MockOmahaRequestParams() : OmahaRequestParams() {
- // Delegate all calls to the parent instance by default. This helps the
- // migration from tests using the real RequestParams when they should have
- // use a fake or mock.
- ON_CALL(*this, GetAppId())
- .WillByDefault(
- testing::Invoke(this, &MockOmahaRequestParams::FakeGetAppId));
- ON_CALL(*this, SetTargetChannel(testing::_, testing::_, testing::_))
- .WillByDefault(testing::Invoke(
- this, &MockOmahaRequestParams::FakeSetTargetChannel));
- ON_CALL(*this, UpdateDownloadChannel())
- .WillByDefault(testing::Invoke(
- this, &MockOmahaRequestParams::FakeUpdateDownloadChannel));
- ON_CALL(*this, ShouldPowerwash())
- .WillByDefault(testing::Invoke(
- this, &MockOmahaRequestParams::FakeShouldPowerwash));
- }
-
- MOCK_CONST_METHOD0(GetAppId, std::string(void));
- MOCK_METHOD3(SetTargetChannel,
- bool(const std::string& channel,
- bool is_powerwash_allowed,
- std::string* error));
- MOCK_CONST_METHOD0(target_version_prefix, std::string(void));
- MOCK_METHOD0(UpdateDownloadChannel, void(void));
- MOCK_CONST_METHOD0(IsUpdateUrlOfficial, bool(void));
- MOCK_CONST_METHOD0(ShouldPowerwash, bool(void));
-
- private:
- // Wrappers to call the parent class and behave like the real object by
- // default. See "Delegating Calls to a Parent Class" in gmock's documentation.
- std::string FakeGetAppId() const { return OmahaRequestParams::GetAppId(); }
-
- bool FakeSetTargetChannel(const std::string& channel,
- bool is_powerwash_allowed,
- std::string* error) {
- return OmahaRequestParams::SetTargetChannel(
- channel, is_powerwash_allowed, error);
- }
-
- void FakeUpdateDownloadChannel() {
- return OmahaRequestParams::UpdateDownloadChannel();
- }
-
- bool FakeShouldPowerwash() const {
- return OmahaRequestParams::ShouldPowerwash();
- }
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_MOCK_OMAHA_REQUEST_PARAMS_H_
diff --git a/cros/mock_p2p_manager.h b/cros/mock_p2p_manager.h
deleted file mode 100644
index 273f7f9c..00000000
--- a/cros/mock_p2p_manager.h
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// Copyright (C) 2013 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_CROS_MOCK_P2P_MANAGER_H_
-#define UPDATE_ENGINE_CROS_MOCK_P2P_MANAGER_H_
-
-#include <string>
-
-#include "update_engine/cros/fake_p2p_manager.h"
-
-#include <gmock/gmock.h>
-
-namespace chromeos_update_engine {
-
-// A mocked, fake implementation of P2PManager.
-class MockP2PManager : public P2PManager {
- public:
- MockP2PManager() {
- // Delegate all calls to the fake instance
- ON_CALL(*this, SetDevicePolicy(testing::_))
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::SetDevicePolicy));
- ON_CALL(*this, IsP2PEnabled())
- .WillByDefault(testing::Invoke(&fake_, &FakeP2PManager::IsP2PEnabled));
- ON_CALL(*this, EnsureP2PRunning())
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::EnsureP2PRunning));
- ON_CALL(*this, EnsureP2PNotRunning())
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::EnsureP2PNotRunning));
- ON_CALL(*this, PerformHousekeeping())
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::PerformHousekeeping));
- ON_CALL(*this,
- LookupUrlForFile(testing::_, testing::_, testing::_, testing::_))
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::LookupUrlForFile));
- ON_CALL(*this, FileShare(testing::_, testing::_))
- .WillByDefault(testing::Invoke(&fake_, &FakeP2PManager::FileShare));
- ON_CALL(*this, FileGetPath(testing::_))
- .WillByDefault(testing::Invoke(&fake_, &FakeP2PManager::FileGetPath));
- ON_CALL(*this, FileGetSize(testing::_))
- .WillByDefault(testing::Invoke(&fake_, &FakeP2PManager::FileGetSize));
- ON_CALL(*this, FileGetExpectedSize(testing::_))
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::FileGetExpectedSize));
- ON_CALL(*this, FileGetVisible(testing::_, testing::_))
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::FileGetVisible));
- ON_CALL(*this, FileMakeVisible(testing::_))
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::FileMakeVisible));
- ON_CALL(*this, CountSharedFiles())
- .WillByDefault(
- testing::Invoke(&fake_, &FakeP2PManager::CountSharedFiles));
- }
-
- ~MockP2PManager() override {}
-
- // P2PManager overrides.
- MOCK_METHOD1(SetDevicePolicy, void(const policy::DevicePolicy*));
- MOCK_METHOD0(IsP2PEnabled, bool());
- MOCK_METHOD0(EnsureP2PRunning, bool());
- MOCK_METHOD0(EnsureP2PNotRunning, bool());
- MOCK_METHOD0(PerformHousekeeping, bool());
- MOCK_METHOD4(
- LookupUrlForFile,
- void(const std::string&, size_t, base::TimeDelta, LookupCallback));
- MOCK_METHOD2(FileShare, bool(const std::string&, size_t));
- MOCK_METHOD1(FileGetPath, base::FilePath(const std::string&));
- MOCK_METHOD1(FileGetSize, ssize_t(const std::string&));
- MOCK_METHOD1(FileGetExpectedSize, ssize_t(const std::string&));
- MOCK_METHOD2(FileGetVisible, bool(const std::string&, bool*));
- MOCK_METHOD1(FileMakeVisible, bool(const std::string&));
- MOCK_METHOD0(CountSharedFiles, int());
-
- // Returns a reference to the underlying FakeP2PManager.
- FakeP2PManager& fake() { return fake_; }
-
- private:
- // The underlying FakeP2PManager.
- FakeP2PManager fake_;
-
- DISALLOW_COPY_AND_ASSIGN(MockP2PManager);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_MOCK_P2P_MANAGER_H_
diff --git a/cros/mock_payload_state.h b/cros/mock_payload_state.h
deleted file mode 100644
index 211b96d6..00000000
--- a/cros/mock_payload_state.h
+++ /dev/null
@@ -1,83 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_MOCK_PAYLOAD_STATE_H_
-#define UPDATE_ENGINE_CROS_MOCK_PAYLOAD_STATE_H_
-
-#include <string>
-
-#include <gmock/gmock.h>
-
-#include "update_engine/cros/payload_state_interface.h"
-
-namespace chromeos_update_engine {
-
-class MockPayloadState : public PayloadStateInterface {
- public:
- bool Initialize() { return true; }
-
- // Significant methods.
- MOCK_METHOD1(SetResponse, void(const OmahaResponse& response));
- MOCK_METHOD0(DownloadComplete, void());
- MOCK_METHOD1(DownloadProgress, void(size_t count));
- MOCK_METHOD0(UpdateResumed, void());
- MOCK_METHOD0(UpdateRestarted, void());
- MOCK_METHOD0(UpdateSucceeded, void());
- MOCK_METHOD1(UpdateFailed, void(ErrorCode error));
- MOCK_METHOD0(ResetUpdateStatus, void());
- MOCK_METHOD0(ShouldBackoffDownload, bool());
- MOCK_METHOD0(UpdateEngineStarted, void());
- MOCK_METHOD0(Rollback, void());
- MOCK_METHOD1(ExpectRebootInNewVersion,
- void(const std::string& target_version_uid));
- MOCK_METHOD0(P2PNewAttempt, void());
- MOCK_METHOD0(P2PAttemptAllowed, bool());
- MOCK_METHOD1(SetUsingP2PForDownloading, void(bool value));
- MOCK_METHOD1(SetUsingP2PForSharing, void(bool value));
- MOCK_METHOD1(SetScatteringWaitPeriod, void(base::TimeDelta));
- MOCK_METHOD1(SetP2PUrl, void(const std::string&));
- MOCK_METHOD0(NextPayload, bool());
- MOCK_METHOD1(SetStagingWaitPeriod, void(base::TimeDelta));
-
- // Getters.
- MOCK_METHOD0(GetResponseSignature, std::string());
- MOCK_METHOD0(GetPayloadAttemptNumber, int());
- MOCK_METHOD0(GetFullPayloadAttemptNumber, int());
- MOCK_METHOD0(GetCurrentUrl, std::string());
- MOCK_METHOD0(GetUrlFailureCount, uint32_t());
- MOCK_METHOD0(GetUrlSwitchCount, uint32_t());
- MOCK_METHOD0(GetNumResponsesSeen, int());
- MOCK_METHOD0(GetBackoffExpiryTime, base::Time());
- MOCK_METHOD0(GetUpdateDuration, base::TimeDelta());
- MOCK_METHOD0(GetUpdateDurationUptime, base::TimeDelta());
- MOCK_METHOD1(GetCurrentBytesDownloaded, uint64_t(DownloadSource source));
- MOCK_METHOD1(GetTotalBytesDownloaded, uint64_t(DownloadSource source));
- MOCK_METHOD0(GetNumReboots, uint32_t());
- MOCK_METHOD0(GetRollbackHappened, bool());
- MOCK_METHOD1(SetRollbackHappened, void(bool));
- MOCK_METHOD0(GetRollbackVersion, std::string());
- MOCK_METHOD0(GetP2PNumAttempts, int());
- MOCK_METHOD0(GetP2PFirstAttemptTimestamp, base::Time());
- MOCK_CONST_METHOD0(GetUsingP2PForDownloading, bool());
- MOCK_CONST_METHOD0(GetUsingP2PForSharing, bool());
- MOCK_METHOD0(GetScatteringWaitPeriod, base::TimeDelta());
- MOCK_CONST_METHOD0(GetP2PUrl, std::string());
- MOCK_METHOD0(GetStagingWaitPeriod, base::TimeDelta());
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_MOCK_PAYLOAD_STATE_H_
diff --git a/cros/mock_power_manager.h b/cros/mock_power_manager.h
deleted file mode 100644
index d4a86820..00000000
--- a/cros/mock_power_manager.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// Copyright (C) 2016 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_CROS_MOCK_POWER_MANAGER_H_
-#define UPDATE_ENGINE_CROS_MOCK_POWER_MANAGER_H_
-
-#include <gmock/gmock.h>
-
-#include "update_engine/cros/power_manager_interface.h"
-
-namespace chromeos_update_engine {
-
-class MockPowerManager : public PowerManagerInterface {
- public:
- MockPowerManager() = default;
-
- MOCK_METHOD0(RequestReboot, bool(void));
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_MOCK_POWER_MANAGER_H_
diff --git a/cros/mock_update_attempter.h b/cros/mock_update_attempter.h
deleted file mode 100644
index be8cfccc..00000000
--- a/cros/mock_update_attempter.h
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Copyright (C) 2010 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_CROS_MOCK_UPDATE_ATTEMPTER_H_
-#define UPDATE_ENGINE_CROS_MOCK_UPDATE_ATTEMPTER_H_
-
-#include <string>
-#include <vector>
-
-#include "update_engine/cros/update_attempter.h"
-
-#include <gmock/gmock.h>
-
-namespace chromeos_update_engine {
-
-class MockUpdateAttempter : public UpdateAttempter {
- public:
- using UpdateAttempter::UpdateAttempter;
-
- MOCK_METHOD(void,
- Update,
- (const chromeos_update_manager::UpdateCheckParams& params),
- (override));
-
- MOCK_METHOD1(GetStatus, bool(update_engine::UpdateEngineStatus* out_status));
-
- MOCK_METHOD1(GetBootTimeAtUpdate, bool(base::Time* out_boot_time));
-
- MOCK_METHOD0(ResetStatus, bool(void));
-
- MOCK_CONST_METHOD0(GetCurrentUpdateAttemptFlags, UpdateAttemptFlags(void));
-
- MOCK_METHOD3(CheckForUpdate,
- bool(const std::string& app_version,
- const std::string& omaha_url,
- UpdateAttemptFlags flags));
-
- MOCK_METHOD2(CheckForInstall,
- bool(const std::vector<std::string>& dlc_ids,
- const std::string& omaha_url));
-
- MOCK_METHOD2(SetDlcActiveValue, bool(bool, const std::string&));
-
- MOCK_CONST_METHOD0(GetExcluder, ExcluderInterface*(void));
-
- MOCK_METHOD0(RefreshDevicePolicy, void(void));
-
- MOCK_CONST_METHOD0(consecutive_failed_update_checks, unsigned int(void));
-
- MOCK_CONST_METHOD0(server_dictated_poll_interval, unsigned int(void));
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_MOCK_UPDATE_ATTEMPTER_H_
diff --git a/cros/omaha_request_action.cc b/cros/omaha_request_action.cc
deleted file mode 100644
index 1e5c15ff..00000000
--- a/cros/omaha_request_action.cc
+++ /dev/null
@@ -1,1783 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/omaha_request_action.h"
-
-#include <inttypes.h>
-
-#include <limits>
-#include <map>
-#include <sstream>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/optional.h>
-#include <base/rand_util.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_split.h>
-#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>
-#include <policy/libpolicy.h>
-
-#include "update_engine/common/action_pipe.h"
-#include "update_engine/common/constants.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/hash_calculator.h"
-#include "update_engine/common/metrics_reporter_interface.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/prefs_interface.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/connection_manager_interface.h"
-#include "update_engine/cros/omaha_request_builder_xml.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/p2p_manager.h"
-#include "update_engine/cros/payload_state_interface.h"
-#include "update_engine/cros/update_attempter.h"
-#include "update_engine/metrics_utils.h"
-
-using base::Optional;
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_manager::kRollforwardInfinity;
-using std::map;
-using std::string;
-using std::vector;
-
-namespace chromeos_update_engine {
-
-// List of custom attributes that we interpret in the Omaha response:
-constexpr char kAttrDeadline[] = "deadline";
-constexpr char kAttrDisableP2PForDownloading[] = "DisableP2PForDownloading";
-constexpr char kAttrDisableP2PForSharing[] = "DisableP2PForSharing";
-constexpr char kAttrDisablePayloadBackoff[] = "DisablePayloadBackoff";
-constexpr char kAttrVersion[] = "version";
-// Deprecated: "IsDelta"
-constexpr char kAttrIsDeltaPayload[] = "IsDeltaPayload";
-constexpr char kAttrMaxFailureCountPerUrl[] = "MaxFailureCountPerUrl";
-constexpr char kAttrMaxDaysToScatter[] = "MaxDaysToScatter";
-// Deprecated: "ManifestSignatureRsa"
-// Deprecated: "ManifestSize"
-constexpr char kAttrMetadataSignatureRsa[] = "MetadataSignatureRsa";
-constexpr char kAttrMetadataSize[] = "MetadataSize";
-constexpr char kAttrMoreInfo[] = "MoreInfo";
-constexpr char kAttrNoUpdate[] = "noupdate";
-// Deprecated: "NeedsAdmin"
-constexpr char kAttrPollInterval[] = "PollInterval";
-constexpr char kAttrPowerwash[] = "Powerwash";
-constexpr char kAttrPrompt[] = "Prompt";
-constexpr char kAttrPublicKeyRsa[] = "PublicKeyRsa";
-
-// List of attributes that we interpret in the Omaha response:
-constexpr char kAttrAppId[] = "appid";
-constexpr char kAttrCodeBase[] = "codebase";
-constexpr char kAttrCohort[] = "cohort";
-constexpr char kAttrCohortHint[] = "cohorthint";
-constexpr char kAttrCohortName[] = "cohortname";
-constexpr char kAttrElapsedDays[] = "elapsed_days";
-constexpr char kAttrElapsedSeconds[] = "elapsed_seconds";
-constexpr char kAttrEvent[] = "event";
-constexpr char kAttrFp[] = "fp";
-constexpr char kAttrHashSha256[] = "hash_sha256";
-// Deprecated: "hash"; Although we still need to pass it from the server for
-// backward compatibility.
-constexpr char kAttrName[] = "name";
-// Deprecated: "sha256"; Although we still need to pass it from the server for
-// backward compatibility.
-constexpr char kAttrSize[] = "size";
-constexpr char kAttrStatus[] = "status";
-
-// List of values that we interpret in the Omaha response:
-constexpr char kValPostInstall[] = "postinstall";
-constexpr char kValNoUpdate[] = "noupdate";
-
-// updatecheck attributes.
-// Deprecated: "eol"
-constexpr char kAttrEolDate[] = "_eol_date";
-constexpr char kAttrRollback[] = "_rollback";
-constexpr char kAttrFirmwareVersion[] = "_firmware_version";
-constexpr char kAttrKernelVersion[] = "_kernel_version";
-
-// Struct used for holding data obtained when parsing the XML.
-struct OmahaParserData {
- OmahaParserData(XML_Parser _xml_parser, int _rollback_allowed_milestones)
- : xml_parser(_xml_parser),
- rollback_allowed_milestones(_rollback_allowed_milestones) {}
-
- // Pointer to the expat XML_Parser object.
- XML_Parser xml_parser;
-
- // Some values that we need during parsing.
- int rollback_allowed_milestones;
-
- // This is the state of the parser as it's processing the XML.
- bool failed = false;
- bool entity_decl = false;
- string current_path;
-
- // These are the values extracted from the XML.
- struct DayStart {
- string elapsed_days;
- string elapsed_seconds;
- } daystart;
-
- struct App {
- string id;
- Optional<string> cohort;
- Optional<string> cohorthint;
- Optional<string> cohortname;
-
- struct Url {
- string codebase;
- };
- vector<Url> urls;
-
- struct Manifest {
- string version;
- } manifest;
-
- struct UpdateCheck {
- string status;
- string poll_interval;
- string eol_date;
- string rollback;
- string firmware_version;
- string kernel_version;
- string past_firmware_version;
- string past_kernel_version;
- } updatecheck;
-
- struct PostInstallAction {
- vector<string> is_delta_payloads;
- vector<string> metadata_signature_rsas;
- vector<string> metadata_sizes;
- string max_days_to_scatter;
- string no_update;
- string more_info_url;
- string prompt;
- string deadline;
- string disable_p2p_for_downloading;
- string disable_p2p_for_sharing;
- string public_key_rsa;
- string max_failure_count_per_url;
- string disable_payload_backoff;
- string powerwash_required;
- };
- Optional<PostInstallAction> postinstall_action;
-
- struct Package {
- string name;
- string size;
- string hash;
- string fp;
- };
- vector<Package> packages;
- };
- vector<App> apps;
-};
-
-namespace {
-
-// Callback function invoked by expat.
-void ParserHandlerStart(void* user_data,
- const XML_Char* element,
- const XML_Char** attr) {
- OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
-
- if (data->failed)
- return;
-
- data->current_path += string("/") + element;
-
- map<string, string> attrs;
- if (attr != nullptr) {
- for (int n = 0; attr[n] != nullptr && attr[n + 1] != nullptr; n += 2) {
- string key = attr[n];
- string value = attr[n + 1];
- attrs[key] = value;
- }
- }
-
- if (data->current_path == "/response/daystart") {
- data->daystart = {
- .elapsed_days = attrs[kAttrElapsedDays],
- .elapsed_seconds = attrs[kAttrElapsedSeconds],
- };
- } else if (data->current_path == "/response/app") {
- data->apps.push_back({.id = attrs[kAttrAppId]});
- if (attrs.find(kAttrCohort) != attrs.end())
- data->apps.back().cohort = attrs[kAttrCohort];
- if (attrs.find(kAttrCohortHint) != attrs.end())
- data->apps.back().cohorthint = attrs[kAttrCohortHint];
- if (attrs.find(kAttrCohortName) != attrs.end())
- data->apps.back().cohortname = attrs[kAttrCohortName];
- } else if (data->current_path == "/response/app/updatecheck") {
- data->apps.back().updatecheck = {
- .status = attrs[kAttrStatus],
- .poll_interval = attrs[kAttrPollInterval],
- .eol_date = attrs[kAttrEolDate],
- .rollback = attrs[kAttrRollback],
- .firmware_version = attrs[kAttrFirmwareVersion],
- .kernel_version = attrs[kAttrKernelVersion],
- .past_firmware_version = attrs[base::StringPrintf(
- "%s_%i", kAttrFirmwareVersion, data->rollback_allowed_milestones)],
- .past_kernel_version = attrs[base::StringPrintf(
- "%s_%i", kAttrKernelVersion, data->rollback_allowed_milestones)],
- };
- } else if (data->current_path == "/response/app/updatecheck/urls/url") {
- data->apps.back().urls.push_back({.codebase = attrs[kAttrCodeBase]});
- } else if (data->current_path ==
- "/response/app/updatecheck/manifest/packages/package") {
- data->apps.back().packages.push_back({
- .name = attrs[kAttrName],
- .size = attrs[kAttrSize],
- .hash = attrs[kAttrHashSha256],
- .fp = attrs[kAttrFp],
- });
- } else if (data->current_path == "/response/app/updatecheck/manifest") {
- data->apps.back().manifest.version = attrs[kAttrVersion];
- } else if (data->current_path ==
- "/response/app/updatecheck/manifest/actions/action") {
- // We only care about the postinstall action.
- if (attrs[kAttrEvent] == kValPostInstall) {
- OmahaParserData::App::PostInstallAction action = {
- .is_delta_payloads = base::SplitString(attrs[kAttrIsDeltaPayload],
- ":",
- base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL),
- .metadata_signature_rsas =
- base::SplitString(attrs[kAttrMetadataSignatureRsa],
- ":",
- base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL),
- .metadata_sizes = base::SplitString(attrs[kAttrMetadataSize],
- ":",
- base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL),
- .max_days_to_scatter = attrs[kAttrMaxDaysToScatter],
- .no_update = attrs[kAttrNoUpdate],
- .more_info_url = attrs[kAttrMoreInfo],
- .prompt = attrs[kAttrPrompt],
- .deadline = attrs[kAttrDeadline],
- .disable_p2p_for_downloading = attrs[kAttrDisableP2PForDownloading],
- .disable_p2p_for_sharing = attrs[kAttrDisableP2PForSharing],
- .public_key_rsa = attrs[kAttrPublicKeyRsa],
- .max_failure_count_per_url = attrs[kAttrMaxFailureCountPerUrl],
- .disable_payload_backoff = attrs[kAttrDisablePayloadBackoff],
- .powerwash_required = attrs[kAttrPowerwash],
- };
- data->apps.back().postinstall_action = std::move(action);
- }
- }
-}
-
-// Callback function invoked by expat.
-void ParserHandlerEnd(void* user_data, const XML_Char* element) {
- OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
- if (data->failed)
- return;
-
- const string path_suffix = string("/") + element;
-
- if (!base::EndsWith(
- data->current_path, path_suffix, base::CompareCase::SENSITIVE)) {
- LOG(ERROR) << "Unexpected end element '" << element
- << "' with current_path='" << data->current_path << "'";
- data->failed = true;
- return;
- }
- data->current_path.resize(data->current_path.size() - path_suffix.size());
-}
-
-// Callback function invoked by expat.
-//
-// This is called for entity declarations. Since Omaha is guaranteed
-// to never return any XML with entities our course of action is to
-// just stop parsing. This avoids potential resource exhaustion
-// problems AKA the "billion laughs". CVE-2013-0340.
-void ParserHandlerEntityDecl(void* user_data,
- const XML_Char* entity_name,
- int is_parameter_entity,
- const XML_Char* value,
- int value_length,
- const XML_Char* base,
- const XML_Char* system_id,
- const XML_Char* public_id,
- const XML_Char* notation_name) {
- OmahaParserData* data = reinterpret_cast<OmahaParserData*>(user_data);
-
- LOG(ERROR) << "XML entities are not supported. Aborting parsing.";
- data->failed = true;
- data->entity_decl = true;
- XML_StopParser(data->xml_parser, false);
-}
-
-} // namespace
-
-OmahaRequestAction::OmahaRequestAction(
- OmahaEvent* event,
- std::unique_ptr<HttpFetcher> http_fetcher,
- bool ping_only,
- const string& session_id)
- : event_(event),
- http_fetcher_(std::move(http_fetcher)),
- policy_provider_(std::make_unique<policy::PolicyProvider>()),
- ping_only_(ping_only),
- ping_active_days_(0),
- ping_roll_call_days_(0),
- session_id_(session_id) {
- policy_provider_->Reload();
-}
-
-OmahaRequestAction::~OmahaRequestAction() {}
-
-// Calculates the value to use for the ping days parameter.
-int OmahaRequestAction::CalculatePingDays(const string& key) {
- int days = kPingNeverPinged;
- int64_t last_ping = 0;
- if (SystemState::Get()->prefs()->GetInt64(key, &last_ping) &&
- last_ping >= 0) {
- days = (Time::Now() - Time::FromInternalValue(last_ping)).InDays();
- if (days < 0) {
- // If |days| is negative, then the system clock must have jumped
- // back in time since the ping was sent. Mark the value so that
- // it doesn't get sent to the server but we still update the
- // last ping daystart preference. This way the next ping time
- // will be correct, hopefully.
- days = kPingTimeJump;
- LOG(WARNING)
- << "System clock jumped back in time. Resetting ping daystarts.";
- }
- }
- return days;
-}
-
-void OmahaRequestAction::InitPingDays() {
- // We send pings only along with update checks, not with events.
- if (IsEvent()) {
- return;
- }
- // TODO(petkov): Figure a way to distinguish active use pings
- // vs. roll call pings. Currently, the two pings are identical. A
- // fix needs to change this code as well as UpdateLastPingDays and ShouldPing.
- ping_active_days_ = CalculatePingDays(kPrefsLastActivePingDay);
- ping_roll_call_days_ = CalculatePingDays(kPrefsLastRollCallPingDay);
-}
-
-bool OmahaRequestAction::ShouldPing() const {
- if (ping_active_days_ == kPingNeverPinged &&
- ping_roll_call_days_ == kPingNeverPinged) {
- int powerwash_count = SystemState::Get()->hardware()->GetPowerwashCount();
- if (powerwash_count > 0) {
- LOG(INFO) << "Not sending ping with a=-1 r=-1 to omaha because "
- << "powerwash_count is " << powerwash_count;
- return false;
- }
- if (SystemState::Get()->hardware()->GetFirstActiveOmahaPingSent()) {
- LOG(INFO) << "Not sending ping with a=-1 r=-1 to omaha because "
- << "the first_active_omaha_ping_sent is true.";
- return false;
- }
- return true;
- }
- return ping_active_days_ > 0 || ping_roll_call_days_ > 0;
-}
-
-// static
-int OmahaRequestAction::GetInstallDate() {
- auto* prefs = SystemState::Get()->prefs();
- // If we have the value stored on disk, just return it.
- int64_t stored_value;
- if (prefs->GetInt64(kPrefsInstallDateDays, &stored_value)) {
- // Convert and validity-check.
- int install_date_days = static_cast<int>(stored_value);
- if (install_date_days >= 0)
- return install_date_days;
- LOG(ERROR) << "Dropping stored Omaha InstallData since its value num_days="
- << install_date_days << " looks suspicious.";
- prefs->Delete(kPrefsInstallDateDays);
- }
-
- // Otherwise, if OOBE is not complete then do nothing and wait for
- // ParseResponse() to call ParseInstallDate() and then
- // PersistInstallDate() to set the kPrefsInstallDateDays state
- // variable. Once that is done, we'll then report back in future
- // Omaha requests. This works exactly because OOBE triggers an
- // update check.
- //
- // However, if OOBE is complete and the kPrefsInstallDateDays state
- // variable is not set, there are two possibilities
- //
- // 1. The update check in OOBE failed so we never got a response
- // from Omaha (no network etc.); or
- //
- // 2. OOBE was done on an older version that didn't write to the
- // kPrefsInstallDateDays state variable.
- //
- // In both cases, we approximate the install date by simply
- // inspecting the timestamp of when OOBE happened.
-
- Time time_of_oobe;
- if (!SystemState::Get()->hardware()->IsOOBEEnabled() ||
- !SystemState::Get()->hardware()->IsOOBEComplete(&time_of_oobe)) {
- LOG(INFO) << "Not generating Omaha InstallData as we have "
- << "no prefs file and OOBE is not complete or not enabled.";
- return -1;
- }
-
- int num_days;
- if (!utils::ConvertToOmahaInstallDate(time_of_oobe, &num_days)) {
- LOG(ERROR) << "Not generating Omaha InstallData from time of OOBE "
- << "as its value '" << utils::ToString(time_of_oobe)
- << "' looks suspicious.";
- return -1;
- }
-
- // Persist this to disk, for future use.
- if (!OmahaRequestAction::PersistInstallDate(num_days,
- kProvisionedFromOOBEMarker))
- return -1;
-
- LOG(INFO) << "Set the Omaha InstallDate from OOBE time-stamp to " << num_days
- << " days.";
-
- return num_days;
-}
-
-void OmahaRequestAction::StorePingReply(
- const OmahaParserData& parser_data) const {
- const auto* params = SystemState::Get()->request_params();
- for (const auto& app : parser_data.apps) {
- auto it = params->dlc_apps_params().find(app.id);
- if (it == params->dlc_apps_params().end())
- continue;
-
- const OmahaRequestParams::AppParams& dlc_params = it->second;
- const string& dlc_id = dlc_params.name;
- // Skip if the ping for this DLC was not sent.
- if (!dlc_params.send_ping)
- continue;
-
- auto* prefs = SystemState::Get()->prefs();
- // Reset the active metadata value to |kPingInactiveValue|.
- auto active_key =
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
- if (!prefs->SetInt64(active_key, kPingInactiveValue))
- LOG(ERROR) << "Failed to set the value of ping metadata '" << active_key
- << "'.";
-
- auto last_rollcall_key =
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingLastRollcall});
- if (!prefs->SetString(last_rollcall_key, parser_data.daystart.elapsed_days))
- LOG(ERROR) << "Failed to set the value of ping metadata '"
- << last_rollcall_key << "'.";
-
- if (dlc_params.ping_active) {
- // Write the value of elapsed_days into |kPrefsPingLastActive| only if
- // the previous ping was an active one.
- auto last_active_key =
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingLastActive});
- if (!prefs->SetString(last_active_key, parser_data.daystart.elapsed_days))
- LOG(ERROR) << "Failed to set the value of ping metadata '"
- << last_active_key << "'.";
- }
- }
-}
-
-void OmahaRequestAction::PerformAction() {
- http_fetcher_->set_delegate(this);
- InitPingDays();
- if (ping_only_ && !ShouldPing()) {
- processor_->ActionComplete(this, ErrorCode::kSuccess);
- return;
- }
-
- OmahaRequestBuilderXml omaha_request(event_.get(),
- ping_only_,
- ShouldPing(), // include_ping
- ping_active_days_,
- ping_roll_call_days_,
- GetInstallDate(),
- session_id_);
- string request_post = omaha_request.GetRequest();
-
- // Set X-Goog-Update headers.
- const auto* params = SystemState::Get()->request_params();
- http_fetcher_->SetHeader(kXGoogleUpdateInteractivity,
- params->interactive() ? "fg" : "bg");
- http_fetcher_->SetHeader(kXGoogleUpdateAppId, params->GetAppId());
- http_fetcher_->SetHeader(
- kXGoogleUpdateUpdater,
- base::StringPrintf(
- "%s-%s", constants::kOmahaUpdaterID, kOmahaUpdaterVersion));
-
- http_fetcher_->SetPostData(
- request_post.data(), request_post.size(), kHttpContentTypeTextXml);
- LOG(INFO) << "Posting an Omaha request to " << params->update_url();
- LOG(INFO) << "Request: " << request_post;
- http_fetcher_->BeginTransfer(params->update_url());
-}
-
-void OmahaRequestAction::TerminateProcessing() {
- http_fetcher_->TerminateTransfer();
-}
-
-// We just store the response in the buffer. Once we've received all bytes,
-// we'll look in the buffer and decide what to do.
-bool OmahaRequestAction::ReceivedBytes(HttpFetcher* fetcher,
- const void* bytes,
- size_t length) {
- const uint8_t* byte_ptr = reinterpret_cast<const uint8_t*>(bytes);
- response_buffer_.insert(response_buffer_.end(), byte_ptr, byte_ptr + length);
- return true;
-}
-
-namespace {
-
-// Parses a 64 bit base-10 int from a string and returns it. Returns 0
-// on error. If the string contains "0", that's indistinguishable from
-// error.
-off_t ParseInt(const string& str) {
- off_t ret = 0;
- int rc = sscanf(str.c_str(), "%" PRIi64, &ret); // NOLINT(runtime/printf)
- if (rc < 1) {
- // failure
- return 0;
- }
- return ret;
-}
-
-// Parses |str| and returns |true| if, and only if, its value is "true".
-bool ParseBool(const string& str) {
- return str == "true";
-}
-
-// Update the last ping day preferences based on the server daystart
-// response. Returns true on success, false otherwise.
-bool UpdateLastPingDays(OmahaParserData* parser_data) {
- int64_t elapsed_seconds = 0;
- TEST_AND_RETURN_FALSE(base::StringToInt64(
- parser_data->daystart.elapsed_seconds, &elapsed_seconds));
- TEST_AND_RETURN_FALSE(elapsed_seconds >= 0);
-
- // Remember the local time that matches the server's last midnight
- // time.
- auto* prefs = SystemState::Get()->prefs();
- Time daystart = Time::Now() - TimeDelta::FromSeconds(elapsed_seconds);
- prefs->SetInt64(kPrefsLastActivePingDay, daystart.ToInternalValue());
- prefs->SetInt64(kPrefsLastRollCallPingDay, daystart.ToInternalValue());
- return true;
-}
-
-// Parses the package node in the given XML document and populates
-// |output_object| if valid. Returns true if we should continue the parsing.
-// False otherwise, in which case it sets any error code using |completer|.
-bool ParsePackage(OmahaParserData::App* app,
- OmahaResponse* output_object,
- bool can_exclude,
- ScopedActionCompleter* completer) {
- if (app->updatecheck.status.empty() ||
- app->updatecheck.status == kValNoUpdate) {
- if (!app->packages.empty()) {
- LOG(ERROR) << "No update in this <app> but <package> is not empty.";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
- return true;
- }
- if (app->packages.empty()) {
- LOG(ERROR) << "Omaha Response has no packages.";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
- if (app->urls.empty()) {
- LOG(ERROR) << "No Omaha Response URLs.";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
- for (size_t i = 0; i < app->packages.size(); i++) {
- const auto& package = app->packages[i];
- if (package.name.empty()) {
- LOG(ERROR) << "Omaha Response has empty package name.";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
-
- OmahaResponse::Package out_package;
- out_package.app_id = app->id;
- out_package.can_exclude = can_exclude;
- for (const auto& url : app->urls) {
- if (url.codebase.empty()) {
- LOG(ERROR) << "Omaha Response URL has empty codebase.";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
- out_package.payload_urls.push_back(url.codebase + package.name);
- }
-
- base::StringToUint64(package.size, &out_package.size);
- if (out_package.size <= 0) {
- LOG(ERROR) << "Omaha Response has invalid payload size: " << package.size;
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
-
- if (i < app->postinstall_action->metadata_sizes.size())
- base::StringToUint64(app->postinstall_action->metadata_sizes[i],
- &out_package.metadata_size);
-
- if (i < app->postinstall_action->metadata_signature_rsas.size())
- out_package.metadata_signature =
- app->postinstall_action->metadata_signature_rsas[i];
-
- out_package.hash = package.hash;
- if (out_package.hash.empty()) {
- LOG(ERROR) << "Omaha Response has empty hash_sha256 value.";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
-
- out_package.fp = package.fp;
-
- if (i < app->postinstall_action->is_delta_payloads.size())
- out_package.is_delta =
- ParseBool(app->postinstall_action->is_delta_payloads[i]);
-
- output_object->packages.push_back(std::move(out_package));
- }
-
- return true;
-}
-
-// 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();
- /* Increment logic in loop */) {
- // If package cannot be excluded, quickly continue.
- if (!package_it->can_exclude) {
- ++package_it;
- continue;
- }
- // Remove the excluded payload URLs.
- for (auto payload_url_it = package_it->payload_urls.begin();
- payload_url_it != package_it->payload_urls.end();
- /* Increment logic in loop */) {
- auto exclusion_name = utils::GetExclusionName(*payload_url_it);
- // If payload URL is not excluded, quickly continue.
- if (!excluder->IsExcluded(exclusion_name)) {
- ++payload_url_it;
- continue;
- }
- LOG(INFO) << "Excluding payload URL=" << *payload_url_it
- << " for payload hash=" << package_it->hash;
- payload_url_it = package_it->payload_urls.erase(payload_url_it);
- }
- // 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;
- }
- ++package_it;
- }
-}
-
-// Parses the 2 key version strings kernel_version and firmware_version. If the
-// field is not present, or cannot be parsed the values default to 0xffff.
-void ParseRollbackVersions(const OmahaParserData::App& platform_app,
- int allowed_milestones,
- OmahaResponse* output_object) {
- // Defaults to false if attribute is not present.
- output_object->is_rollback = ParseBool(platform_app.updatecheck.rollback);
-
- utils::ParseRollbackKeyVersion(
- platform_app.updatecheck.firmware_version,
- &output_object->rollback_key_version.firmware_key,
- &output_object->rollback_key_version.firmware);
- utils::ParseRollbackKeyVersion(
- platform_app.updatecheck.kernel_version,
- &output_object->rollback_key_version.kernel_key,
- &output_object->rollback_key_version.kernel);
-
- string firmware_version = platform_app.updatecheck.past_firmware_version;
- string kernel_version = platform_app.updatecheck.past_kernel_version;
-
- LOG(INFO) << "For milestone N-" << allowed_milestones
- << " firmware_key_version=" << firmware_version
- << " kernel_key_version=" << kernel_version;
-
- OmahaResponse::RollbackKeyVersion version;
- utils::ParseRollbackKeyVersion(
- firmware_version, &version.firmware_key, &version.firmware);
- utils::ParseRollbackKeyVersion(
- kernel_version, &version.kernel_key, &version.kernel);
-
- output_object->past_rollback_key_version = std::move(version);
-}
-
-void PersistEolInfo(const OmahaParserData::App& platform_app) {
- // If EOL date attribute is not sent, don't delete the old persisted EOL
- // date information.
- if (!platform_app.updatecheck.eol_date.empty() &&
- !SystemState::Get()->prefs()->SetString(
- kPrefsOmahaEolDate, platform_app.updatecheck.eol_date)) {
- LOG(ERROR) << "Setting EOL date failed.";
- }
-}
-
-} // namespace
-
-bool OmahaRequestAction::ParseResponse(OmahaParserData* parser_data,
- OmahaResponse* output_object,
- ScopedActionCompleter* completer) {
- if (parser_data->apps.empty()) {
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
-
- // Locate the platform App since it's an important one that has specific
- // information attached to it that may not be available from other Apps.
- const auto* params = SystemState::Get()->request_params();
- auto platform_app = std::find_if(parser_data->apps.begin(),
- parser_data->apps.end(),
- [&params](const OmahaParserData::App& app) {
- return app.id == params->GetAppId();
- });
- if (platform_app == parser_data->apps.end()) {
- LOG(WARNING) << "Platform App is missing.";
- } else {
- // chromium-os:37289: The PollInterval is not supported by Omaha server
- // currently. But still keeping this existing code in case we ever decide
- // to slow down the request rate from the server-side. Note that the
- // PollInterval is not persisted, so it has to be sent by the server on
- // every response to guarantee that the scheduler uses this value
- // (otherwise, if the device got rebooted after the last server-indicated
- // value, it'll revert to the default value). Also kDefaultMaxUpdateChecks
- // value for the scattering logic is based on the assumption that we perform
- // an update check every hour so that the max value of 8 will roughly be
- // equivalent to one work day. If we decide to use PollInterval permanently,
- // we should update the max_update_checks_allowed to take PollInterval into
- // account. Note: The parsing for PollInterval happens even before parsing
- // of the status because we may want to specify the PollInterval even when
- // there's no update.
- base::StringToInt(platform_app->updatecheck.poll_interval,
- &output_object->poll_interval);
-
- PersistEolInfo(*platform_app);
-
- // Parses the rollback versions of the current image. If the fields do not
- // exist they default to 0xffff for the 4 key versions.
- ParseRollbackVersions(
- *platform_app, params->rollback_allowed_milestones(), output_object);
- }
-
- // Check for the "elapsed_days" attribute in the "daystart"
- // element. This is the number of days since Jan 1 2007, 0:00
- // PST. If we don't have a persisted value of the Omaha InstallDate,
- // we'll use it to calculate it and then persist it.
- if (ParseInstallDate(parser_data, output_object) && !HasInstallDate()) {
- // Since output_object->install_date_days is never negative, the
- // elapsed_days -> install-date calculation is reduced to simply
- // rounding down to the nearest number divisible by 7.
- int remainder = output_object->install_date_days % 7;
- int install_date_days_rounded =
- output_object->install_date_days - remainder;
- if (PersistInstallDate(install_date_days_rounded,
- kProvisionedFromOmahaResponse)) {
- LOG(INFO) << "Set the Omaha InstallDate from Omaha Response to "
- << install_date_days_rounded << " days.";
- }
- }
-
- // We persist the cohorts sent by omaha even if the status is "noupdate".
- PersistCohorts(*parser_data);
-
- if (!ParseStatus(parser_data, output_object, completer))
- return false;
-
- if (!ParseParams(parser_data, output_object, completer))
- return false;
-
- // Package has to be parsed after Params now because ParseParams need to make
- // sure that postinstall action exists.
- for (auto& app : parser_data->apps) {
- // Only allow exclusions for a non-critical package during an update. For
- // non-critical package installations, let the errors propagate instead
- // of being handled inside update_engine as installations are a dlcservice
- // specific feature.
- bool can_exclude = !params->is_install() && params->IsDlcAppId(app.id);
- if (!ParsePackage(&app, output_object, can_exclude, completer))
- return false;
- }
-
- return true;
-}
-
-bool OmahaRequestAction::ParseStatus(OmahaParserData* parser_data,
- OmahaResponse* output_object,
- ScopedActionCompleter* completer) {
- output_object->update_exists = false;
- auto* params = SystemState::Get()->request_params();
- for (const auto& app : parser_data->apps) {
- const string& status = app.updatecheck.status;
- if (status == kValNoUpdate) {
- // If the app is a DLC, allow status "noupdate" to support DLC
- // deprecations.
- if (params->IsDlcAppId(app.id)) {
- LOG(INFO) << "No update for App " << app.id
- << " but update continuing since a DLC.";
- params->SetDlcNoUpdate(app.id);
- continue;
- }
- // Don't update if any app has status="noupdate".
- LOG(INFO) << "No update for App " << app.id;
- output_object->update_exists = false;
- break;
- } else if (status == "ok") {
- if (ParseBool(app.postinstall_action->no_update)) {
- // noupdate="true" in postinstall attributes means it's an update to
- // self, only update if there's at least one app really have update.
- LOG(INFO) << "Update to self for App " << app.id;
- } else {
- output_object->update_exists = true;
- }
- } else if (status.empty() && params->is_install() &&
- params->GetAppId() == app.id) {
- // Skips the platform app for install operation.
- LOG(INFO) << "No payload (and ignore) for App " << app.id;
- } else {
- LOG(ERROR) << "Unknown Omaha response status: " << status;
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
- }
- if (!output_object->update_exists) {
- SetOutputObject(*output_object);
- completer->set_code(ErrorCode::kSuccess);
- }
-
- return output_object->update_exists;
-}
-
-bool OmahaRequestAction::ParseParams(OmahaParserData* parser_data,
- OmahaResponse* output_object,
- ScopedActionCompleter* completer) {
- const auto* params = SystemState::Get()->request_params();
- const OmahaParserData::App* main_app = nullptr;
- for (const auto& app : parser_data->apps) {
- if (app.id == params->GetAppId() && app.postinstall_action) {
- main_app = &app;
- } else if (params->is_install()) {
- if (app.manifest.version != params->app_version()) {
- LOG(WARNING) << "An app has a version: " << app.manifest.version
- << " that is different than platform app version: "
- << params->app_version();
- }
- }
- if (app.postinstall_action && main_app == nullptr) {
- main_app = &app;
- }
- }
-
- if (main_app == nullptr) {
- LOG(ERROR) << "Omaha Response has no postinstall event action.";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
-
- const OmahaParserData::App& app = *main_app;
- // Get the optional properties one by one.
- output_object->version = app.manifest.version;
- output_object->more_info_url = app.postinstall_action->more_info_url;
- output_object->prompt = ParseBool(app.postinstall_action->prompt);
- output_object->deadline = app.postinstall_action->deadline;
- output_object->max_days_to_scatter =
- ParseInt(app.postinstall_action->max_days_to_scatter);
- output_object->disable_p2p_for_downloading =
- ParseBool(app.postinstall_action->disable_p2p_for_downloading);
- output_object->disable_p2p_for_sharing =
- ParseBool(app.postinstall_action->disable_p2p_for_sharing);
- output_object->public_key_rsa = app.postinstall_action->public_key_rsa;
-
- if (!base::StringToUint(app.postinstall_action->max_failure_count_per_url,
- &output_object->max_failure_count_per_url))
- output_object->max_failure_count_per_url = kDefaultMaxFailureCountPerUrl;
-
- output_object->disable_payload_backoff =
- ParseBool(app.postinstall_action->disable_payload_backoff);
- output_object->powerwash_required =
- ParseBool(app.postinstall_action->powerwash_required);
-
- if (output_object->version.empty()) {
- LOG(ERROR) << "Omaha Response does not have version in manifest!";
- completer->set_code(ErrorCode::kOmahaResponseInvalid);
- return false;
- }
-
- return true;
-}
-
-// If the transfer was successful, this uses expat to parse the response
-// and fill in the appropriate fields of the output object. Also, notifies
-// the processor that we're done.
-void OmahaRequestAction::TransferComplete(HttpFetcher* fetcher,
- bool successful) {
- ScopedActionCompleter completer(processor_, this);
- string current_response(response_buffer_.begin(), response_buffer_.end());
- LOG(INFO) << "Omaha request response: " << current_response;
-
- PayloadStateInterface* const payload_state =
- SystemState::Get()->payload_state();
-
- // Set the max kernel key version based on whether rollback is allowed.
- SetMaxKernelKeyVersionForRollback();
-
- // Events are best effort transactions -- assume they always succeed.
- if (IsEvent()) {
- CHECK(!HasOutputPipe()) << "No output pipe allowed for event requests.";
- completer.set_code(ErrorCode::kSuccess);
- return;
- }
-
- ErrorCode aux_error_code = fetcher->GetAuxiliaryErrorCode();
- if (aux_error_code != ErrorCode::kSuccess) {
- metrics::DownloadErrorCode download_error_code =
- metrics_utils::GetDownloadErrorCode(aux_error_code);
- SystemState::Get()->metrics_reporter()->ReportUpdateCheckMetrics(
- metrics::CheckResult::kUnset,
- metrics::CheckReaction::kUnset,
- download_error_code);
- }
-
- if (!successful) {
- int code = GetHTTPResponseCode();
- LOG(ERROR) << "Omaha request network transfer failed with HTTPResponseCode="
- << code;
- // Makes sure we send proper error values.
- if (code < 0 || code >= 1000) {
- code = 999;
- LOG(WARNING) << "Converting to proper HTTPResponseCode=" << code;
- }
- completer.set_code(static_cast<ErrorCode>(
- static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + code));
- return;
- }
-
- XML_Parser parser = XML_ParserCreate(nullptr);
- OmahaParserData parser_data(
- parser,
- SystemState::Get()->request_params()->rollback_allowed_milestones());
- XML_SetUserData(parser, &parser_data);
- XML_SetElementHandler(parser, ParserHandlerStart, ParserHandlerEnd);
- XML_SetEntityDeclHandler(parser, ParserHandlerEntityDecl);
- XML_Status res =
- XML_Parse(parser,
- reinterpret_cast<const char*>(response_buffer_.data()),
- response_buffer_.size(),
- XML_TRUE);
-
- if (res != XML_STATUS_OK || parser_data.failed) {
- LOG(ERROR) << "Omaha response not valid XML: "
- << XML_ErrorString(XML_GetErrorCode(parser)) << " at line "
- << XML_GetCurrentLineNumber(parser) << " col "
- << XML_GetCurrentColumnNumber(parser);
- XML_ParserFree(parser);
- ErrorCode error_code = ErrorCode::kOmahaRequestXMLParseError;
- if (response_buffer_.empty()) {
- error_code = ErrorCode::kOmahaRequestEmptyResponseError;
- } else if (parser_data.entity_decl) {
- error_code = ErrorCode::kOmahaRequestXMLHasEntityDecl;
- }
- completer.set_code(error_code);
- return;
- }
- XML_ParserFree(parser);
-
- // Update the last ping day preferences based on the server daystart response
- // even if we didn't send a ping. Omaha always includes the daystart in the
- // response, but log the error if it didn't.
- LOG_IF(ERROR, !UpdateLastPingDays(&parser_data))
- << "Failed to update the last ping day preferences!";
-
- // Sets first_active_omaha_ping_sent to true (vpd in CrOS). We only do this if
- // we have got a response from omaha and if its value has never been set to
- // true before. Failure of this function should be ignored. There should be no
- // need to check if a=-1 has been sent because older devices have already sent
- // their a=-1 in the past and we have to set first_active_omaha_ping_sent for
- // future checks.
- if (!SystemState::Get()->hardware()->GetFirstActiveOmahaPingSent()) {
- if (!SystemState::Get()->hardware()->SetFirstActiveOmahaPingSent()) {
- SystemState::Get()->metrics_reporter()->ReportInternalErrorCode(
- ErrorCode::kFirstActiveOmahaPingSentPersistenceError);
- }
- }
-
- // Create/update the metadata files for each DLC app received.
- StorePingReply(parser_data);
-
- if (!HasOutputPipe()) {
- // Just set success to whether or not the http transfer succeeded,
- // which must be true at this point in the code.
- completer.set_code(ErrorCode::kSuccess);
- return;
- }
-
- OmahaResponse output_object;
- if (!ParseResponse(&parser_data, &output_object, &completer))
- return;
- ProcessExclusions(&output_object,
- SystemState::Get()->request_params(),
- SystemState::Get()->update_attempter()->GetExcluder());
- output_object.update_exists = true;
- SetOutputObject(output_object);
-
- LoadOrPersistUpdateFirstSeenAtPref();
-
- ErrorCode error = ErrorCode::kSuccess;
- if (ShouldIgnoreUpdate(output_object, &error)) {
- // No need to change output_object.update_exists here, since the value
- // has been output to the pipe.
- completer.set_code(error);
- return;
- }
-
- // If Omaha says to disable p2p, respect that
- if (output_object.disable_p2p_for_downloading) {
- LOG(INFO) << "Forcibly disabling use of p2p for downloading as "
- << "requested by Omaha.";
- payload_state->SetUsingP2PForDownloading(false);
- }
- if (output_object.disable_p2p_for_sharing) {
- LOG(INFO) << "Forcibly disabling use of p2p for sharing as "
- << "requested by Omaha.";
- payload_state->SetUsingP2PForSharing(false);
- }
-
- // Update the payload state with the current response. The payload state
- // will automatically reset all stale state if this response is different
- // from what's stored already. We are updating the payload state as late
- // as possible in this method so that if a new release gets pushed and then
- // got pulled back due to some issues, we don't want to clear our internal
- // state unnecessarily.
- payload_state->SetResponse(output_object);
-
- // It could be we've already exceeded the deadline for when p2p is
- // allowed or that we've tried too many times with p2p. Check that.
- if (payload_state->GetUsingP2PForDownloading()) {
- payload_state->P2PNewAttempt();
- if (!payload_state->P2PAttemptAllowed()) {
- LOG(INFO) << "Forcibly disabling use of p2p for downloading because "
- << "of previous failures when using p2p.";
- payload_state->SetUsingP2PForDownloading(false);
- }
- }
-
- // From here on, we'll complete stuff in CompleteProcessing() so
- // disable |completer| since we'll create a new one in that
- // function.
- completer.set_should_complete(false);
-
- // If we're allowed to use p2p for downloading we do not pay
- // attention to wall-clock-based waiting if the URL is indeed
- // available via p2p. Therefore, check if the file is available via
- // p2p before deferring...
- if (payload_state->GetUsingP2PForDownloading()) {
- LookupPayloadViaP2P(output_object);
- } else {
- CompleteProcessing();
- }
-}
-
-void OmahaRequestAction::CompleteProcessing() {
- ScopedActionCompleter completer(processor_, this);
- OmahaResponse& output_object = const_cast<OmahaResponse&>(GetOutputObject());
- PayloadStateInterface* payload_state = SystemState::Get()->payload_state();
-
- if (ShouldDeferDownload(&output_object)) {
- output_object.update_exists = false;
- LOG(INFO) << "Ignoring Omaha updates as updates are deferred by policy.";
- completer.set_code(ErrorCode::kOmahaUpdateDeferredPerPolicy);
- return;
- }
-
- if (payload_state->ShouldBackoffDownload()) {
- output_object.update_exists = false;
- LOG(INFO) << "Ignoring Omaha updates in order to backoff our retry "
- << "attempts.";
- completer.set_code(ErrorCode::kOmahaUpdateDeferredForBackoff);
- return;
- }
- completer.set_code(ErrorCode::kSuccess);
-}
-
-void OmahaRequestAction::OnLookupPayloadViaP2PCompleted(const string& url) {
- LOG(INFO) << "Lookup complete, p2p-client returned URL '" << url << "'";
- if (!url.empty()) {
- SystemState::Get()->payload_state()->SetP2PUrl(url);
- } else {
- LOG(INFO) << "Forcibly disabling use of p2p for downloading "
- << "because no suitable peer could be found.";
- SystemState::Get()->payload_state()->SetUsingP2PForDownloading(false);
- }
- CompleteProcessing();
-}
-
-void OmahaRequestAction::LookupPayloadViaP2P(const OmahaResponse& response) {
- // If the device is in the middle of an update, the state variables
- // kPrefsUpdateStateNextDataOffset, kPrefsUpdateStateNextDataLength
- // tracks the offset and length of the operation currently in
- // progress. The offset is based from the end of the manifest which
- // is kPrefsManifestMetadataSize bytes long.
- //
- // To make forward progress and avoid deadlocks, we need to find a
- // peer that has at least the entire operation we're currently
- // working on. Otherwise we may end up in a situation where two
- // devices bounce back and forth downloading from each other,
- // neither making any forward progress until one of them decides to
- // stop using p2p (via kMaxP2PAttempts and kMaxP2PAttemptTimeSeconds
- // safe-guards). See http://crbug.com/297170 for an example)
- size_t minimum_size = 0;
- int64_t manifest_metadata_size = 0;
- int64_t manifest_signature_size = 0;
- int64_t next_data_offset = 0;
- int64_t next_data_length = 0;
- if (SystemState::Get()->prefs()->GetInt64(kPrefsManifestMetadataSize,
- &manifest_metadata_size) &&
- manifest_metadata_size != -1 &&
- SystemState::Get()->prefs()->GetInt64(kPrefsManifestSignatureSize,
- &manifest_signature_size) &&
- manifest_signature_size != -1 &&
- SystemState::Get()->prefs()->GetInt64(kPrefsUpdateStateNextDataOffset,
- &next_data_offset) &&
- next_data_offset != -1 &&
- SystemState::Get()->prefs()->GetInt64(kPrefsUpdateStateNextDataLength,
- &next_data_length)) {
- minimum_size = manifest_metadata_size + manifest_signature_size +
- next_data_offset + next_data_length;
- }
-
- // TODO(senj): Fix P2P for multiple package.
- brillo::Blob raw_hash;
- if (!base::HexStringToBytes(response.packages[0].hash, &raw_hash))
- return;
- string file_id =
- utils::CalculateP2PFileId(raw_hash, response.packages[0].size);
- if (SystemState::Get()->p2p_manager()) {
- LOG(INFO) << "Checking if payload is available via p2p, file_id=" << file_id
- << " minimum_size=" << minimum_size;
- SystemState::Get()->p2p_manager()->LookupUrlForFile(
- file_id,
- minimum_size,
- TimeDelta::FromSeconds(kMaxP2PNetworkWaitTimeSeconds),
- base::Bind(&OmahaRequestAction::OnLookupPayloadViaP2PCompleted,
- base::Unretained(this)));
- }
-}
-
-bool OmahaRequestAction::ShouldDeferDownload(OmahaResponse* output_object) {
- const auto* params = SystemState::Get()->request_params();
- if (params->interactive()) {
- LOG(INFO) << "Not deferring download because update is interactive.";
- return false;
- }
-
- // If we're using p2p to download _and_ we have a p2p URL, we never
- // defer the download. This is because the download will always
- // happen from a peer on the LAN and we've been waiting in line for
- // our turn.
- const PayloadStateInterface* payload_state =
- SystemState::Get()->payload_state();
- if (payload_state->GetUsingP2PForDownloading() &&
- !payload_state->GetP2PUrl().empty()) {
- LOG(INFO) << "Download not deferred because download "
- << "will happen from a local peer (via p2p).";
- return false;
- }
-
- // We should defer the downloads only if we've first satisfied the
- // wall-clock-based-waiting period and then the update-check-based waiting
- // period, if required.
- if (!params->wall_clock_based_wait_enabled()) {
- LOG(INFO) << "Wall-clock-based waiting period is not enabled,"
- << " so no deferring needed.";
- return false;
- }
-
- switch (IsWallClockBasedWaitingSatisfied(output_object)) {
- case kWallClockWaitNotSatisfied:
- // We haven't even satisfied the first condition, passing the
- // wall-clock-based waiting period, so we should defer the downloads
- // until that happens.
- LOG(INFO) << "wall-clock-based-wait not satisfied.";
- return true;
-
- case kWallClockWaitDoneButUpdateCheckWaitRequired:
- LOG(INFO) << "wall-clock-based-wait satisfied and "
- << "update-check-based-wait required.";
- return !IsUpdateCheckCountBasedWaitingSatisfied();
-
- case kWallClockWaitDoneAndUpdateCheckWaitNotRequired:
- // Wall-clock-based waiting period is satisfied, and it's determined
- // that we do not need the update-check-based wait. so no need to
- // defer downloads.
- LOG(INFO) << "wall-clock-based-wait satisfied and "
- << "update-check-based-wait is not required.";
- return false;
-
- default:
- // Returning false for this default case so we err on the
- // side of downloading updates than deferring in case of any bugs.
- NOTREACHED();
- return false;
- }
-}
-
-OmahaRequestAction::WallClockWaitResult
-OmahaRequestAction::IsWallClockBasedWaitingSatisfied(
- OmahaResponse* output_object) {
- Time update_first_seen_at = LoadOrPersistUpdateFirstSeenAtPref();
- if (update_first_seen_at == base::Time()) {
- LOG(INFO) << "Not scattering as UpdateFirstSeenAt value cannot be read or "
- "persisted.";
- return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
- }
-
- TimeDelta elapsed_time =
- SystemState::Get()->clock()->GetWallclockTime() - update_first_seen_at;
- TimeDelta max_scatter_period =
- TimeDelta::FromDays(output_object->max_days_to_scatter);
- int64_t staging_wait_time_in_days = 0;
- // Use staging and its default max value if staging is on.
- if (SystemState::Get()->prefs()->GetInt64(kPrefsWallClockStagingWaitPeriod,
- &staging_wait_time_in_days) &&
- staging_wait_time_in_days > 0)
- max_scatter_period = TimeDelta::FromDays(kMaxWaitTimeStagingInDays);
-
- const auto* params = SystemState::Get()->request_params();
- LOG(INFO) << "Waiting Period = "
- << utils::FormatSecs(params->waiting_period().InSeconds())
- << ", Time Elapsed = "
- << utils::FormatSecs(elapsed_time.InSeconds())
- << ", MaxDaysToScatter = " << max_scatter_period.InDays();
-
- if (!output_object->deadline.empty()) {
- // The deadline is set for all rules which serve a delta update from a
- // previous FSI, which means this update will be applied mostly in OOBE
- // cases. For these cases, we shouldn't scatter so as to finish the OOBE
- // quickly.
- LOG(INFO) << "Not scattering as deadline flag is set.";
- return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
- }
-
- if (max_scatter_period.InDays() == 0) {
- // This means the Omaha rule creator decides that this rule
- // should not be scattered irrespective of the policy.
- LOG(INFO) << "Not scattering as MaxDaysToScatter in rule is 0.";
- return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
- }
-
- if (elapsed_time > max_scatter_period) {
- // This means we've waited more than the upperbound wait in the rule
- // from the time we first saw a valid update available to us.
- // This will prevent update starvation.
- LOG(INFO) << "Not scattering as we're past the MaxDaysToScatter limit.";
- return kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
- }
-
- // This means we are required to participate in scattering.
- // See if our turn has arrived now.
- TimeDelta remaining_wait_time = params->waiting_period() - elapsed_time;
- if (remaining_wait_time.InSeconds() <= 0) {
- // Yes, it's our turn now.
- LOG(INFO) << "Successfully passed the wall-clock-based-wait.";
-
- // But we can't download until the update-check-count-based wait is also
- // satisfied, so mark it as required now if update checks are enabled.
- return params->update_check_count_wait_enabled()
- ? kWallClockWaitDoneButUpdateCheckWaitRequired
- : kWallClockWaitDoneAndUpdateCheckWaitNotRequired;
- }
-
- // Not our turn yet, so we have to wait until our turn to
- // help scatter the downloads across all clients of the enterprise.
- LOG(INFO) << "Update deferred for another "
- << utils::FormatSecs(remaining_wait_time.InSeconds())
- << " per policy.";
- return kWallClockWaitNotSatisfied;
-}
-
-bool OmahaRequestAction::IsUpdateCheckCountBasedWaitingSatisfied() {
- int64_t update_check_count_value;
- const auto* params = SystemState::Get()->request_params();
-
- if (SystemState::Get()->prefs()->Exists(kPrefsUpdateCheckCount)) {
- if (!SystemState::Get()->prefs()->GetInt64(kPrefsUpdateCheckCount,
- &update_check_count_value)) {
- // We are unable to read the update check count from file for some reason.
- // So let's proceed anyway so as to not stall the update.
- LOG(ERROR) << "Unable to read update check count. "
- << "Skipping update-check-count-based-wait.";
- return true;
- }
- } else {
- // This file does not exist. This means we haven't started our update
- // check count down yet, so this is the right time to start the count down.
- update_check_count_value =
- base::RandInt(params->min_update_checks_needed(),
- params->max_update_checks_allowed());
-
- LOG(INFO) << "Randomly picked update check count value = "
- << update_check_count_value;
-
- // Write out the initial value of update_check_count_value.
- if (!SystemState::Get()->prefs()->SetInt64(kPrefsUpdateCheckCount,
- update_check_count_value)) {
- // We weren't able to write the update check count file for some reason.
- // So let's proceed anyway so as to not stall the update.
- LOG(ERROR) << "Unable to write update check count. "
- << "Skipping update-check-count-based-wait.";
- return true;
- }
- }
-
- if (update_check_count_value == 0) {
- LOG(INFO) << "Successfully passed the update-check-based-wait.";
- return true;
- }
-
- if (update_check_count_value < 0 ||
- update_check_count_value > params->max_update_checks_allowed()) {
- // We err on the side of skipping scattering logic instead of stalling
- // a machine from receiving any updates in case of any unexpected state.
- LOG(ERROR) << "Invalid value for update check count detected. "
- << "Skipping update-check-count-based-wait.";
- return true;
- }
-
- // Legal value, we need to wait for more update checks to happen
- // until this becomes 0.
- LOG(INFO) << "Deferring Omaha updates for another "
- << update_check_count_value << " update checks per policy";
- return false;
-}
-
-// static
-bool OmahaRequestAction::ParseInstallDate(OmahaParserData* parser_data,
- OmahaResponse* output_object) {
- int64_t elapsed_days = 0;
- if (!base::StringToInt64(parser_data->daystart.elapsed_days, &elapsed_days))
- return false;
-
- if (elapsed_days < 0)
- return false;
-
- output_object->install_date_days = elapsed_days;
- return true;
-}
-
-// static
-bool OmahaRequestAction::HasInstallDate() {
- return SystemState::Get()->prefs()->Exists(kPrefsInstallDateDays);
-}
-
-// static
-bool OmahaRequestAction::PersistInstallDate(
- int install_date_days,
- InstallDateProvisioningSource source) {
- TEST_AND_RETURN_FALSE(install_date_days >= 0);
-
- auto* prefs = SystemState::Get()->prefs();
- if (!prefs->SetInt64(kPrefsInstallDateDays, install_date_days))
- return false;
-
- SystemState::Get()->metrics_reporter()->ReportInstallDateProvisioningSource(
- static_cast<int>(source), // Sample.
- kProvisionedMax); // Maximum.
- return true;
-}
-
-void OmahaRequestAction::PersistCohortData(const string& prefs_key,
- const Optional<string>& new_value) {
- if (!new_value)
- return;
- const string& value = new_value.value();
- if (value.empty() && SystemState::Get()->prefs()->Exists(prefs_key)) {
- if (!SystemState::Get()->prefs()->Delete(prefs_key))
- LOG(ERROR) << "Failed to remove stored " << prefs_key << "value.";
- else
- LOG(INFO) << "Removed stored " << prefs_key << " value.";
- } else if (!value.empty()) {
- if (!SystemState::Get()->prefs()->SetString(prefs_key, value))
- LOG(INFO) << "Failed to store new setting " << prefs_key << " as "
- << value;
- else
- LOG(INFO) << "Stored cohort setting " << prefs_key << " as " << value;
- }
-}
-
-void OmahaRequestAction::PersistCohorts(const OmahaParserData& parser_data) {
- const auto* params = SystemState::Get()->request_params();
- for (const auto& app : parser_data.apps) {
- // For platform App ID.
- if (app.id == params->GetAppId()) {
- PersistCohortData(kPrefsOmahaCohort, app.cohort);
- PersistCohortData(kPrefsOmahaCohortName, app.cohortname);
- PersistCohortData(kPrefsOmahaCohortHint, app.cohorthint);
- } else if (params->IsDlcAppId(app.id)) {
- string dlc_id;
- if (!params->GetDlcId(app.id, &dlc_id)) {
- LOG(WARNING) << "Skip persisting cohorts for DLC App ID=" << app.id
- << " as it is not in the request params.";
- continue;
- }
- auto* prefs = SystemState::Get()->prefs();
- PersistCohortData(
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohort}),
- app.cohort);
- PersistCohortData(
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohortName}),
- app.cohortname);
- PersistCohortData(
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohortHint}),
- app.cohorthint);
- } else {
- LOG(WARNING) << "Skip persisting cohorts for unknown App ID=" << app.id;
- }
- }
-}
-
-void OmahaRequestAction::ActionCompleted(ErrorCode code) {
- // We only want to report this on "update check".
- if (ping_only_ || event_ != nullptr)
- return;
-
- metrics::CheckResult result = metrics::CheckResult::kUnset;
- metrics::CheckReaction reaction = metrics::CheckReaction::kUnset;
- metrics::DownloadErrorCode download_error_code =
- metrics::DownloadErrorCode::kUnset;
-
- // Regular update attempt.
- switch (code) {
- case ErrorCode::kSuccess:
- // OK, we parsed the response successfully but that does
- // necessarily mean that an update is available.
- if (HasOutputPipe()) {
- const OmahaResponse& response = GetOutputObject();
- if (response.update_exists) {
- result = metrics::CheckResult::kUpdateAvailable;
- reaction = metrics::CheckReaction::kUpdating;
- } else {
- result = metrics::CheckResult::kNoUpdateAvailable;
- }
- } else {
- result = metrics::CheckResult::kNoUpdateAvailable;
- }
- break;
-
- case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
- case ErrorCode::kOmahaUpdateIgnoredOverCellular:
- result = metrics::CheckResult::kUpdateAvailable;
- reaction = metrics::CheckReaction::kIgnored;
- break;
-
- case ErrorCode::kOmahaUpdateDeferredPerPolicy:
- result = metrics::CheckResult::kUpdateAvailable;
- reaction = metrics::CheckReaction::kDeferring;
- break;
-
- case ErrorCode::kOmahaUpdateDeferredForBackoff:
- result = metrics::CheckResult::kUpdateAvailable;
- reaction = metrics::CheckReaction::kBackingOff;
- break;
-
- default:
- // We report two flavors of errors, "Download errors" and "Parsing
- // error". Try to convert to the former and if that doesn't work
- // we know it's the latter.
- metrics::DownloadErrorCode tmp_error =
- metrics_utils::GetDownloadErrorCode(code);
- if (tmp_error != metrics::DownloadErrorCode::kInputMalformed) {
- result = metrics::CheckResult::kDownloadError;
- download_error_code = tmp_error;
- } else {
- result = metrics::CheckResult::kParsingError;
- }
- break;
- }
-
- SystemState::Get()->metrics_reporter()->ReportUpdateCheckMetrics(
- result, reaction, download_error_code);
-}
-
-bool OmahaRequestAction::ShouldIgnoreUpdate(const OmahaResponse& response,
- ErrorCode* error) const {
- // Note: policy decision to not update to a version we rolled back from.
- string rollback_version =
- SystemState::Get()->payload_state()->GetRollbackVersion();
- const auto* params = SystemState::Get()->request_params();
- if (!rollback_version.empty()) {
- LOG(INFO) << "Detected previous rollback from version " << rollback_version;
- if (rollback_version == response.version) {
- LOG(INFO) << "Received version that we rolled back from. Ignoring.";
- *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
- return true;
- }
- }
-
- if (SystemState::Get()->hardware()->IsOOBEEnabled() &&
- !SystemState::Get()->hardware()->IsOOBEComplete(nullptr) &&
- (response.deadline.empty() ||
- SystemState::Get()->payload_state()->GetRollbackHappened()) &&
- params->app_version() != "ForcedUpdate") {
- LOG(INFO) << "Ignoring a non-critical Omaha update before OOBE completion.";
- *error = ErrorCode::kNonCriticalUpdateInOOBE;
- return true;
- }
-
- if (!IsUpdateAllowedOverCurrentConnection(error, response)) {
- LOG(INFO) << "Update is not allowed over current connection.";
- return true;
- }
-
- // Currently non-critical updates always update alongside the platform update
- // (a critical update) so this case should never actually be hit if the
- // request to Omaha for updates are correct. In other words, stop the update
- // from happening as there are no packages in the response to process.
- if (response.packages.empty()) {
- LOG(ERROR) << "All packages were excluded.";
- }
-
- // Note: We could technically delete the UpdateFirstSeenAt state when we
- // return true. If we do, it'll mean a device has to restart the
- // UpdateFirstSeenAt and thus help scattering take effect when the AU is
- // turned on again. On the other hand, it also increases the chance of update
- // starvation if an admin turns AU on/off more frequently. We choose to err on
- // the side of preventing starvation at the cost of not applying scattering in
- // those cases.
- return false;
-}
-
-bool OmahaRequestAction::IsUpdateAllowedOverCellularByPrefs(
- const OmahaResponse& response) const {
- auto* prefs = SystemState::Get()->prefs();
- bool is_allowed;
- if (prefs->Exists(kPrefsUpdateOverCellularPermission) &&
- prefs->GetBoolean(kPrefsUpdateOverCellularPermission, &is_allowed) &&
- is_allowed) {
- LOG(INFO) << "Allowing updates over cellular as permission preference is "
- "set to true.";
- return true;
- }
-
- if (!prefs->Exists(kPrefsUpdateOverCellularTargetVersion) ||
- !prefs->Exists(kPrefsUpdateOverCellularTargetSize)) {
- LOG(INFO) << "Disabling updates over cellular as permission preference is "
- "set to false or does not exist while target does not exist.";
- return false;
- }
-
- std::string target_version;
- int64_t target_size;
-
- if (!prefs->GetString(kPrefsUpdateOverCellularTargetVersion,
- &target_version) ||
- !prefs->GetInt64(kPrefsUpdateOverCellularTargetSize, &target_size)) {
- LOG(INFO) << "Disabling updates over cellular as the target version or "
- "size is not accessible.";
- return false;
- }
-
- uint64_t total_packages_size = 0;
- for (const auto& package : response.packages) {
- total_packages_size += package.size;
- }
- if (target_version == response.version &&
- static_cast<uint64_t>(target_size) == total_packages_size) {
- LOG(INFO) << "Allowing updates over cellular as the target matches the"
- "omaha response.";
- return true;
- } else {
- LOG(INFO) << "Disabling updates over cellular as the target does not"
- "match the omaha response.";
- return false;
- }
-}
-
-bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection(
- ErrorCode* error, const OmahaResponse& response) const {
- ConnectionType type;
- ConnectionTethering tethering;
- ConnectionManagerInterface* connection_manager =
- SystemState::Get()->connection_manager();
- if (!connection_manager->GetConnectionProperties(&type, &tethering)) {
- LOG(INFO) << "We could not determine our connection type. "
- << "Defaulting to allow updates.";
- return true;
- }
-
- bool is_allowed = connection_manager->IsUpdateAllowedOver(type, tethering);
- bool is_device_policy_set =
- connection_manager->IsAllowedConnectionTypesForUpdateSet();
- // Treats tethered connection as if it is cellular connection.
- bool is_over_cellular = type == ConnectionType::kCellular ||
- tethering == ConnectionTethering::kConfirmed;
-
- if (!is_over_cellular) {
- // There's no need to further check user preferences as we are not over
- // cellular connection.
- if (!is_allowed)
- *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
- } else if (is_device_policy_set) {
- // There's no need to further check user preferences as the device policy
- // is set regarding updates over cellular.
- if (!is_allowed)
- *error = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
- } else {
- // Deivce policy is not set, so user preferences overwrite whether to
- // allow updates over cellular.
- is_allowed = IsUpdateAllowedOverCellularByPrefs(response);
- if (!is_allowed)
- *error = ErrorCode::kOmahaUpdateIgnoredOverCellular;
- }
-
- LOG(INFO) << "We are connected via "
- << connection_utils::StringForConnectionType(type)
- << ", Updates allowed: " << (is_allowed ? "Yes" : "No");
- return is_allowed;
-}
-
-bool OmahaRequestAction::IsRollbackEnabled() const {
- if (policy_provider_->IsConsumerDevice()) {
- LOG(INFO) << "Rollback is not enabled for consumer devices.";
- return false;
- }
-
- if (!policy_provider_->device_policy_is_loaded()) {
- LOG(INFO) << "No device policy is loaded. Assuming rollback enabled.";
- return true;
- }
-
- int allowed_milestones;
- if (!policy_provider_->GetDevicePolicy().GetRollbackAllowedMilestones(
- &allowed_milestones)) {
- LOG(INFO) << "RollbackAllowedMilestones policy can't be read. "
- "Defaulting to rollback enabled.";
- return true;
- }
-
- LOG(INFO) << "Rollback allows " << allowed_milestones << " milestones.";
- return allowed_milestones > 0;
-}
-
-void OmahaRequestAction::SetMaxKernelKeyVersionForRollback() const {
- int max_kernel_rollforward;
- int min_kernel_version =
- SystemState::Get()->hardware()->GetMinKernelKeyVersion();
- if (IsRollbackEnabled()) {
- // If rollback is enabled, set the max kernel key version to the current
- // kernel key version. This has the effect of freezing kernel key roll
- // forwards.
- //
- // TODO(zentaro): This behavior is temporary, and ensures that no kernel
- // key roll forward happens until the server side components of rollback
- // are implemented. Future changes will allow the Omaha server to return
- // the kernel key version from max_rollback_versions in the past. At that
- // point the max kernel key version will be set to that value, creating a
- // sliding window of versions that can be rolled back to.
- LOG(INFO) << "Rollback is enabled. Setting kernel_max_rollforward to "
- << min_kernel_version;
- max_kernel_rollforward = min_kernel_version;
- } else {
- // For devices that are not rollback enabled (ie. consumer devices), the
- // max kernel key version is set to 0xfffffffe, which is logically
- // infinity. This maintains the previous behavior that that kernel key
- // versions roll forward each time they are incremented.
- LOG(INFO) << "Rollback is disabled. Setting kernel_max_rollforward to "
- << kRollforwardInfinity;
- max_kernel_rollforward = kRollforwardInfinity;
- }
-
- bool max_rollforward_set =
- SystemState::Get()->hardware()->SetMaxKernelKeyRollforward(
- max_kernel_rollforward);
- if (!max_rollforward_set) {
- LOG(ERROR) << "Failed to set kernel_max_rollforward";
- }
- // Report metrics
- SystemState::Get()->metrics_reporter()->ReportKeyVersionMetrics(
- min_kernel_version, max_kernel_rollforward, max_rollforward_set);
-}
-
-base::Time OmahaRequestAction::LoadOrPersistUpdateFirstSeenAtPref() const {
- Time update_first_seen_at;
- int64_t update_first_seen_at_int;
- if (SystemState::Get()->prefs()->Exists(kPrefsUpdateFirstSeenAt)) {
- if (SystemState::Get()->prefs()->GetInt64(kPrefsUpdateFirstSeenAt,
- &update_first_seen_at_int)) {
- // Note: This timestamp could be that of ANY update we saw in the past
- // (not necessarily this particular update we're considering to apply)
- // but never got to apply because of some reason (e.g. stop AU policy,
- // updates being pulled out from Omaha, changes in target version prefix,
- // new update being rolled out, etc.). But for the purposes of scattering
- // it doesn't matter which update the timestamp corresponds to. i.e.
- // the clock starts ticking the first time we see an update and we're
- // ready to apply when the random wait period is satisfied relative to
- // that first seen timestamp.
- update_first_seen_at = Time::FromInternalValue(update_first_seen_at_int);
- LOG(INFO) << "Using persisted value of UpdateFirstSeenAt: "
- << utils::ToString(update_first_seen_at);
- } else {
- // This seems like an unexpected error where the persisted value exists
- // but it's not readable for some reason.
- LOG(INFO) << "UpdateFirstSeenAt value cannot be read";
- return base::Time();
- }
- } else {
- update_first_seen_at = SystemState::Get()->clock()->GetWallclockTime();
- update_first_seen_at_int = update_first_seen_at.ToInternalValue();
- if (SystemState::Get()->prefs()->SetInt64(kPrefsUpdateFirstSeenAt,
- update_first_seen_at_int)) {
- LOG(INFO) << "Persisted the new value for UpdateFirstSeenAt: "
- << utils::ToString(update_first_seen_at);
- } else {
- // This seems like an unexpected error where the value cannot be
- // persisted for some reason.
- LOG(INFO) << "UpdateFirstSeenAt value "
- << utils::ToString(update_first_seen_at)
- << " cannot be persisted";
- return base::Time();
- }
- }
- return update_first_seen_at;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_request_action.h b/cros/omaha_request_action.h
deleted file mode 100644
index 4926c7d8..00000000
--- a/cros/omaha_request_action.h
+++ /dev/null
@@ -1,312 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_OMAHA_REQUEST_ACTION_H_
-#define UPDATE_ENGINE_CROS_OMAHA_REQUEST_ACTION_H_
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-#include <base/optional.h>
-#include <brillo/secure_blob.h>
-#include <curl/curl.h>
-
-#include "update_engine/common/action.h"
-#include "update_engine/common/http_fetcher.h"
-#include "update_engine/cros/omaha_request_builder_xml.h"
-#include "update_engine/cros/omaha_response.h"
-
-// The Omaha Request action makes a request to Omaha and can output
-// the response on the output ActionPipe.
-
-namespace policy {
-class PolicyProvider;
-}
-
-namespace chromeos_update_engine {
-
-class NoneType;
-class OmahaRequestAction;
-class OmahaRequestParams;
-
-// This struct is declared in the .cc file.
-struct OmahaParserData;
-
-template <>
-class ActionTraits<OmahaRequestAction> {
- public:
- // Takes parameters on the input pipe.
- typedef NoneType InputObjectType;
- // On UpdateCheck success, puts the Omaha response on output. Event
- // requests do not have an output pipe.
- typedef OmahaResponse OutputObjectType;
-};
-
-class OmahaRequestAction : public Action<OmahaRequestAction>,
- public HttpFetcherDelegate {
- public:
- static const int kPingTimeJump = -2;
- // We choose this value of 3 as a heuristic for a work day in trying
- // each URL, assuming we check roughly every 45 mins. This is a good time to
- // wait so we don't give up the preferred URLs, but allow using the URL that
- // appears earlier in list for every payload before resorting to the fallback
- // URLs in the candiate URL list.
- static const int kDefaultMaxFailureCountPerUrl = 3;
-
- // If staging is enabled, set the maximum wait time to 28 days, since that is
- // the predetermined wait time for staging.
- static const int kMaxWaitTimeStagingInDays = 28;
-
- // These are the possible outcome upon checking whether we satisfied
- // the wall-clock-based-wait.
- enum WallClockWaitResult {
- kWallClockWaitNotSatisfied,
- kWallClockWaitDoneButUpdateCheckWaitRequired,
- kWallClockWaitDoneAndUpdateCheckWaitNotRequired,
- };
-
- // The ctor takes in all the parameters that will be used for making
- // the request to Omaha. For some of them we have constants that
- // should be used.
- //
- // Takes ownership of the passed in HttpFetcher. Useful for testing.
- //
- // Takes ownership of the passed in OmahaEvent. If |event| is null,
- // this is an UpdateCheck request, otherwise it's an Event request.
- // Event requests always succeed.
- //
- // A good calling pattern is:
- // OmahaRequestAction(..., new OmahaEvent(...), new WhateverHttpFetcher);
- // or
- // OmahaRequestAction(..., nullptr, new WhateverHttpFetcher);
- OmahaRequestAction(OmahaEvent* event,
- std::unique_ptr<HttpFetcher> http_fetcher,
- bool ping_only,
- const std::string& session_id);
- ~OmahaRequestAction() override;
- typedef ActionTraits<OmahaRequestAction>::InputObjectType InputObjectType;
- typedef ActionTraits<OmahaRequestAction>::OutputObjectType OutputObjectType;
- void PerformAction() override;
- void TerminateProcessing() override;
- void ActionCompleted(ErrorCode code) override;
-
- int GetHTTPResponseCode() { return http_fetcher_->http_response_code(); }
-
- // Debugging/logging
- static std::string StaticType() { return "OmahaRequestAction"; }
- std::string Type() const override { return StaticType(); }
-
- // Delegate methods (see http_fetcher.h)
- bool ReceivedBytes(HttpFetcher* fetcher,
- const void* bytes,
- size_t length) override;
-
- void TransferComplete(HttpFetcher* fetcher, bool successful) override;
-
- // Returns true if this is an Event request, false if it's an UpdateCheck.
- bool IsEvent() const { return event_.get() != nullptr; }
-
- private:
- friend class OmahaRequestActionTest;
- friend class OmahaRequestActionTestProcessorDelegate;
- FRIEND_TEST(OmahaRequestActionTest, GetInstallDateWhenNoPrefsNorOOBE);
- FRIEND_TEST(OmahaRequestActionTest,
- GetInstallDateWhenOOBECompletedWithInvalidDate);
- FRIEND_TEST(OmahaRequestActionTest,
- GetInstallDateWhenOOBECompletedWithValidDate);
- FRIEND_TEST(OmahaRequestActionTest,
- GetInstallDateWhenOOBECompletedDateChanges);
- friend class UpdateAttempterTest;
- FRIEND_TEST(UpdateAttempterTest, SessionIdTestEnforceEmptyStrPingOmaha);
- FRIEND_TEST(UpdateAttempterTest, SessionIdTestConsistencyInUpdateFlow);
-
- // Enumeration used in PersistInstallDate().
- enum InstallDateProvisioningSource {
- kProvisionedFromOmahaResponse,
- kProvisionedFromOOBEMarker,
-
- // kProvisionedMax is the count of the number of enums above. Add
- // any new enums above this line only.
- kProvisionedMax
- };
-
- // Gets the install date, expressed as the number of PST8PDT
- // calendar weeks since January 1st 2007, times seven. Returns -1 if
- // unknown. See http://crbug.com/336838 for details about this value.
- static int GetInstallDate();
-
- // Parses the Omaha Response in |doc| and sets the
- // |install_date_days| field of |output_object| to the value of the
- // elapsed_days attribute of the daystart element. Returns True if
- // the value was set, False if it wasn't found.
- static bool ParseInstallDate(OmahaParserData* parser_data,
- OmahaResponse* output_object);
-
- // Returns True if the kPrefsInstallDateDays state variable is set,
- // False otherwise.
- static bool HasInstallDate();
-
- // Writes |install_date_days| into the kPrefsInstallDateDays state
- // variable and emits an UMA stat for the |source| used. Returns
- // True if the value was written, False if an error occurred.
- static bool PersistInstallDate(int install_date_days,
- InstallDateProvisioningSource source);
-
- // Persist the new cohort value received in the XML file in the |prefs_key|
- // preference file. If the |new_value| is empty, do nothing. If the
- // |new_value| stores and empty value, the currently stored value will be
- // deleted. Don't call this function with an empty |new_value| if the value
- // was not set in the XML, since that would delete the stored value.
- void PersistCohortData(const std::string& prefs_key,
- const base::Optional<std::string>& new_value);
-
- // Parses and persists the cohorts sent back in the updatecheck tag
- // attributes.
- void PersistCohorts(const OmahaParserData& parser_data);
-
- // If this is an update check request, initializes
- // |ping_active_days_| and |ping_roll_call_days_| to values that may
- // be sent as pings to Omaha.
- void InitPingDays();
-
- // Based on the persistent preference store values, calculates the
- // number of days since the last ping sent for |key|.
- int CalculatePingDays(const std::string& key);
-
- // Returns whether we have "active_days" or "roll_call_days" ping values to
- // send to Omaha and thus we should include them in the response.
- bool ShouldPing() const;
-
- // Process Omaha's response to a ping request and store the results in the DLC
- // metadata directory.
- void StorePingReply(const OmahaParserData& parser_data) const;
-
- // Returns true if the download of a new update should be deferred.
- // False if the update can be downloaded.
- bool ShouldDeferDownload(OmahaResponse* output_object);
-
- // Returns true if the basic wall-clock-based waiting period has been
- // satisfied based on the scattering policy setting. False otherwise.
- // If true, it also indicates whether the additional update-check-count-based
- // waiting period also needs to be satisfied before the download can begin.
- WallClockWaitResult IsWallClockBasedWaitingSatisfied(
- OmahaResponse* output_object);
-
- // Returns true if the update-check-count-based waiting period has been
- // satisfied. False otherwise.
- bool IsUpdateCheckCountBasedWaitingSatisfied();
-
- // Parses the response from Omaha that's available in |doc| using the other
- // helper methods below and populates the |output_object| with the relevant
- // values. Returns true if we should continue the parsing. False otherwise,
- // in which case it sets any error code using |completer|.
- bool ParseResponse(OmahaParserData* parser_data,
- OmahaResponse* output_object,
- ScopedActionCompleter* completer);
-
- // Parses the status property in the given update_check_node and populates
- // |output_object| if valid. Returns true if we should continue the parsing.
- // False otherwise, in which case it sets any error code using |completer|.
- bool ParseStatus(OmahaParserData* parser_data,
- OmahaResponse* output_object,
- ScopedActionCompleter* completer);
-
- // Parses the URL nodes in the given XML document and populates
- // |output_object| if valid. Returns true if we should continue the parsing.
- // False otherwise, in which case it sets any error code using |completer|.
- bool ParseUrls(OmahaParserData* parser_data,
- OmahaResponse* output_object,
- ScopedActionCompleter* completer);
-
- // Parses the other parameters in the given XML document and populates
- // |output_object| if valid. Returns true if we should continue the parsing.
- // False otherwise, in which case it sets any error code using |completer|.
- bool ParseParams(OmahaParserData* parser_data,
- OmahaResponse* output_object,
- ScopedActionCompleter* completer);
-
- // Called by TransferComplete() to complete processing, either
- // asynchronously after looking up resources via p2p or directly.
- void CompleteProcessing();
-
- // Helper to asynchronously look up payload on the LAN.
- void LookupPayloadViaP2P(const OmahaResponse& response);
-
- // Callback used by LookupPayloadViaP2P().
- void OnLookupPayloadViaP2PCompleted(const std::string& url);
-
- // Returns true if the current update should be ignored.
- bool ShouldIgnoreUpdate(const OmahaResponse& response,
- ErrorCode* error) const;
-
- // Return true if updates are allowed by user preferences.
- bool IsUpdateAllowedOverCellularByPrefs(const OmahaResponse& response) const;
-
- // Returns true if updates are allowed over the current type of connection.
- // False otherwise.
- bool IsUpdateAllowedOverCurrentConnection(
- ErrorCode* error, const OmahaResponse& response) const;
-
- // Returns true if rollback is enabled. Always returns false for consumer
- // devices.
- bool IsRollbackEnabled() const;
-
- // Sets the appropriate max kernel key version based on whether rollback is
- // enabled.
- void SetMaxKernelKeyVersionForRollback() const;
-
- // Reads and returns the kPrefsUpdateFirstSeenAt pref if the pref currently
- // exists. Otherwise saves the current wallclock time to the
- // kPrefsUpdateFirstSeenAt pref and returns it as a base::Time object.
- base::Time LoadOrPersistUpdateFirstSeenAtPref() const;
-
- // Pointer to the OmahaEvent info. This is an UpdateCheck request if null.
- std::unique_ptr<OmahaEvent> event_;
-
- // pointer to the HttpFetcher that does the http work
- std::unique_ptr<HttpFetcher> http_fetcher_;
-
- // Used for fetching information about the device policy.
- std::unique_ptr<policy::PolicyProvider> policy_provider_;
-
- // If true, only include the <ping> element in the request.
- bool ping_only_;
-
- // Stores the response from the omaha server
- brillo::Blob response_buffer_;
-
- // Initialized by InitPingDays to values that may be sent to Omaha
- // as part of a ping message. Note that only positive values and -1
- // are sent to Omaha.
- int ping_active_days_;
- int ping_roll_call_days_;
-
- std::string session_id_;
-
- DISALLOW_COPY_AND_ASSIGN(OmahaRequestAction);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_OMAHA_REQUEST_ACTION_H_
diff --git a/cros/omaha_request_action_fuzzer.cc b/cros/omaha_request_action_fuzzer.cc
deleted file mode 100644
index 995de8c5..00000000
--- a/cros/omaha_request_action_fuzzer.cc
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// Copyright (C) 2018 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 <brillo/message_loops/fake_message_loop.h>
-
-#include "update_engine/common/mock_http_fetcher.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/cros/omaha_request_action.h"
-
-class Environment {
- public:
- Environment() { logging::SetMinLogLevel(logging::LOG_FATAL); }
-};
-
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- static Environment env;
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
-
- chromeos_update_engine::FakeSystemState::CreateInstance();
- auto omaha_request_action =
- std::make_unique<chromeos_update_engine::OmahaRequestAction>(
- nullptr,
- std::make_unique<chromeos_update_engine::MockHttpFetcher>(
- data, size, nullptr),
- false,
- "" /* session_id */);
- auto collector_action =
- std::make_unique<chromeos_update_engine::ObjectCollectorAction<
- chromeos_update_engine::OmahaResponse>>();
- BondActions(omaha_request_action.get(), collector_action.get());
- chromeos_update_engine::ActionProcessor action_processor;
- action_processor.EnqueueAction(std::move(omaha_request_action));
- action_processor.EnqueueAction(std::move(collector_action));
- action_processor.StartProcessing();
-
- loop.Run();
- return 0;
-}
diff --git a/cros/omaha_request_action_unittest.cc b/cros/omaha_request_action_unittest.cc
deleted file mode 100644
index 01be1a82..00000000
--- a/cros/omaha_request_action_unittest.cc
+++ /dev/null
@@ -1,3189 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/omaha_request_action.h"
-
-#include <stdint.h>
-
-#include <limits>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/memory/ptr_util.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <base/time/time.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <expat.h>
-#include <gtest/gtest.h>
-#include <policy/libpolicy.h>
-#include <policy/mock_libpolicy.h>
-
-#include "update_engine/common/action_pipe.h"
-#include "update_engine/common/constants.h"
-#include "update_engine/common/fake_prefs.h"
-#include "update_engine/common/hash_calculator.h"
-#include "update_engine/common/metrics_reporter_interface.h"
-#include "update_engine/common/mock_excluder.h"
-#include "update_engine/common/mock_http_fetcher.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/cros/mock_connection_manager.h"
-#include "update_engine/cros/mock_payload_state.h"
-#include "update_engine/cros/omaha_request_builder_xml.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/omaha_utils.h"
-#include "update_engine/update_manager/rollback_prefs.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_manager::kRollforwardInfinity;
-using std::pair;
-using std::string;
-using std::vector;
-using testing::_;
-using testing::AllOf;
-using testing::AnyNumber;
-using testing::DoAll;
-using testing::Ge;
-using testing::Le;
-using testing::NiceMock;
-using testing::Return;
-using testing::ReturnPointee;
-using testing::ReturnRef;
-using testing::SaveArg;
-using testing::SetArgPointee;
-using testing::StrictMock;
-
-namespace {
-
-static_assert(kRollforwardInfinity == 0xfffffffe,
- "Don't change the value of kRollforward infinity unless its "
- "size has been changed in firmware.");
-
-const char kCurrentVersion[] = "0.1.0.0";
-const char kTestAppId[] = "test-app-id";
-const char kTestAppId2[] = "test-app2-id";
-const char kTestAppIdSkipUpdatecheck[] = "test-app-id-skip-updatecheck";
-const char kDlcId1[] = "dlc-id-1";
-const char kDlcId2[] = "dlc-id-2";
-
-// This is a helper struct to allow unit tests build an update response with the
-// values they care about.
-struct FakeUpdateResponse {
- string GetRollbackVersionAttributes() const {
- string num_milestones;
- num_milestones = base::NumberToString(rollback_allowed_milestones);
- const string rollback_version =
- " _firmware_version_" + num_milestones + "=\"" +
- past_rollback_key_version.first + "\"" + " _kernel_version_" +
- num_milestones + "=\"" + past_rollback_key_version.second + "\"";
-
- return (rollback ? " _rollback=\"true\"" : "") + rollback_version +
- (!rollback_firmware_version.empty()
- ? " _firmware_version=\"" + rollback_firmware_version + "\""
- : "") +
- (!rollback_kernel_version.empty()
- ? " _kernel_version=\"" + rollback_kernel_version + "\""
- : "");
- }
-
- string GetNoUpdateResponse() const {
- string entity_str;
- if (include_entity)
- entity_str = "<!DOCTYPE response [<!ENTITY CrOS \"ChromeOS\">]>";
- return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + entity_str +
- "<response protocol=\"3.0\">"
- "<daystart elapsed_seconds=\"100\"/>"
- "<app appid=\"" +
- app_id + "\" " +
- (include_cohorts
- ? "cohort=\"" + cohort + "\" cohorthint=\"" + cohorthint +
- "\" cohortname=\"" + cohortname + "\" "
- : "") +
- " status=\"ok\">"
- "<ping status=\"ok\"/>"
- "<updatecheck status=\"noupdate\"/></app>" +
- (multi_app_no_update
- ? "<app appid=\"" + app_id2 +
- "\"><updatecheck status=\"noupdate\"/></app>"
- : "") +
- "</response>";
- }
-
- string GetUpdateResponse() const {
- chromeos_update_engine::OmahaRequestParams request_params;
- request_params.set_app_id(app_id);
- return "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\">"
- "<daystart elapsed_seconds=\"100\"" +
- (elapsed_days.empty() ? ""
- : (" elapsed_days=\"" + elapsed_days + "\"")) +
- "/>"
- "<app appid=\"" +
- app_id + "\" " +
- (include_cohorts
- ? "cohort=\"" + cohort + "\" cohorthint=\"" + cohorthint +
- "\" cohortname=\"" + cohortname + "\" "
- : "") +
- " status=\"ok\">"
- "<ping status=\"ok\"/><updatecheck status=\"ok\"" +
- GetRollbackVersionAttributes() + ">" + "<urls><url codebase=\"" +
- codebase +
- "\"/></urls>"
- "<manifest version=\"" +
- version +
- "\">"
- "<packages><package hash=\"not-used\" name=\"" +
- filename + "\" size=\"" + base::NumberToString(size) + "\" fp=\"" +
- fp + "\" hash_sha256=\"" + hash + "\"/>" +
- (multi_package ? "<package name=\"package2\" size=\"222\" fp=\"" +
- fp2 + "\" hash_sha256=\"hash2\"/>"
- : "") +
- "</packages>"
- "<actions><action event=\"postinstall\" MetadataSize=\"11" +
- (multi_package ? ":22" : "") + "\" MoreInfo=\"" + more_info_url +
- "\" Prompt=\"" + prompt +
- "\" "
- "IsDeltaPayload=\"true" +
- (multi_package ? ":false" : "") +
- "\" "
- "MaxDaysToScatter=\"" +
- max_days_to_scatter +
- "\" "
- "sha256=\"not-used\" " +
- (deadline.empty() ? "" : ("deadline=\"" + deadline + "\" ")) +
- (disable_p2p_for_downloading ? "DisableP2PForDownloading=\"true\" "
- : "") +
- (disable_p2p_for_sharing ? "DisableP2PForSharing=\"true\" " : "") +
- (powerwash ? "Powerwash=\"true\" " : "") +
- "/></actions></manifest></updatecheck></app>" +
- (multi_app
- ? "<app appid=\"" + app_id2 + "\"" +
- (include_cohorts ? " cohort=\"cohort2\"" : "") +
- "><updatecheck status=\"ok\"><urls><url codebase=\"" +
- codebase2 + "\"/></urls><manifest version=\"" + version2 +
- "\"><packages>"
- "<package name=\"package3\" size=\"333\" fp=\"" +
- fp2 +
- "\" hash_sha256=\"hash3\"/></packages>"
- "<actions><action event=\"postinstall\" " +
- (multi_app_self_update
- ? "noupdate=\"true\" IsDeltaPayload=\"true\" "
- : "IsDeltaPayload=\"false\" ") +
- "MetadataSize=\"33\"/></actions>"
- "</manifest></updatecheck></app>"
- : "") +
- (multi_app_no_update
- ? "<app><updatecheck status=\"noupdate\"/></app>"
- : "") +
- (multi_app_skip_updatecheck
- ? "<app appid=\"" + app_id_skip_updatecheck + "\"></app>"
- : "") +
- (dlc_app_update
- ? "<app appid=\"" + request_params.GetDlcAppId(kDlcId1) +
- "\" " +
- (include_dlc_cohorts
- ? "cohort=\"" + dlc_cohort + "\" cohorthint=\"" +
- dlc_cohorthint + "\" cohortname=\"" +
- dlc_cohortname + "\" "
- : "") +
- "status=\"ok\">"
- "<updatecheck status=\"ok\"><urls><url codebase=\"" +
- codebase + "\"/><url codebase=\"" + codebase2 +
- "\"/></urls><manifest version=\"" + version +
- "\"><packages><package name=\"package3\" size=\"333\" "
- "fp=\"" +
- fp2 +
- "\" hash_sha256=\"hash3\"/></packages>"
- "<actions><action event=\"install\" run=\".signed\"/>"
- "<action event=\"postinstall\" MetadataSize=\"33\"/>"
- "</actions></manifest></updatecheck></app>"
- : "") +
- (dlc_app_no_update
- ? "<app appid=\"" + request_params.GetDlcAppId(kDlcId2) +
- +"\" " +
- (include_dlc_cohorts
- ? "cohort=\"" + dlc_cohort + "\" cohorthint=\"" +
- dlc_cohorthint + "\" cohortname=\"" +
- dlc_cohortname + "\" "
- : "") +
- "><updatecheck status=\"noupdate\"/></app>"
- : "") +
- "</response>";
- }
-
- // Return the payload URL, which is split in two fields in the XML response.
- string GetPayloadUrl() { return codebase + filename; }
-
- string app_id = kTestAppId;
- string app_id2 = kTestAppId2;
- string app_id_skip_updatecheck = kTestAppIdSkipUpdatecheck;
- string version = "1.2.3.4";
- string version2 = "2.3.4.5";
- string more_info_url = "http://more/info";
- string prompt = "true";
- string codebase = "http://code/base/";
- string codebase2 = "http://code/base/2/";
- string filename = "file.signed";
- string hash = "4841534831323334";
- string fp = "3.98ba213e";
- string fp2 = "3.755aff78e";
- uint64_t size = 123;
- string deadline = "";
- string max_days_to_scatter = "7";
- string elapsed_days = "42";
-
- // P2P setting defaults to allowed.
- bool disable_p2p_for_downloading = false;
- bool disable_p2p_for_sharing = false;
-
- bool powerwash = false;
-
- // Omaha cohorts settings.
- bool include_cohorts = false;
- string cohort = "";
- string cohorthint = "";
- string cohortname = "";
- // Whether to include Omaha cohorts for DLC apps.
- bool include_dlc_cohorts = false;
- string dlc_cohort = "";
- string dlc_cohorthint = "";
- string dlc_cohortname = "";
-
- // Whether to include the CrOS <!ENTITY> in the XML response.
- bool include_entity = false;
-
- // Whether to include more than one app.
- bool multi_app = false;
- // Whether to include an app with noupdate="true".
- bool multi_app_self_update = false;
- // Whether to include an additional app with status="noupdate".
- bool multi_app_no_update = false;
- // Whether to include an additional app with no updatecheck tag.
- bool multi_app_skip_updatecheck = false;
- // Whether to include more than one package in an app.
- bool multi_package = false;
- // Whether to include a DLC app with updatecheck tag.
- bool dlc_app_update = false;
- // Whether to include a DLC app with no updatecheck tag.
- bool dlc_app_no_update = false;
-
- // Whether the payload is a rollback.
- bool rollback = false;
- // The verified boot firmware key version for the rollback image.
- string rollback_firmware_version = "";
- // The verified boot kernel key version for the rollback image.
- string rollback_kernel_version = "";
- // The number of milestones back that the verified boot key version has been
- // supplied.
- uint32_t rollback_allowed_milestones = 0;
- // The verified boot key version for the
- // |current - rollback_allowed_milestones| most recent release.
- // The pair contains <firmware_key_version, kernel_key_version> each
- // of which is in the form "key_version.version".
- pair<string, string> past_rollback_key_version;
-};
-
-} // namespace
-
-namespace chromeos_update_engine {
-
-class OmahaRequestActionTestProcessorDelegate : public ActionProcessorDelegate {
- public:
- OmahaRequestActionTestProcessorDelegate()
- : expected_code_(ErrorCode::kSuccess),
- interactive_(false),
- test_http_fetcher_headers_(false) {}
- ~OmahaRequestActionTestProcessorDelegate() override = default;
-
- void ProcessingDone(const ActionProcessor* processor,
- ErrorCode code) override {
- brillo::MessageLoop::current()->BreakLoop();
- }
-
- void ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) override {
- // Make sure actions always succeed.
- if (action->Type() == OmahaRequestAction::StaticType()) {
- EXPECT_EQ(expected_code_, code);
- // Check that the headers were set in the fetcher during the action. Note
- // that we set this request as "interactive".
- auto fetcher = static_cast<const MockHttpFetcher*>(
- static_cast<OmahaRequestAction*>(action)->http_fetcher_.get());
-
- if (test_http_fetcher_headers_) {
- EXPECT_EQ(interactive_ ? "fg" : "bg",
- fetcher->GetHeader("X-Goog-Update-Interactivity"));
- EXPECT_EQ(kTestAppId, fetcher->GetHeader("X-Goog-Update-AppId"));
- EXPECT_NE("", fetcher->GetHeader("X-Goog-Update-Updater"));
- }
- post_data_ = fetcher->post_data();
- } else if (action->Type() ==
- ObjectCollectorAction<OmahaResponse>::StaticType()) {
- EXPECT_EQ(ErrorCode::kSuccess, code);
- auto collector_action =
- static_cast<ObjectCollectorAction<OmahaResponse>*>(action);
- omaha_response_.reset(new OmahaResponse(collector_action->object()));
- EXPECT_TRUE(omaha_response_);
- } else {
- EXPECT_EQ(ErrorCode::kSuccess, code);
- }
- }
- ErrorCode expected_code_;
- brillo::Blob post_data_;
- bool interactive_;
- bool test_http_fetcher_headers_;
- std::unique_ptr<OmahaResponse> omaha_response_;
-};
-
-struct TestUpdateCheckParams {
- string http_response;
- int fail_http_response_code;
- bool ping_only;
- bool is_consumer_device;
- int rollback_allowed_milestones;
- bool is_policy_loaded;
- ErrorCode expected_code;
- metrics::CheckResult expected_check_result;
- metrics::CheckReaction expected_check_reaction;
- metrics::DownloadErrorCode expected_download_error_code;
- string session_id;
-};
-
-class OmahaRequestActionTest : public ::testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
-
- request_params_.set_os_sp("service_pack");
- request_params_.set_os_board("x86-generic");
- request_params_.set_app_id(kTestAppId);
- request_params_.set_app_version(kCurrentVersion);
- request_params_.set_app_lang("en-US");
- request_params_.set_current_channel("unittest");
- request_params_.set_target_channel("unittest");
- request_params_.set_hwid("OEM MODEL 09235 7471");
- request_params_.set_delta_okay(true);
- request_params_.set_interactive(false);
- request_params_.set_update_url("http://url");
- request_params_.set_target_version_prefix("");
- request_params_.set_rollback_allowed(false);
- request_params_.set_is_powerwash_allowed(false);
- request_params_.set_is_install(false);
- request_params_.set_dlc_apps_params({});
-
- FakeSystemState::Get()->set_request_params(&request_params_);
- fake_prefs_ = FakeSystemState::Get()->fake_prefs();
-
- // Setting the default update check params. Lookup |TestUpdateCheck()|.
- tuc_params_ = {
- .http_response = "",
- .fail_http_response_code = -1,
- .ping_only = false,
- .is_consumer_device = true,
- .rollback_allowed_milestones = 0,
- .is_policy_loaded = false,
- .expected_code = ErrorCode::kSuccess,
- .expected_check_result = metrics::CheckResult::kUpdateAvailable,
- .expected_check_reaction = metrics::CheckReaction::kUpdating,
- .expected_download_error_code = metrics::DownloadErrorCode::kUnset,
- };
-
- ON_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetExcluder())
- .WillByDefault(Return(&mock_excluder_));
- }
-
- // This function uses the parameters in |tuc_params_| to do an update check.
- // It will fill out |post_str_| with the result data and |response| with
- // |OmahaResponse|. Returns true iff an output response was obtained from the
- // |OmahaRequestAction|. If |fail_http_response_code| is non-negative, the
- // transfer will fail with that code. |ping_only| is passed through to the
- // |OmahaRequestAction| constructor.
- //
- // The |expected_check_result|, |expected_check_reaction| and
- // |expected_error_code| parameters are for checking expectations about
- // reporting UpdateEngine.Check.{Result,Reaction,DownloadError} UMA
- // statistics. Use the appropriate ::kUnset value to specify that the given
- // metric should not be reported.
- bool TestUpdateCheck();
-
- // Tests events using |event| and |https_response|. It will fill up
- // |post_str_| with the result data.
- void TestEvent(OmahaEvent* event, const string& http_response);
-
- // Runs and checks a ping test. |ping_only| indicates whether it should send
- // only a ping or also an updatecheck.
- void PingTest(bool ping_only);
-
- // InstallDate test helper function.
- bool InstallDateParseHelper(const string& elapsed_days,
- OmahaResponse* response);
-
- // P2P test helper function.
- void P2PTest(bool initial_allow_p2p_for_downloading,
- bool initial_allow_p2p_for_sharing,
- bool omaha_disable_p2p_for_downloading,
- bool omaha_disable_p2p_for_sharing,
- bool payload_state_allow_p2p_attempt,
- bool expect_p2p_client_lookup,
- const string& p2p_client_result_url,
- bool expected_allow_p2p_for_downloading,
- bool expected_allow_p2p_for_sharing,
- const string& expected_p2p_url);
-
- StrictMock<MockExcluder> mock_excluder_;
- FakeUpdateResponse fake_update_response_;
- // Used by all tests.
- OmahaRequestParams request_params_;
-
- FakePrefs* fake_prefs_;
-
- OmahaRequestActionTestProcessorDelegate delegate_;
-
- bool test_http_fetcher_headers_{false};
-
- TestUpdateCheckParams tuc_params_;
-
- OmahaResponse response_;
- string post_str_;
-};
-
-class OmahaRequestActionDlcPingTest : public OmahaRequestActionTest {
- protected:
- void SetUp() override {
- OmahaRequestActionTest::SetUp();
- dlc_id_ = "dlc0";
- active_key_ = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id_, kPrefsPingActive});
- last_active_key_ = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id_, kPrefsPingLastActive});
- last_rollcall_key_ = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id_, kPrefsPingLastRollcall});
-
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><daystart elapsed_days=\"4763\" "
- "elapsed_seconds=\"36540\"/><app appid=\"test-app-id\" status=\"ok\">\""
- "<updatecheck status=\"noupdate\"/></app><app "
- "appid=\"test-app-id_dlc0\" "
- "status=\"ok\"><ping status=\"ok\"/><updatecheck status=\"noupdate\"/>"
- "</app></response>";
- tuc_params_.expected_check_result =
- metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
- }
-
- std::string dlc_id_;
- std::string active_key_;
- std::string last_active_key_;
- std::string last_rollcall_key_;
-};
-
-bool OmahaRequestActionTest::TestUpdateCheck() {
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
- auto fetcher =
- std::make_unique<MockHttpFetcher>(tuc_params_.http_response.data(),
- tuc_params_.http_response.size(),
- nullptr);
- if (tuc_params_.fail_http_response_code >= 0) {
- fetcher->FailTransfer(tuc_params_.fail_http_response_code);
- }
- // This ensures the tests didn't forget to update |FakeSystemState| if they
- // are not using the default |request_params_|.
- EXPECT_EQ(&request_params_, FakeSystemState::Get()->request_params());
-
- auto omaha_request_action =
- std::make_unique<OmahaRequestAction>(nullptr,
- std::move(fetcher),
- tuc_params_.ping_only,
- tuc_params_.session_id);
-
- auto mock_policy_provider =
- std::make_unique<NiceMock<policy::MockPolicyProvider>>();
- EXPECT_CALL(*mock_policy_provider, IsConsumerDevice())
- .WillRepeatedly(Return(tuc_params_.is_consumer_device));
-
- EXPECT_CALL(*mock_policy_provider, device_policy_is_loaded())
- .WillRepeatedly(Return(tuc_params_.is_policy_loaded));
-
- const policy::MockDevicePolicy device_policy;
- const bool get_allowed_milestone_succeeds =
- tuc_params_.rollback_allowed_milestones >= 0;
- EXPECT_CALL(device_policy, GetRollbackAllowedMilestones(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(tuc_params_.rollback_allowed_milestones),
- Return(get_allowed_milestone_succeeds)));
-
- EXPECT_CALL(*mock_policy_provider, GetDevicePolicy())
- .WillRepeatedly(ReturnRef(device_policy));
- omaha_request_action->policy_provider_ = std::move(mock_policy_provider);
-
- delegate_.expected_code_ = tuc_params_.expected_code;
- delegate_.interactive_ = request_params_.interactive();
- delegate_.test_http_fetcher_headers_ = test_http_fetcher_headers_;
- ActionProcessor processor;
- processor.set_delegate(&delegate_);
-
- auto collector_action =
- std::make_unique<ObjectCollectorAction<OmahaResponse>>();
- BondActions(omaha_request_action.get(), collector_action.get());
- processor.EnqueueAction(std::move(omaha_request_action));
- processor.EnqueueAction(std::move(collector_action));
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportUpdateCheckMetrics(_, _, _))
- .Times(AnyNumber());
-
- EXPECT_CALL(
- *FakeSystemState::Get()->mock_metrics_reporter(),
- ReportUpdateCheckMetrics(tuc_params_.expected_check_result,
- tuc_params_.expected_check_reaction,
- tuc_params_.expected_download_error_code))
- .Times(tuc_params_.ping_only ? 0 : 1);
-
- loop.PostTask(base::Bind(
- [](ActionProcessor* processor) { processor->StartProcessing(); },
- base::Unretained(&processor)));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
- if (delegate_.omaha_response_)
- response_ = *delegate_.omaha_response_;
- post_str_ = string(delegate_.post_data_.begin(), delegate_.post_data_.end());
- return delegate_.omaha_response_ != nullptr;
-}
-
-// Tests Event requests -- they should always succeed. |out_post_data| may be
-// null; if non-null, the post-data received by the mock HttpFetcher is
-// returned.
-void OmahaRequestActionTest::TestEvent(OmahaEvent* event,
- const string& http_response) {
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
-
- auto action = std::make_unique<OmahaRequestAction>(
- event,
- std::make_unique<MockHttpFetcher>(
- http_response.data(), http_response.size(), nullptr),
- false,
- "");
- ActionProcessor processor;
- processor.set_delegate(&delegate_);
- processor.EnqueueAction(std::move(action));
-
- loop.PostTask(base::Bind(
- [](ActionProcessor* processor) { processor->StartProcessing(); },
- base::Unretained(&processor)));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
-
- post_str_ = string(delegate_.post_data_.begin(), delegate_.post_data_.end());
-}
-
-TEST_F(OmahaRequestActionTest, RejectEntities) {
- fake_update_response_.include_entity = true;
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLHasEntityDecl;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, NoUpdateTest) {
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, MultiAppNoUpdateTest) {
- fake_update_response_.multi_app_no_update = true;
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, MultiAppNoPartialUpdateTest) {
- fake_update_response_.multi_app_no_update = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, NoSelfUpdateTest) {
- tuc_params_.http_response =
- "<response><app><updatecheck status=\"ok\"><manifest><actions><action "
- "event=\"postinstall\" noupdate=\"true\"/></actions>"
- "</manifest></updatecheck></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-// Test that all the values in the response are parsed in a normal update
-// response_.
-TEST_F(OmahaRequestActionTest, ValidUpdateTest) {
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(fake_update_response_.version, response_.version);
- EXPECT_EQ(fake_update_response_.GetPayloadUrl(),
- response_.packages[0].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.more_info_url, response_.more_info_url);
- EXPECT_EQ(fake_update_response_.hash, response_.packages[0].hash);
- EXPECT_EQ(fake_update_response_.size, response_.packages[0].size);
- EXPECT_EQ(fake_update_response_.fp, response_.packages[0].fp);
- EXPECT_EQ(true, response_.packages[0].is_delta);
- EXPECT_EQ(fake_update_response_.prompt == "true", response_.prompt);
- EXPECT_EQ(fake_update_response_.deadline, response_.deadline);
- EXPECT_FALSE(response_.powerwash_required);
- // Omaha cohort attributes are not set in the response, so they should not be
- // persisted.
- EXPECT_FALSE(fake_prefs_->Exists(kPrefsOmahaCohort));
- EXPECT_FALSE(fake_prefs_->Exists(kPrefsOmahaCohortHint));
- EXPECT_FALSE(fake_prefs_->Exists(kPrefsOmahaCohortName));
-}
-
-TEST_F(OmahaRequestActionTest, MultiPackageUpdateTest) {
- fake_update_response_.multi_package = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(fake_update_response_.version, response_.version);
- EXPECT_EQ(fake_update_response_.GetPayloadUrl(),
- response_.packages[0].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.codebase + "package2",
- response_.packages[1].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.hash, response_.packages[0].hash);
- EXPECT_EQ(fake_update_response_.size, response_.packages[0].size);
- EXPECT_EQ(fake_update_response_.fp, response_.packages[0].fp);
- EXPECT_EQ(true, response_.packages[0].is_delta);
- EXPECT_EQ(11u, response_.packages[0].metadata_size);
- ASSERT_EQ(2u, response_.packages.size());
- EXPECT_EQ(string("hash2"), response_.packages[1].hash);
- EXPECT_EQ(222u, response_.packages[1].size);
- EXPECT_EQ(fake_update_response_.fp2, response_.packages[1].fp);
- EXPECT_EQ(22u, response_.packages[1].metadata_size);
- EXPECT_EQ(false, response_.packages[1].is_delta);
-}
-
-TEST_F(OmahaRequestActionTest, MultiAppUpdateTest) {
- fake_update_response_.multi_app = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(fake_update_response_.version, response_.version);
- EXPECT_EQ(fake_update_response_.GetPayloadUrl(),
- response_.packages[0].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.codebase2 + "package3",
- response_.packages[1].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.hash, response_.packages[0].hash);
- EXPECT_EQ(fake_update_response_.size, response_.packages[0].size);
- EXPECT_EQ(fake_update_response_.fp, response_.packages[0].fp);
- EXPECT_EQ(11u, response_.packages[0].metadata_size);
- EXPECT_EQ(true, response_.packages[0].is_delta);
- ASSERT_EQ(2u, response_.packages.size());
- EXPECT_EQ(string("hash3"), response_.packages[1].hash);
- EXPECT_EQ(333u, response_.packages[1].size);
- EXPECT_EQ(fake_update_response_.fp2, response_.packages[1].fp);
- EXPECT_EQ(33u, response_.packages[1].metadata_size);
- EXPECT_EQ(false, response_.packages[1].is_delta);
-}
-
-TEST_F(OmahaRequestActionTest, MultiAppPartialUpdateTest) {
- fake_update_response_.multi_app = true;
- fake_update_response_.multi_app_self_update = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(fake_update_response_.version, response_.version);
- EXPECT_EQ(fake_update_response_.GetPayloadUrl(),
- response_.packages[0].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.hash, response_.packages[0].hash);
- EXPECT_EQ(fake_update_response_.size, response_.packages[0].size);
- EXPECT_EQ(fake_update_response_.fp, response_.packages[0].fp);
- EXPECT_EQ(11u, response_.packages[0].metadata_size);
- ASSERT_EQ(2u, response_.packages.size());
- EXPECT_EQ(string("hash3"), response_.packages[1].hash);
- EXPECT_EQ(333u, response_.packages[1].size);
- EXPECT_EQ(fake_update_response_.fp2, response_.packages[1].fp);
- EXPECT_EQ(33u, response_.packages[1].metadata_size);
- EXPECT_EQ(true, response_.packages[1].is_delta);
-}
-
-TEST_F(OmahaRequestActionTest, MultiAppMultiPackageUpdateTest) {
- fake_update_response_.multi_app = true;
- fake_update_response_.multi_package = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(fake_update_response_.version, response_.version);
- EXPECT_EQ(fake_update_response_.GetPayloadUrl(),
- response_.packages[0].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.codebase + "package2",
- response_.packages[1].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.codebase2 + "package3",
- response_.packages[2].payload_urls[0]);
- EXPECT_EQ(fake_update_response_.hash, response_.packages[0].hash);
- EXPECT_EQ(fake_update_response_.size, response_.packages[0].size);
- EXPECT_EQ(fake_update_response_.fp, response_.packages[0].fp);
- EXPECT_EQ(11u, response_.packages[0].metadata_size);
- EXPECT_EQ(true, response_.packages[0].is_delta);
- ASSERT_EQ(3u, response_.packages.size());
- EXPECT_EQ(string("hash2"), response_.packages[1].hash);
- EXPECT_EQ(222u, response_.packages[1].size);
- EXPECT_EQ(fake_update_response_.fp2, response_.packages[1].fp);
- EXPECT_EQ(22u, response_.packages[1].metadata_size);
- EXPECT_EQ(false, response_.packages[1].is_delta);
- EXPECT_EQ(string("hash3"), response_.packages[2].hash);
- EXPECT_EQ(333u, response_.packages[2].size);
- EXPECT_EQ(fake_update_response_.fp2, response_.packages[2].fp);
- EXPECT_EQ(33u, response_.packages[2].metadata_size);
- EXPECT_EQ(false, response_.packages[2].is_delta);
-}
-
-TEST_F(OmahaRequestActionTest, PowerwashTest) {
- fake_update_response_.powerwash = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_TRUE(response_.powerwash_required);
-}
-
-TEST_F(OmahaRequestActionTest, ExtraHeadersSentInteractiveTest) {
- request_params_.set_interactive(true);
- test_http_fetcher_headers_ = true;
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ExtraHeadersSentNoInteractiveTest) {
- request_params_.set_interactive(false);
- test_http_fetcher_headers_ = true;
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ValidUpdateBlockedByConnection) {
- // Set up a connection manager that doesn't allow a valid update over
- // the current ethernet connection.
- MockConnectionManager mock_cm;
- FakeSystemState::Get()->set_connection_manager(&mock_cm);
-
- EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
- .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kEthernet),
- SetArgPointee<1>(ConnectionTethering::kUnknown),
- Return(true)));
- EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kEthernet, _))
- .WillRepeatedly(Return(false));
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kIgnored;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ValidUpdateOverCellularAllowedByDevicePolicy) {
- // This test tests that update over cellular is allowed as device policy
- // says yes.
- MockConnectionManager mock_cm;
- FakeSystemState::Get()->set_connection_manager(&mock_cm);
-
- EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
- .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
- SetArgPointee<1>(ConnectionTethering::kUnknown),
- Return(true)));
- EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
- .WillRepeatedly(Return(true));
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ValidUpdateOverCellularBlockedByDevicePolicy) {
- // This test tests that update over cellular is blocked as device policy
- // says no.
- MockConnectionManager mock_cm;
- FakeSystemState::Get()->set_connection_manager(&mock_cm);
-
- EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
- .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
- SetArgPointee<1>(ConnectionTethering::kUnknown),
- Return(true)));
- EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
- .WillRepeatedly(Return(true));
- EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
- .WillRepeatedly(Return(false));
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kIgnored;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest,
- ValidUpdateOverCellularAllowedByUserPermissionTrue) {
- // This test tests that, when device policy is not set, update over cellular
- // is allowed as permission for update over cellular is set to true.
- MockConnectionManager mock_cm;
- fake_prefs_->SetBoolean(kPrefsUpdateOverCellularPermission, true);
- FakeSystemState::Get()->set_connection_manager(&mock_cm);
-
- EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
- .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
- SetArgPointee<1>(ConnectionTethering::kUnknown),
- Return(true)));
- EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
- .WillRepeatedly(Return(true));
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest,
- ValidUpdateOverCellularBlockedByUpdateTargetNotMatch) {
- // This test tests that, when device policy is not set and permission for
- // update over cellular is set to false or does not exist, update over
- // cellular is blocked as update target does not match the omaha response.
- MockConnectionManager mock_cm;
- // A version different from the version in omaha response.
- string diff_version = "99.99.99";
- // A size different from the size in omaha response.
- int64_t diff_size = 999;
-
- fake_prefs_->SetString(kPrefsUpdateOverCellularTargetVersion, diff_version);
- fake_prefs_->SetInt64(kPrefsUpdateOverCellularTargetSize, diff_size);
- // This test tests cellular (3G) being the only connection type being allowed.
- FakeSystemState::Get()->set_connection_manager(&mock_cm);
-
- EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
- .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
- SetArgPointee<1>(ConnectionTethering::kUnknown),
- Return(true)));
- EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
- .WillRepeatedly(Return(true));
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateIgnoredOverCellular;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kIgnored;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest,
- ValidUpdateOverCellularAllowedByUpdateTargetMatch) {
- // This test tests that, when device policy is not set and permission for
- // update over cellular is set to false or does not exist, update over
- // cellular is allowed as update target matches the omaha response.
- MockConnectionManager mock_cm;
- // A version same as the version in omaha response.
- string new_version = fake_update_response_.version;
- // A size same as the size in omaha response.
- int64_t new_size = fake_update_response_.size;
-
- fake_prefs_->SetString(kPrefsUpdateOverCellularTargetVersion, new_version);
- fake_prefs_->SetInt64(kPrefsUpdateOverCellularTargetSize, new_size);
- FakeSystemState::Get()->set_connection_manager(&mock_cm);
-
- EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
- .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
- SetArgPointee<1>(ConnectionTethering::kUnknown),
- Return(true)));
- EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
- .WillRepeatedly(Return(false));
- EXPECT_CALL(mock_cm, IsUpdateAllowedOver(ConnectionType::kCellular, _))
- .WillRepeatedly(Return(true));
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ValidUpdateBlockedByRollback) {
- string rollback_version = "1234.0.0";
- MockPayloadState mock_payload_state;
- FakeSystemState::Get()->set_payload_state(&mock_payload_state);
- fake_update_response_.version = rollback_version;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateIgnoredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kIgnored;
-
- EXPECT_CALL(mock_payload_state, GetRollbackVersion())
- .WillRepeatedly(Return(rollback_version));
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-// Verify that update checks called during OOBE will not try to download an
-// update if the response doesn't include the deadline field.
-TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBE) {
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kNonCriticalUpdateInOOBE;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- // TODO(senj): set better default value for metrics::checkresult in
- // OmahaRequestAction::ActionCompleted.
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-// Verify that the IsOOBEComplete() value is ignored when the OOBE flow is not
-// enabled.
-TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBEDisabled) {
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEEnabled(false);
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-// Verify that update checks called during OOBE will still try to download an
-// update if the response includes the deadline field.
-TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBEDeadlineSet) {
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-// Verify that update checks called during OOBE will not try to download an
-// update if a rollback happened, even when the response includes the deadline
-// field.
-TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesBeforeOOBERollback) {
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kNonCriticalUpdateInOOBE;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- EXPECT_CALL(*(FakeSystemState::Get()->mock_payload_state()),
- GetRollbackHappened())
- .WillOnce(Return(true));
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-// Verify that non-critical updates are skipped by reporting the
-// kNonCriticalUpdateInOOBE error code when attempted over cellular network -
-// i.e. when the update would need user permission. Note that reporting
-// kOmahaUpdateIgnoredOverCellular error in this case might cause undesired UX
-// in OOBE (warning the user about an update that will be skipped).
-TEST_F(OmahaRequestActionTest, SkipNonCriticalUpdatesInOOBEOverCellular) {
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
-
- MockConnectionManager mock_cm;
- FakeSystemState::Get()->set_connection_manager(&mock_cm);
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kNonCriticalUpdateInOOBE;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- EXPECT_CALL(mock_cm, GetConnectionProperties(_, _))
- .WillRepeatedly(DoAll(SetArgPointee<0>(ConnectionType::kCellular),
- SetArgPointee<1>(ConnectionTethering::kUnknown),
- Return(true)));
- EXPECT_CALL(mock_cm, IsAllowedConnectionTypesForUpdateSet())
- .WillRepeatedly(Return(false));
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, WallClockBasedWaitAloneCausesScattering) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_update_check_count_wait_enabled(false);
- request_params_.set_waiting_period(TimeDelta::FromDays(2));
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateDeferredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kDeferring;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest,
- WallClockBasedWaitAloneCausesScatteringInteractive) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_update_check_count_wait_enabled(false);
- request_params_.set_waiting_period(TimeDelta::FromDays(2));
- request_params_.set_interactive(true);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- // Verify if we are interactive check we don't defer.
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, NoWallClockBasedWaitCausesNoScattering) {
- request_params_.set_wall_clock_based_wait_enabled(false);
- request_params_.set_waiting_period(TimeDelta::FromDays(2));
- request_params_.set_update_check_count_wait_enabled(true);
- request_params_.set_min_update_checks_needed(1);
- request_params_.set_max_update_checks_allowed(8);
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ZeroMaxDaysToScatterCausesNoScattering) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta::FromDays(2));
- request_params_.set_update_check_count_wait_enabled(true);
- request_params_.set_min_update_checks_needed(1);
- request_params_.set_max_update_checks_allowed(8);
- fake_update_response_.max_days_to_scatter = "0";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ZeroUpdateCheckCountCausesNoScattering) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta());
- request_params_.set_update_check_count_wait_enabled(true);
- request_params_.set_min_update_checks_needed(0);
- request_params_.set_max_update_checks_allowed(0);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- int64_t count;
- ASSERT_TRUE(fake_prefs_->GetInt64(kPrefsUpdateCheckCount, &count));
- ASSERT_EQ(count, 0);
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, NonZeroUpdateCheckCountCausesScattering) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta());
- request_params_.set_update_check_count_wait_enabled(true);
- request_params_.set_min_update_checks_needed(1);
- request_params_.set_max_update_checks_allowed(8);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateDeferredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kDeferring;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- int64_t count;
- ASSERT_TRUE(fake_prefs_->GetInt64(kPrefsUpdateCheckCount, &count));
- ASSERT_GT(count, 0);
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest,
- NonZeroUpdateCheckCountCausesScatteringInteractive) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta());
- request_params_.set_update_check_count_wait_enabled(true);
- request_params_.set_min_update_checks_needed(1);
- request_params_.set_max_update_checks_allowed(8);
- request_params_.set_interactive(true);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- // Verify if we are interactive check we don't defer.
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, ExistingUpdateCheckCountCausesScattering) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta());
- request_params_.set_update_check_count_wait_enabled(true);
- request_params_.set_min_update_checks_needed(1);
- request_params_.set_max_update_checks_allowed(8);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateDeferredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kDeferring;
-
- ASSERT_TRUE(fake_prefs_->SetInt64(kPrefsUpdateCheckCount, 5));
- ASSERT_FALSE(TestUpdateCheck());
-
- int64_t count;
- ASSERT_TRUE(fake_prefs_->GetInt64(kPrefsUpdateCheckCount, &count));
- // |count| remains the same, as the decrementing happens in update_attempter
- // which this test doesn't exercise.
- ASSERT_EQ(count, 5);
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest,
- ExistingUpdateCheckCountCausesScatteringInteractive) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta());
- request_params_.set_update_check_count_wait_enabled(true);
- request_params_.set_min_update_checks_needed(1);
- request_params_.set_max_update_checks_allowed(8);
- request_params_.set_interactive(true);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(fake_prefs_->SetInt64(kPrefsUpdateCheckCount, 5));
-
- // Verify if we are interactive check we don't defer.
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, StagingTurnedOnCausesScattering) {
- // If staging is on, the value for max days to scatter should be ignored, and
- // staging's scatter value should be used.
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta::FromDays(6));
- request_params_.set_update_check_count_wait_enabled(false);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(Time::Now());
-
- ASSERT_TRUE(fake_prefs_->SetInt64(kPrefsWallClockStagingWaitPeriod, 6));
- // This should not prevent scattering due to staging.
- fake_update_response_.max_days_to_scatter = "0";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateDeferredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kDeferring;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-
- // Interactive updates should not be affected.
- request_params_.set_interactive(true);
- tuc_params_.expected_code = ErrorCode::kSuccess;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUpdating;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, CohortsArePersisted) {
- fake_update_response_.include_cohorts = true;
- fake_update_response_.cohort = "s/154454/8479665";
- fake_update_response_.cohorthint = "please-put-me-on-beta";
- fake_update_response_.cohortname = "stable";
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
- fake_update_response_.dlc_app_update = true;
- fake_update_response_.include_dlc_cohorts = true;
- fake_update_response_.dlc_cohort = "s/154454/8479665/dlc";
- fake_update_response_.dlc_cohorthint = "please-put-me-on-beta-dlc";
- fake_update_response_.dlc_cohortname = "stable-dlc";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
-
- string value;
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohort, &value));
- EXPECT_EQ(fake_update_response_.cohort, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohortHint, &value));
- EXPECT_EQ(fake_update_response_.cohorthint, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohortName, &value));
- EXPECT_EQ(fake_update_response_.cohortname, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohort, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohortname, value);
-}
-
-TEST_F(OmahaRequestActionTest, CohortsAreUpdated) {
- EXPECT_TRUE(fake_prefs_->SetString(kPrefsOmahaCohort, "old_value"));
- EXPECT_TRUE(fake_prefs_->SetString(kPrefsOmahaCohortHint, "old_hint"));
- EXPECT_TRUE(fake_prefs_->SetString(kPrefsOmahaCohortName, "old_name"));
- const string dlc_cohort_key =
- fake_prefs_->CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort});
- const string dlc_cohort_hint_key = fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint});
- const string dlc_cohort_name_key = fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName});
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
- EXPECT_TRUE(fake_prefs_->SetString(dlc_cohort_key, "old_value_dlc"));
- EXPECT_TRUE(fake_prefs_->SetString(dlc_cohort_hint_key, "old_hint_dlc"));
- EXPECT_TRUE(fake_prefs_->SetString(dlc_cohort_name_key, "old_name_dlc"));
- fake_update_response_.include_cohorts = true;
- fake_update_response_.cohort = "s/154454/8479665";
- fake_update_response_.cohorthint = "please-put-me-on-beta";
- fake_update_response_.cohortname = "";
- fake_update_response_.dlc_app_update = true;
- fake_update_response_.include_dlc_cohorts = true;
- fake_update_response_.dlc_cohort = "s/154454/8479665/dlc";
- fake_update_response_.dlc_cohorthint = "please-put-me-on-beta-dlc";
- fake_update_response_.dlc_cohortname = "";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
-
- string value;
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohort, &value));
- EXPECT_EQ(fake_update_response_.cohort, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohortHint, &value));
- EXPECT_EQ(fake_update_response_.cohorthint, value);
-
- EXPECT_FALSE(fake_prefs_->GetString(kPrefsOmahaCohortName, &value));
-
- EXPECT_TRUE(fake_prefs_->GetString(dlc_cohort_key, &value));
- EXPECT_EQ(fake_update_response_.dlc_cohort, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(dlc_cohort_hint_key, &value));
- EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
-
- EXPECT_FALSE(fake_prefs_->GetString(dlc_cohort_name_key, &value));
-}
-
-TEST_F(OmahaRequestActionTest, CohortsAreNotModifiedWhenMissing) {
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- EXPECT_TRUE(fake_prefs_->SetString(kPrefsOmahaCohort, "old_value"));
- const string dlc_cohort_key =
- fake_prefs_->CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort});
- EXPECT_TRUE(fake_prefs_->SetString(dlc_cohort_key, "old_value_dlc"));
- ASSERT_TRUE(TestUpdateCheck());
-
- string value;
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohort, &value));
- EXPECT_EQ("old_value", value);
-
- EXPECT_FALSE(fake_prefs_->GetString(kPrefsOmahaCohortHint, &value));
- EXPECT_FALSE(fake_prefs_->GetString(kPrefsOmahaCohortName, &value));
-
- EXPECT_TRUE(fake_prefs_->GetString(dlc_cohort_key, &value));
- EXPECT_EQ("old_value_dlc", value);
-
- EXPECT_FALSE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint}),
- &value));
- EXPECT_FALSE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName}),
- &value));
-}
-
-TEST_F(OmahaRequestActionTest, CohortsArePersistedWhenNoUpdate) {
- fake_update_response_.include_cohorts = true;
- fake_update_response_.cohort = "s/154454/8479665";
- fake_update_response_.cohorthint = "please-put-me-on-beta";
- fake_update_response_.cohortname = "stable";
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- string value;
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohort, &value));
- EXPECT_EQ(fake_update_response_.cohort, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohortHint, &value));
- EXPECT_EQ(fake_update_response_.cohorthint, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohortName, &value));
- EXPECT_EQ(fake_update_response_.cohortname, value);
-}
-
-TEST_F(OmahaRequestActionTest, MultiAppCohortTest) {
- fake_update_response_.multi_app = true;
- fake_update_response_.include_cohorts = true;
- fake_update_response_.cohort = "s/154454/8479665";
- fake_update_response_.cohorthint = "please-put-me-on-beta";
- fake_update_response_.cohortname = "stable";
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}},
- {request_params_.GetDlcAppId(kDlcId2), {.name = kDlcId2}}});
- fake_update_response_.dlc_app_update = true;
- fake_update_response_.dlc_app_no_update = true;
- fake_update_response_.include_dlc_cohorts = true;
- fake_update_response_.dlc_cohort = "s/154454/8479665/dlc";
- fake_update_response_.dlc_cohorthint = "please-put-me-on-beta-dlc";
- fake_update_response_.dlc_cohortname = "stable-dlc";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
-
- string value;
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohort, &value));
- EXPECT_EQ(fake_update_response_.cohort, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohortHint, &value));
- EXPECT_EQ(fake_update_response_.cohorthint, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsOmahaCohortName, &value));
- EXPECT_EQ(fake_update_response_.cohortname, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey({kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohort}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohort, value);
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey({kDlcPrefsSubDir, kDlcId2, kPrefsOmahaCohort}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohort, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortHint}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId2, kPrefsOmahaCohortHint}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohorthint, value);
-
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId1, kPrefsOmahaCohortName}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohortname, value);
- EXPECT_TRUE(fake_prefs_->GetString(
- fake_prefs_->CreateSubKey(
- {kDlcPrefsSubDir, kDlcId2, kPrefsOmahaCohortName}),
- &value));
- EXPECT_EQ(fake_update_response_.dlc_cohortname, value);
-}
-
-TEST_F(OmahaRequestActionTest, NoOutputPipeTest) {
- const string http_response(fake_update_response_.GetNoUpdateResponse());
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
-
- auto action = std::make_unique<OmahaRequestAction>(
- nullptr,
- std::make_unique<MockHttpFetcher>(
- http_response.data(), http_response.size(), nullptr),
- false,
- "");
- ActionProcessor processor;
- processor.set_delegate(&delegate_);
- processor.EnqueueAction(std::move(action));
-
- loop.PostTask(base::Bind(
- [](ActionProcessor* processor) { processor->StartProcessing(); },
- base::Unretained(&processor)));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
- EXPECT_FALSE(processor.IsRunning());
-}
-
-TEST_F(OmahaRequestActionTest, InvalidXmlTest) {
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, EmptyResponseTest) {
- tuc_params_.expected_code = ErrorCode::kOmahaRequestEmptyResponseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, MissingStatusTest) {
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response protocol=\"3.0\">"
- "<daystart elapsed_seconds=\"100\"/>"
- "<app appid=\"foo\" status=\"ok\">"
- "<ping status=\"ok\"/>"
- "<updatecheck/></app></response>";
- tuc_params_.expected_code = ErrorCode::kOmahaResponseInvalid;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, InvalidStatusTest) {
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response protocol=\"3.0\">"
- "<daystart elapsed_seconds=\"100\"/>"
- "<app appid=\"foo\" status=\"ok\">"
- "<ping status=\"ok\"/>"
- "<updatecheck status=\"InvalidStatusTest\"/></app></response>";
- tuc_params_.expected_code = ErrorCode::kOmahaResponseInvalid;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, MissingNodesetTest) {
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response protocol=\"3.0\">"
- "<daystart elapsed_seconds=\"100\"/>"
- "<app appid=\"foo\" status=\"ok\">"
- "<ping status=\"ok\"/>"
- "</app></response>";
- tuc_params_.expected_code = ErrorCode::kOmahaResponseInvalid;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, MissingFieldTest) {
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response protocol=\"3.0\">"
- "<daystart elapsed_seconds=\"100\"/>"
- // the appid needs to match that in the request params
- "<app appid=\"" +
- fake_update_response_.app_id +
- "\" status=\"ok\">"
- "<updatecheck status=\"ok\">"
- "<urls><url codebase=\"http://missing/field/test/\"/></urls>"
- "<manifest version=\"10.2.3.4\">"
- "<packages><package hash=\"not-used\" name=\"f\" "
- "size=\"587\" fp=\"3.789\" hash_sha256=\"lkq34j5345\"/></packages>"
- "<actions><action event=\"postinstall\" "
- "Prompt=\"false\" "
- "IsDeltaPayload=\"false\" "
- "sha256=\"not-used\" "
- "/></actions></manifest></updatecheck></app></response>";
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ("10.2.3.4", response_.version);
- EXPECT_EQ("http://missing/field/test/f",
- response_.packages[0].payload_urls[0]);
- EXPECT_EQ("", response_.more_info_url);
- EXPECT_EQ("lkq34j5345", response_.packages[0].hash);
- EXPECT_EQ(string("3.789"), response_.packages[0].fp);
- EXPECT_EQ(587u, response_.packages[0].size);
- EXPECT_FALSE(response_.prompt);
- EXPECT_TRUE(response_.deadline.empty());
-}
-
-namespace {
-class TerminateEarlyTestProcessorDelegate : public ActionProcessorDelegate {
- public:
- void ProcessingStopped(const ActionProcessor* processor) {
- brillo::MessageLoop::current()->BreakLoop();
- }
-};
-
-void TerminateTransferTestStarter(ActionProcessor* processor) {
- processor->StartProcessing();
- CHECK(processor->IsRunning());
- processor->StopProcessing();
-}
-} // namespace
-
-TEST_F(OmahaRequestActionTest, TerminateTransferTest) {
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
-
- string http_response("doesn't matter");
- auto action = std::make_unique<OmahaRequestAction>(
- nullptr,
- std::make_unique<MockHttpFetcher>(
- http_response.data(), http_response.size(), nullptr),
- false,
- "");
- TerminateEarlyTestProcessorDelegate delegate;
- ActionProcessor processor;
- processor.set_delegate(&delegate);
- processor.EnqueueAction(std::move(action));
-
- loop.PostTask(base::Bind(&TerminateTransferTestStarter, &processor));
- loop.Run();
- EXPECT_FALSE(loop.PendingTasks());
-}
-
-TEST_F(OmahaRequestActionTest, XmlEncodeIsUsedForParams) {
- // Make sure XML Encode is being called on the params.
- request_params_.set_os_sp("testtheservice_pack>");
- request_params_.set_os_board("x86 generic<id");
- request_params_.set_current_channel("unittest_track&lt;");
- request_params_.set_target_channel("unittest_track&lt;");
- request_params_.set_lts_tag("unittest_hint&lt;");
- request_params_.set_hwid("<OEM MODEL>");
- fake_prefs_->SetString(kPrefsOmahaCohort, "evil\nstring");
- fake_prefs_->SetString(kPrefsOmahaCohortHint, "evil&string\\");
- fake_prefs_->SetString(
- kPrefsOmahaCohortName,
- base::JoinString(vector<string>(100, "My spoon is too big."), " "));
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_NE(string::npos, post_str_.find("testtheservice_pack&gt;"));
- EXPECT_EQ(string::npos, post_str_.find("testtheservice_pack>"));
- EXPECT_NE(string::npos, post_str_.find("x86 generic&lt;id"));
- EXPECT_EQ(string::npos, post_str_.find("x86 generic<id"));
- EXPECT_NE(string::npos, post_str_.find("unittest_track&amp;lt;"));
- EXPECT_EQ(string::npos, post_str_.find("unittest_track&lt;"));
- EXPECT_NE(string::npos, post_str_.find("unittest_hint&amp;lt;"));
- EXPECT_EQ(string::npos, post_str_.find("unittest_hint&lt;"));
- EXPECT_NE(string::npos, post_str_.find("&lt;OEM MODEL&gt;"));
- EXPECT_EQ(string::npos, post_str_.find("<OEM MODEL>"));
- EXPECT_NE(string::npos, post_str_.find("cohort=\"evil\nstring\""));
- EXPECT_EQ(string::npos, post_str_.find("cohorthint=\"evil&string\\\""));
- EXPECT_NE(string::npos, post_str_.find("cohorthint=\"evil&amp;string\\\""));
- // Values from Prefs that are too big are removed from the XML instead of
- // encoded.
- EXPECT_EQ(string::npos, post_str_.find("cohortname="));
-}
-
-TEST_F(OmahaRequestActionTest, XmlDecodeTest) {
- fake_update_response_.deadline = "&lt;20110101";
- fake_update_response_.more_info_url = "testthe&lt;url";
- fake_update_response_.codebase = "testthe&amp;codebase/";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_EQ("testthe<url", response_.more_info_url);
- EXPECT_EQ("testthe&codebase/file.signed",
- response_.packages[0].payload_urls[0]);
- EXPECT_EQ("<20110101", response_.deadline);
-}
-
-TEST_F(OmahaRequestActionTest, ParseIntTest) {
- // overflows int32_t:
- fake_update_response_.size = 123123123123123ull;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_EQ(fake_update_response_.size, response_.packages[0].size);
-}
-
-TEST_F(OmahaRequestActionTest, FormatUpdateCheckOutputTest) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- EXPECT_CALL(prefs, GetString(kPrefsPreviousVersion, _))
- .WillOnce(DoAll(SetArgPointee<1>(string("")), Return(true)));
- // An existing but empty previous version means that we didn't reboot to a new
- // update, therefore, no need to update the previous version.
- EXPECT_CALL(prefs, SetString(kPrefsPreviousVersion, _)).Times(0);
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_NE(
- post_str_.find(" <ping active=\"1\" a=\"-1\" r=\"-1\"></ping>\n"
- " <updatecheck></updatecheck>\n"),
- string::npos);
- EXPECT_NE(post_str_.find("hardware_class=\"OEM MODEL 09235 7471\""),
- string::npos);
- // No <event> tag should be sent if we didn't reboot to an update.
- EXPECT_EQ(post_str_.find("<event"), string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, FormatSuccessEventOutputTest) {
- TestEvent(new OmahaEvent(OmahaEvent::kTypeUpdateDownloadStarted),
- "invalid xml>");
-
- string expected_event = base::StringPrintf(
- " <event eventtype=\"%d\" eventresult=\"%d\"></event>\n",
- OmahaEvent::kTypeUpdateDownloadStarted,
- OmahaEvent::kResultSuccess);
- EXPECT_NE(post_str_.find(expected_event), string::npos);
- EXPECT_EQ(post_str_.find("ping"), string::npos);
- EXPECT_EQ(post_str_.find("updatecheck"), string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, FormatErrorEventOutputTest) {
- TestEvent(new OmahaEvent(OmahaEvent::kTypeDownloadComplete,
- OmahaEvent::kResultError,
- ErrorCode::kError),
- "invalid xml>");
-
- string expected_event = base::StringPrintf(
- " <event eventtype=\"%d\" eventresult=\"%d\" "
- "errorcode=\"%d\"></event>\n",
- OmahaEvent::kTypeDownloadComplete,
- OmahaEvent::kResultError,
- static_cast<int>(ErrorCode::kError));
- EXPECT_NE(post_str_.find(expected_event), string::npos);
- EXPECT_EQ(post_str_.find("updatecheck"), string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, IsEventTest) {
- string http_response("doesn't matter");
- OmahaRequestAction update_check_action(
- nullptr,
- std::make_unique<MockHttpFetcher>(
- http_response.data(), http_response.size(), nullptr),
- false,
- "");
- EXPECT_FALSE(update_check_action.IsEvent());
-
- OmahaRequestAction event_action(
- new OmahaEvent(OmahaEvent::kTypeUpdateComplete),
- std::make_unique<MockHttpFetcher>(
- http_response.data(), http_response.size(), nullptr),
- false,
- "");
- EXPECT_TRUE(event_action.IsEvent());
-}
-
-TEST_F(OmahaRequestActionTest, FormatDeltaOkayOutputTest) {
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- for (int i = 0; i < 2; i++) {
- bool delta_okay = i == 1;
- const char* delta_okay_str = delta_okay ? "true" : "false";
- request_params_.set_delta_okay(delta_okay);
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_NE(post_str_.find(
- base::StringPrintf(" delta_okay=\"%s\"", delta_okay_str)),
- string::npos)
- << "i = " << i;
- }
-}
-
-TEST_F(OmahaRequestActionTest, FormatInteractiveOutputTest) {
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- for (int i = 0; i < 2; i++) {
- bool interactive = i == 1;
- const char* interactive_str = interactive ? "ondemandupdate" : "scheduler";
- request_params_.set_interactive(interactive);
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_NE(post_str_.find(
- base::StringPrintf("installsource=\"%s\"", interactive_str)),
- string::npos)
- << "i = " << i;
- }
-}
-
-TEST_F(OmahaRequestActionTest, FormatTargetVersionPrefixOutputTest) {
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- for (int i = 0; i < 2; i++) {
- bool target_version_set = i == 1;
- const char* target_version_prefix = target_version_set ? "10032." : "";
- request_params_.set_target_version_prefix(target_version_prefix);
-
- ASSERT_FALSE(TestUpdateCheck());
- if (target_version_set) {
- EXPECT_NE(post_str_.find("<updatecheck targetversionprefix=\"10032.\">"),
- string::npos)
- << "i = " << i;
- } else {
- EXPECT_EQ(post_str_.find("targetversionprefix"), string::npos)
- << "i = " << i;
- }
- }
-}
-
-TEST_F(OmahaRequestActionTest, FormatRollbackAllowedOutputTest) {
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- for (int i = 0; i < 4; i++) {
- bool rollback_allowed = i / 2 == 0;
- bool target_version_set = i % 2 == 0;
- request_params_.set_target_version_prefix(target_version_set ? "10032."
- : "");
- request_params_.set_rollback_allowed(rollback_allowed);
-
- ASSERT_FALSE(TestUpdateCheck());
- if (rollback_allowed && target_version_set) {
- EXPECT_NE(post_str_.find("rollback_allowed=\"true\""), string::npos)
- << "i = " << i;
- } else {
- EXPECT_EQ(post_str_.find("rollback_allowed"), string::npos)
- << "i = " << i;
- }
- }
-}
-
-TEST_F(OmahaRequestActionTest, OmahaEventTest) {
- OmahaEvent default_event;
- EXPECT_EQ(OmahaEvent::kTypeUnknown, default_event.type);
- EXPECT_EQ(OmahaEvent::kResultError, default_event.result);
- EXPECT_EQ(ErrorCode::kError, default_event.error_code);
-
- OmahaEvent success_event(OmahaEvent::kTypeUpdateDownloadStarted);
- EXPECT_EQ(OmahaEvent::kTypeUpdateDownloadStarted, success_event.type);
- EXPECT_EQ(OmahaEvent::kResultSuccess, success_event.result);
- EXPECT_EQ(ErrorCode::kSuccess, success_event.error_code);
-
- OmahaEvent error_event(OmahaEvent::kTypeUpdateDownloadFinished,
- OmahaEvent::kResultError,
- ErrorCode::kError);
- EXPECT_EQ(OmahaEvent::kTypeUpdateDownloadFinished, error_event.type);
- EXPECT_EQ(OmahaEvent::kResultError, error_event.result);
- EXPECT_EQ(ErrorCode::kError, error_event.error_code);
-}
-
-TEST_F(OmahaRequestActionTest, DeviceQuickFixBuildTokenIsSetTest) {
- // If DeviceQuickFixBuildToken value is set it takes precedence over pref
- // value.
- constexpr char autoupdate_token[] = "autoupdate_token>";
- constexpr char xml_encoded_autoupdate_token[] = "autoupdate_token&gt;";
- constexpr char omaha_cohort_hint[] = "cohort_hint";
-
- 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_autoupdate_token(autoupdate_token);
- fake_prefs_->SetString(kPrefsOmahaCohortHint, omaha_cohort_hint);
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_NE(string::npos,
- post_str_.find("cohorthint=\"" +
- string(xml_encoded_autoupdate_token) + "\""));
- EXPECT_EQ(string::npos, post_str_.find(autoupdate_token));
- EXPECT_EQ(string::npos, post_str_.find(omaha_cohort_hint));
-}
-
-TEST_F(OmahaRequestActionTest, DeviceQuickFixBuildTokenIsNotSetTest) {
- // If DeviceQuickFixBuildToken is not set, pref value will be provided in
- // cohorthint attribute.
- constexpr char omaha_cohort_hint[] = "evil_string>";
- constexpr char xml_encoded_cohort_hint[] = "evil_string&gt;";
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
- fake_prefs_->SetString(kPrefsOmahaCohortHint, omaha_cohort_hint);
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_NE(
- string::npos,
- post_str_.find("cohorthint=\"" + string(xml_encoded_cohort_hint) + "\""));
- 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&gt;\""));
-}
-
-void OmahaRequestActionTest::PingTest(bool ping_only) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(kPrefsMetricsCheckLastReportingTime, _))
- .Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- // Add a few hours to the day difference to test no rounding, etc.
- int64_t five_days_ago =
- (Time::Now() - TimeDelta::FromHours(5 * 24 + 13)).ToInternalValue();
- int64_t six_days_ago =
- (Time::Now() - TimeDelta::FromHours(6 * 24 + 11)).ToInternalValue();
- EXPECT_CALL(prefs, GetInt64(kPrefsInstallDateDays, _))
- .WillOnce(DoAll(SetArgPointee<1>(0), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(six_days_ago), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(five_days_ago), Return(true)));
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.ping_only = ping_only;
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_NE(post_str_.find("<ping active=\"1\" a=\"6\" r=\"5\"></ping>"),
- string::npos);
- if (ping_only) {
- EXPECT_EQ(post_str_.find("updatecheck"), string::npos);
- EXPECT_EQ(post_str_.find("previousversion"), string::npos);
- } else {
- EXPECT_NE(post_str_.find("updatecheck"), string::npos);
- EXPECT_NE(post_str_.find("previousversion"), string::npos);
- }
-}
-
-TEST_F(OmahaRequestActionTest, PingTestSendOnlyAPing) {
- PingTest(true /* ping_only */);
-}
-
-TEST_F(OmahaRequestActionTest, PingTestSendAlsoAnUpdateCheck) {
- PingTest(false /* ping_only */);
-}
-
-TEST_F(OmahaRequestActionTest, ActivePingTest) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(kPrefsMetricsCheckLastReportingTime, _))
- .Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- int64_t three_days_ago =
- (Time::Now() - TimeDelta::FromHours(3 * 24 + 12)).ToInternalValue();
- int64_t now = Time::Now().ToInternalValue();
- EXPECT_CALL(prefs, GetInt64(kPrefsInstallDateDays, _))
- .WillOnce(DoAll(SetArgPointee<1>(0), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(three_days_ago), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(now), Return(true)));
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_NE(post_str_.find("<ping active=\"1\" a=\"3\"></ping>"), string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, RollCallPingTest) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(kPrefsMetricsCheckLastReportingTime, _))
- .Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- int64_t four_days_ago =
- (Time::Now() - TimeDelta::FromHours(4 * 24)).ToInternalValue();
- int64_t now = Time::Now().ToInternalValue();
- EXPECT_CALL(prefs, GetInt64(kPrefsInstallDateDays, _))
- .WillOnce(DoAll(SetArgPointee<1>(0), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(now), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(four_days_ago), Return(true)));
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_NE(post_str_.find("<ping active=\"1\" r=\"4\"></ping>\n"),
- string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, NoPingTest) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(kPrefsMetricsCheckLastReportingTime, _))
- .Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- int64_t one_hour_ago =
- (Time::Now() - TimeDelta::FromHours(1)).ToInternalValue();
- EXPECT_CALL(prefs, GetInt64(kPrefsInstallDateDays, _))
- .WillOnce(DoAll(SetArgPointee<1>(0), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(one_hour_ago), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(one_hour_ago), Return(true)));
- // LastActivePingDay and PrefsLastRollCallPingDay are set even if we didn't
- // send a ping.
- EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(Return(true));
- EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(Return(true));
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_EQ(post_str_.find("ping"), string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, IgnoreEmptyPingTest) {
- // This test ensures that we ignore empty ping only requests.
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- int64_t now = Time::Now().ToInternalValue();
- EXPECT_CALL(prefs, GetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(now), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(now), Return(true)));
- EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _)).Times(0);
- EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _)).Times(0);
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.ping_only = true;
- tuc_params_.expected_check_result = metrics::CheckResult::kUnset;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(post_str_.empty());
-}
-
-TEST_F(OmahaRequestActionTest, BackInTimePingTest) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(kPrefsMetricsCheckLastReportingTime, _))
- .Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- int64_t future =
- (Time::Now() + TimeDelta::FromHours(3 * 24 + 4)).ToInternalValue();
- EXPECT_CALL(prefs, GetInt64(kPrefsInstallDateDays, _))
- .WillOnce(DoAll(SetArgPointee<1>(0), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(future), Return(true)));
- EXPECT_CALL(prefs, GetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(DoAll(SetArgPointee<1>(future), Return(true)));
- EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _))
- .WillOnce(Return(true));
- EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _))
- .WillOnce(Return(true));
-
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><daystart elapsed_seconds=\"100\"/>"
- "<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
- "<updatecheck status=\"noupdate\"/></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_EQ(post_str_.find("ping"), string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, LastPingDayUpdateTest) {
- // This test checks that the action updates the last ping day to now
- // minus 200 seconds with a slack of 5 seconds. Therefore, the test
- // may fail if it runs for longer than 5 seconds. It shouldn't run
- // that long though.
- int64_t midnight =
- (Time::Now() - TimeDelta::FromSeconds(200)).ToInternalValue();
- int64_t midnight_slack =
- (Time::Now() - TimeDelta::FromSeconds(195)).ToInternalValue();
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(prefs,
- SetInt64(kPrefsLastActivePingDay,
- AllOf(Ge(midnight), Le(midnight_slack))))
- .WillOnce(Return(true));
- EXPECT_CALL(prefs,
- SetInt64(kPrefsLastRollCallPingDay,
- AllOf(Ge(midnight), Le(midnight_slack))))
- .WillOnce(Return(true));
-
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><daystart elapsed_seconds=\"200\"/>"
- "<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
- "<updatecheck status=\"noupdate\"/></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-}
-
-TEST_F(OmahaRequestActionTest, NoElapsedSecondsTest) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _)).Times(0);
- EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _)).Times(0);
-
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><daystart blah=\"200\"/>"
- "<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
- "<updatecheck status=\"noupdate\"/></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-}
-
-TEST_F(OmahaRequestActionTest, BadElapsedSecondsTest) {
- NiceMock<MockPrefs> prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(prefs, GetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(prefs, SetInt64(kPrefsLastActivePingDay, _)).Times(0);
- EXPECT_CALL(prefs, SetInt64(kPrefsLastRollCallPingDay, _)).Times(0);
-
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><daystart elapsed_seconds=\"x\"/>"
- "<app appid=\"foo\" status=\"ok\"><ping status=\"ok\"/>"
- "<updatecheck status=\"noupdate\"/></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-}
-
-TEST_F(OmahaRequestActionTest, NoUniqueIDTest) {
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_EQ(post_str_.find("machineid="), string::npos);
- EXPECT_EQ(post_str_.find("userid="), string::npos);
-}
-
-TEST_F(OmahaRequestActionTest, NetworkFailureTest) {
- const int http_error_code =
- static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + 501;
- tuc_params_.fail_http_response_code = 501;
- tuc_params_.expected_code = static_cast<ErrorCode>(http_error_code);
- tuc_params_.expected_check_result = metrics::CheckResult::kDownloadError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
- tuc_params_.expected_download_error_code =
- static_cast<metrics::DownloadErrorCode>(501);
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, NetworkFailureBadHTTPCodeTest) {
- const int http_error_code =
- static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + 999;
-
- tuc_params_.fail_http_response_code = 1500;
- tuc_params_.expected_code = static_cast<ErrorCode>(http_error_code);
- tuc_params_.expected_check_result = metrics::CheckResult::kDownloadError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
- tuc_params_.expected_download_error_code =
- metrics::DownloadErrorCode::kHttpStatusOther;
-
- ASSERT_FALSE(TestUpdateCheck());
- EXPECT_FALSE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, TestUpdateFirstSeenAtGetsPersistedFirstTime) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta().FromDays(1));
- request_params_.set_update_check_count_wait_enabled(false);
-
- Time arbitrary_date;
- ASSERT_TRUE(Time::FromString("6/4/1989", &arbitrary_date));
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(arbitrary_date);
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_code = ErrorCode::kOmahaUpdateDeferredPerPolicy;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kDeferring;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- int64_t timestamp = 0;
- ASSERT_TRUE(fake_prefs_->GetInt64(kPrefsUpdateFirstSeenAt, &timestamp));
- EXPECT_EQ(arbitrary_date.ToInternalValue(), timestamp);
- EXPECT_FALSE(response_.update_exists);
-
- // Verify if we are interactive check we don't defer.
- request_params_.set_interactive(true);
- tuc_params_.expected_code = ErrorCode::kSuccess;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUpdating;
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, TestUpdateFirstSeenAtGetsUsedIfAlreadyPresent) {
- request_params_.set_wall_clock_based_wait_enabled(true);
- request_params_.set_waiting_period(TimeDelta().FromDays(1));
- request_params_.set_update_check_count_wait_enabled(false);
-
- Time t1, t2;
- ASSERT_TRUE(Time::FromString("1/1/2012", &t1));
- ASSERT_TRUE(Time::FromString("1/3/2012", &t2));
- ASSERT_TRUE(
- fake_prefs_->SetInt64(kPrefsUpdateFirstSeenAt, t1.ToInternalValue()));
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(t2);
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-
- // Make sure the timestamp t1 is unchanged showing that it was reused.
- int64_t timestamp = 0;
- ASSERT_TRUE(fake_prefs_->GetInt64(kPrefsUpdateFirstSeenAt, &timestamp));
- ASSERT_TRUE(timestamp == t1.ToInternalValue());
-}
-
-TEST_F(OmahaRequestActionTest, TestChangingToMoreStableChannel) {
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- request_params_.set_root(tempdir.GetPath().value());
- request_params_.set_app_id("{22222222-2222-2222-2222-222222222222}");
- request_params_.set_app_version("1.2.3.4");
- request_params_.set_product_components("o.bundle=1");
- request_params_.set_current_channel("canary-channel");
- EXPECT_TRUE(
- request_params_.SetTargetChannel("stable-channel", true, nullptr));
- request_params_.UpdateDownloadChannel();
- EXPECT_TRUE(request_params_.ShouldPowerwash());
-
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_NE(string::npos,
- post_str_.find(
- "appid=\"{22222222-2222-2222-2222-222222222222}\" "
- "version=\"0.0.0.0\" from_version=\"1.2.3.4\" "
- "track=\"stable-channel\" from_track=\"canary-channel\" "));
- EXPECT_EQ(string::npos, post_str_.find("o.bundle"));
-}
-
-TEST_F(OmahaRequestActionTest, TestChangingToLessStableChannel) {
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- request_params_.set_root(tempdir.GetPath().value());
- request_params_.set_app_id("{11111111-1111-1111-1111-111111111111}");
- request_params_.set_app_version("5.6.7.8");
- request_params_.set_product_components("o.bundle=1");
- request_params_.set_current_channel("stable-channel");
- EXPECT_TRUE(
- request_params_.SetTargetChannel("canary-channel", false, nullptr));
- request_params_.UpdateDownloadChannel();
- EXPECT_FALSE(request_params_.ShouldPowerwash());
-
- tuc_params_.http_response = "invalid xml>";
- tuc_params_.expected_code = ErrorCode::kOmahaRequestXMLParseError;
- tuc_params_.expected_check_result = metrics::CheckResult::kParsingError;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_FALSE(TestUpdateCheck());
-
- EXPECT_NE(
- string::npos,
- post_str_.find("appid=\"{11111111-1111-1111-1111-111111111111}\" "
- "version=\"5.6.7.8\" "
- "track=\"canary-channel\" from_track=\"stable-channel\""));
- EXPECT_EQ(string::npos, post_str_.find("from_version"));
- EXPECT_NE(string::npos, post_str_.find("o.bundle.version=\"1\""));
-}
-
-// Checks that the initial ping with a=-1 r=-1 is not send when the device
-// was powerwashed.
-TEST_F(OmahaRequestActionTest, PingWhenPowerwashed) {
- fake_prefs_->SetString(kPrefsPreviousVersion, "");
-
- // Flag that the device was powerwashed in the past.
- FakeSystemState::Get()->fake_hardware()->SetPowerwashCount(1);
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- // We shouldn't send a ping in this case since powerwash > 0.
- EXPECT_EQ(string::npos, post_str_.find("<ping"));
-}
-
-// Checks that the initial ping with a=-1 r=-1 is not send when the device
-// first_active_omaha_ping_sent is set.
-TEST_F(OmahaRequestActionTest, PingWhenFirstActiveOmahaPingIsSent) {
- fake_prefs_->SetString(kPrefsPreviousVersion, "");
-
- // Flag that the device was not powerwashed in the past.
- FakeSystemState::Get()->fake_hardware()->SetPowerwashCount(0);
-
- // Flag that the device has sent first active ping in the past.
- FakeSystemState::Get()->fake_hardware()->SetFirstActiveOmahaPingSent();
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- // We shouldn't send a ping in this case since
- // first_active_omaha_ping_sent=true
- EXPECT_EQ(string::npos, post_str_.find("<ping"));
-}
-
-// Checks that the event 54 is sent on a reboot to a new update.
-TEST_F(OmahaRequestActionTest, RebootAfterUpdateEvent) {
- // Flag that the device was updated in a previous boot.
- fake_prefs_->SetString(kPrefsPreviousVersion, "1.2.3.4");
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- // An event 54 is included and has the right version.
- EXPECT_NE(
- string::npos,
- post_str_.find(base::StringPrintf("<event eventtype=\"%d\"",
- OmahaEvent::kTypeRebootedAfterUpdate)));
- EXPECT_NE(string::npos,
- post_str_.find("previousversion=\"1.2.3.4\"></event>"));
-
- // The previous version flag should have been removed.
- EXPECT_TRUE(fake_prefs_->Exists(kPrefsPreviousVersion));
- string prev_version;
- EXPECT_TRUE(fake_prefs_->GetString(kPrefsPreviousVersion, &prev_version));
- EXPECT_TRUE(prev_version.empty());
-}
-
-void OmahaRequestActionTest::P2PTest(bool initial_allow_p2p_for_downloading,
- bool initial_allow_p2p_for_sharing,
- bool omaha_disable_p2p_for_downloading,
- bool omaha_disable_p2p_for_sharing,
- bool payload_state_allow_p2p_attempt,
- bool expect_p2p_client_lookup,
- const string& p2p_client_result_url,
- bool expected_allow_p2p_for_downloading,
- bool expected_allow_p2p_for_sharing,
- const string& expected_p2p_url) {
- bool actual_allow_p2p_for_downloading = initial_allow_p2p_for_downloading;
- bool actual_allow_p2p_for_sharing = initial_allow_p2p_for_sharing;
- string actual_p2p_url;
-
- MockPayloadState mock_payload_state;
- FakeSystemState::Get()->set_payload_state(&mock_payload_state);
- EXPECT_CALL(mock_payload_state, P2PAttemptAllowed())
- .WillRepeatedly(Return(payload_state_allow_p2p_attempt));
- EXPECT_CALL(mock_payload_state, GetUsingP2PForDownloading())
- .WillRepeatedly(ReturnPointee(&actual_allow_p2p_for_downloading));
- EXPECT_CALL(mock_payload_state, GetUsingP2PForSharing())
- .WillRepeatedly(ReturnPointee(&actual_allow_p2p_for_sharing));
- EXPECT_CALL(mock_payload_state, SetUsingP2PForDownloading(_))
- .WillRepeatedly(SaveArg<0>(&actual_allow_p2p_for_downloading));
- EXPECT_CALL(mock_payload_state, SetUsingP2PForSharing(_))
- .WillRepeatedly(SaveArg<0>(&actual_allow_p2p_for_sharing));
- EXPECT_CALL(mock_payload_state, SetP2PUrl(_))
- .WillRepeatedly(SaveArg<0>(&actual_p2p_url));
-
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- mock_p2p_manager.fake().SetLookupUrlForFileResult(p2p_client_result_url);
-
- TimeDelta timeout = TimeDelta::FromSeconds(kMaxP2PNetworkWaitTimeSeconds);
- EXPECT_CALL(mock_p2p_manager, LookupUrlForFile(_, _, timeout, _))
- .Times(expect_p2p_client_lookup ? 1 : 0);
-
- fake_update_response_.disable_p2p_for_downloading =
- omaha_disable_p2p_for_downloading;
- fake_update_response_.disable_p2p_for_sharing = omaha_disable_p2p_for_sharing;
-
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kUpdateAvailable;
-
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-
- EXPECT_EQ(omaha_disable_p2p_for_downloading,
- response_.disable_p2p_for_downloading);
- EXPECT_EQ(omaha_disable_p2p_for_sharing, response_.disable_p2p_for_sharing);
-
- EXPECT_EQ(expected_allow_p2p_for_downloading,
- actual_allow_p2p_for_downloading);
- EXPECT_EQ(expected_allow_p2p_for_sharing, actual_allow_p2p_for_sharing);
- EXPECT_EQ(expected_p2p_url, actual_p2p_url);
-}
-
-TEST_F(OmahaRequestActionTest, P2PWithPeer) {
- P2PTest(true, // initial_allow_p2p_for_downloading
- true, // initial_allow_p2p_for_sharing
- false, // omaha_disable_p2p_for_downloading
- false, // omaha_disable_p2p_for_sharing
- true, // payload_state_allow_p2p_attempt
- true, // expect_p2p_client_lookup
- "http://1.3.5.7/p2p", // p2p_client_result_url
- true, // expected_allow_p2p_for_downloading
- true, // expected_allow_p2p_for_sharing
- "http://1.3.5.7/p2p"); // expected_p2p_url
-}
-
-TEST_F(OmahaRequestActionTest, P2PWithoutPeer) {
- P2PTest(true, // initial_allow_p2p_for_downloading
- true, // initial_allow_p2p_for_sharing
- false, // omaha_disable_p2p_for_downloading
- false, // omaha_disable_p2p_for_sharing
- true, // payload_state_allow_p2p_attempt
- true, // expect_p2p_client_lookup
- "", // p2p_client_result_url
- false, // expected_allow_p2p_for_downloading
- true, // expected_allow_p2p_for_sharing
- ""); // expected_p2p_url
-}
-
-TEST_F(OmahaRequestActionTest, P2PDownloadNotAllowed) {
- P2PTest(false, // initial_allow_p2p_for_downloading
- true, // initial_allow_p2p_for_sharing
- false, // omaha_disable_p2p_for_downloading
- false, // omaha_disable_p2p_for_sharing
- true, // payload_state_allow_p2p_attempt
- false, // expect_p2p_client_lookup
- "unset", // p2p_client_result_url
- false, // expected_allow_p2p_for_downloading
- true, // expected_allow_p2p_for_sharing
- ""); // expected_p2p_url
-}
-
-TEST_F(OmahaRequestActionTest, P2PWithPeerDownloadDisabledByOmaha) {
- P2PTest(true, // initial_allow_p2p_for_downloading
- true, // initial_allow_p2p_for_sharing
- true, // omaha_disable_p2p_for_downloading
- false, // omaha_disable_p2p_for_sharing
- true, // payload_state_allow_p2p_attempt
- false, // expect_p2p_client_lookup
- "unset", // p2p_client_result_url
- false, // expected_allow_p2p_for_downloading
- true, // expected_allow_p2p_for_sharing
- ""); // expected_p2p_url
-}
-
-TEST_F(OmahaRequestActionTest, P2PWithPeerSharingDisabledByOmaha) {
- P2PTest(true, // initial_allow_p2p_for_downloading
- true, // initial_allow_p2p_for_sharing
- false, // omaha_disable_p2p_for_downloading
- true, // omaha_disable_p2p_for_sharing
- true, // payload_state_allow_p2p_attempt
- true, // expect_p2p_client_lookup
- "http://1.3.5.7/p2p", // p2p_client_result_url
- true, // expected_allow_p2p_for_downloading
- false, // expected_allow_p2p_for_sharing
- "http://1.3.5.7/p2p"); // expected_p2p_url
-}
-
-TEST_F(OmahaRequestActionTest, P2PWithPeerBothDisabledByOmaha) {
- P2PTest(true, // initial_allow_p2p_for_downloading
- true, // initial_allow_p2p_for_sharing
- true, // omaha_disable_p2p_for_downloading
- true, // omaha_disable_p2p_for_sharing
- true, // payload_state_allow_p2p_attempt
- false, // expect_p2p_client_lookup
- "unset", // p2p_client_result_url
- false, // expected_allow_p2p_for_downloading
- false, // expected_allow_p2p_for_sharing
- ""); // expected_p2p_url
-}
-
-bool OmahaRequestActionTest::InstallDateParseHelper(const string& elapsed_days,
- OmahaResponse* response) {
- fake_update_response_.elapsed_days = elapsed_days;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- return TestUpdateCheck();
-}
-
-TEST_F(OmahaRequestActionTest, ParseInstallDateFromResponse) {
- // Simulate a successful update check that happens during OOBE. The
- // deadline in the response is needed to force the update attempt to
- // occur; responses without a deadline seen during OOBE will normally
- // return ErrorCode::kNonCriticalUpdateInOOBE.
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- fake_update_response_.deadline = "20101020";
-
- // Check that we parse elapsed_days in the Omaha Response correctly.
- // and that the kPrefsInstallDateDays value is written to.
- EXPECT_FALSE(fake_prefs_->Exists(kPrefsInstallDateDays));
- EXPECT_TRUE(InstallDateParseHelper("42", &response_));
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(42, response_.install_date_days);
- EXPECT_TRUE(fake_prefs_->Exists(kPrefsInstallDateDays));
- int64_t prefs_days;
- EXPECT_TRUE(fake_prefs_->GetInt64(kPrefsInstallDateDays, &prefs_days));
- EXPECT_EQ(prefs_days, 42);
-
- // If there already is a value set, we shouldn't do anything.
- EXPECT_TRUE(InstallDateParseHelper("7", &response_));
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(7, response_.install_date_days);
- EXPECT_TRUE(fake_prefs_->GetInt64(kPrefsInstallDateDays, &prefs_days));
- EXPECT_EQ(prefs_days, 42);
-
- // Note that elapsed_days is not necessarily divisible by 7 so check
- // that we round down correctly when populating kPrefsInstallDateDays.
- EXPECT_TRUE(fake_prefs_->Delete(kPrefsInstallDateDays));
- EXPECT_TRUE(InstallDateParseHelper("23", &response_));
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(23, response_.install_date_days);
- EXPECT_TRUE(fake_prefs_->GetInt64(kPrefsInstallDateDays, &prefs_days));
- EXPECT_EQ(prefs_days, 21);
-
- // Check that we correctly handle elapsed_days not being included in
- // the Omaha Response_.
- EXPECT_TRUE(InstallDateParseHelper("", &response_));
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(-1, response_.install_date_days);
-}
-
-// If there is no prefs and OOBE is not complete, we should not
-// report anything to Omaha.
-TEST_F(OmahaRequestActionTest, GetInstallDateWhenNoPrefsNorOOBE) {
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- EXPECT_EQ(OmahaRequestAction::GetInstallDate(), -1);
- EXPECT_FALSE(fake_prefs_->Exists(kPrefsInstallDateDays));
-}
-
-// If OOBE is complete and happened on a valid date (e.g. after Jan
-// 1 2007 0:00 PST), that date should be used and written to
-// prefs. However, first try with an invalid date and check we do
-// nothing.
-TEST_F(OmahaRequestActionTest, GetInstallDateWhenOOBECompletedWithInvalidDate) {
- Time oobe_date = Time::FromTimeT(42); // Dec 31, 1969 16:00:42 PST.
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(oobe_date);
- EXPECT_EQ(OmahaRequestAction::GetInstallDate(), -1);
- EXPECT_FALSE(fake_prefs_->Exists(kPrefsInstallDateDays));
-}
-
-// Then check with a valid date. The date Jan 20, 2007 0:00 PST
-// should yield an InstallDate of 14.
-TEST_F(OmahaRequestActionTest, GetInstallDateWhenOOBECompletedWithValidDate) {
- Time oobe_date = Time::FromTimeT(1169280000); // Jan 20, 2007 0:00 PST.
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(oobe_date);
- EXPECT_EQ(OmahaRequestAction::GetInstallDate(), 14);
- EXPECT_TRUE(fake_prefs_->Exists(kPrefsInstallDateDays));
-
- int64_t prefs_days;
- EXPECT_TRUE(fake_prefs_->GetInt64(kPrefsInstallDateDays, &prefs_days));
- EXPECT_EQ(prefs_days, 14);
-}
-
-// Now that we have a valid date in prefs, check that we keep using
-// that even if OOBE date reports something else. The date Jan 30,
-// 2007 0:00 PST should yield an InstallDate of 28... but since
-// there's a prefs file, we should still get 14.
-TEST_F(OmahaRequestActionTest, GetInstallDateWhenOOBECompletedDateChanges) {
- // Set a valid date in the prefs first.
- EXPECT_TRUE(fake_prefs_->SetInt64(kPrefsInstallDateDays, 14));
-
- Time oobe_date = Time::FromTimeT(1170144000); // Jan 30, 2007 0:00 PST.
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(oobe_date);
- EXPECT_EQ(OmahaRequestAction::GetInstallDate(), 14);
-
- int64_t prefs_days;
- EXPECT_TRUE(fake_prefs_->GetInt64(kPrefsInstallDateDays, &prefs_days));
- EXPECT_EQ(prefs_days, 14);
-
- // If we delete the prefs file, we should get 28 days.
- EXPECT_TRUE(fake_prefs_->Delete(kPrefsInstallDateDays));
- EXPECT_EQ(OmahaRequestAction::GetInstallDate(), 28);
- EXPECT_TRUE(fake_prefs_->GetInt64(kPrefsInstallDateDays, &prefs_days));
- EXPECT_EQ(prefs_days, 28);
-}
-
-// Verifies that a device with no device policy, and is not a consumer
-// device sets the max kernel key version to the current version.
-// ie. the same behavior as if rollback is enabled.
-TEST_F(OmahaRequestActionTest, NoPolicyEnterpriseDevicesSetMaxRollback) {
- FakeHardware* fake_hw = FakeSystemState::Get()->fake_hardware();
-
- // Setup and verify some initial default values for the kernel TPM
- // values that control verified boot and rollback.
- const int min_kernel_version = 4;
- fake_hw->SetMinKernelKeyVersion(min_kernel_version);
- fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
-
- EXPECT_CALL(
- *FakeSystemState::Get()->mock_metrics_reporter(),
- ReportKeyVersionMetrics(min_kernel_version, min_kernel_version, true))
- .Times(1);
-
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = 3;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-
- // Verify kernel_max_rollforward was set to the current minimum
- // kernel key version. This has the effect of freezing roll
- // forwards indefinitely. This will hold the rollback window
- // open until a future change will be able to move this forward
- // relative the configured window.
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(min_kernel_version, fake_hw->GetMaxKernelKeyRollforward());
-}
-
-// Verifies that a conmsumer device with no device policy sets the
-// max kernel key version to the current version. ie. the same
-// behavior as if rollback is enabled.
-TEST_F(OmahaRequestActionTest, NoPolicyConsumerDevicesSetMaxRollback) {
- FakeHardware* fake_hw = FakeSystemState::Get()->fake_hardware();
-
- // Setup and verify some initial default values for the kernel TPM
- // values that control verified boot and rollback.
- const int min_kernel_version = 3;
- fake_hw->SetMinKernelKeyVersion(min_kernel_version);
- fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
-
- EXPECT_CALL(
- *FakeSystemState::Get()->mock_metrics_reporter(),
- ReportKeyVersionMetrics(min_kernel_version, kRollforwardInfinity, true))
- .Times(1);
-
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = true;
- tuc_params_.rollback_allowed_milestones = 3;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-
- // Verify that with rollback disabled that kernel_max_rollforward
- // was set to logical infinity. This is the expected behavior for
- // consumer devices and matches the existing behavior prior to the
- // rollback features.
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
-}
-
-// Verifies that a device with rollback enabled sets kernel_max_rollforward
-// in the TPM to prevent roll forward.
-TEST_F(OmahaRequestActionTest, RollbackEnabledDevicesSetMaxRollback) {
- FakeHardware* fake_hw = FakeSystemState::Get()->fake_hardware();
-
- // Setup and verify some initial default values for the kernel TPM
- // values that control verified boot and rollback.
- const int allowed_milestones = 4;
- const int min_kernel_version = 3;
- fake_hw->SetMinKernelKeyVersion(min_kernel_version);
- fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
-
- EXPECT_CALL(
- *FakeSystemState::Get()->mock_metrics_reporter(),
- ReportKeyVersionMetrics(min_kernel_version, min_kernel_version, true))
- .Times(1);
-
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = allowed_milestones;
- tuc_params_.is_policy_loaded = true;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-
- // Verify that with rollback enabled that kernel_max_rollforward
- // was set to the current minimum kernel key version. This has
- // the effect of freezing roll forwards indefinitely. This will
- // hold the rollback window open until a future change will
- // be able to move this forward relative the configured window.
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(min_kernel_version, fake_hw->GetMaxKernelKeyRollforward());
-}
-
-// Verifies that a device with rollback disabled sets kernel_max_rollforward
-// in the TPM to logical infinity, to allow roll forward.
-TEST_F(OmahaRequestActionTest, RollbackDisabledDevicesSetMaxRollback) {
- FakeHardware* fake_hw = FakeSystemState::Get()->fake_hardware();
-
- // Setup and verify some initial default values for the kernel TPM
- // values that control verified boot and rollback.
- const int allowed_milestones = 0;
- const int min_kernel_version = 3;
- fake_hw->SetMinKernelKeyVersion(min_kernel_version);
- fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity);
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
-
- EXPECT_CALL(
- *FakeSystemState::Get()->mock_metrics_reporter(),
- ReportKeyVersionMetrics(min_kernel_version, kRollforwardInfinity, true))
- .Times(1);
-
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = allowed_milestones;
- tuc_params_.is_policy_loaded = true;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
-
- // Verify that with rollback disabled that kernel_max_rollforward
- // was set to logical infinity.
- EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion());
- EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward());
-}
-
-TEST_F(OmahaRequestActionTest, RollbackResponseParsedNoEntries) {
- fake_update_response_.rollback = true;
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = 4;
- tuc_params_.is_policy_loaded = true;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
- EXPECT_TRUE(response_.is_rollback);
-}
-
-TEST_F(OmahaRequestActionTest, RollbackResponseValidVersionsParsed) {
- fake_update_response_.rollback_firmware_version = "1.2";
- fake_update_response_.rollback_kernel_version = "3.4";
- fake_update_response_.rollback = true;
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = 4;
- tuc_params_.is_policy_loaded = true;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
- EXPECT_TRUE(response_.is_rollback);
- EXPECT_EQ(1, response_.rollback_key_version.firmware_key);
- EXPECT_EQ(2, response_.rollback_key_version.firmware);
- EXPECT_EQ(3, response_.rollback_key_version.kernel_key);
- EXPECT_EQ(4, response_.rollback_key_version.kernel);
-}
-
-TEST_F(OmahaRequestActionTest,
- TestUpdateFirstSeenAtPrefPersistedIfUpdateExists) {
- FakeClock fake_clock;
- Time now = Time::Now();
- fake_clock.SetWallclockTime(now);
- FakeSystemState::Get()->set_clock(&fake_clock);
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_TRUE(fake_prefs_->Exists(kPrefsUpdateFirstSeenAt));
-
- int64_t stored_first_seen_at_time;
- EXPECT_TRUE(fake_prefs_->GetInt64(kPrefsUpdateFirstSeenAt,
- &stored_first_seen_at_time));
- EXPECT_EQ(now.ToInternalValue(), stored_first_seen_at_time);
-}
-
-TEST_F(OmahaRequestActionTest,
- TestUpdateFirstSeenAtPrefNotPersistedIfUpdateFails) {
- FakeClock fake_clock;
- Time now = Time::Now();
- fake_clock.SetWallclockTime(now);
- FakeSystemState::Get()->set_clock(&fake_clock);
-
- tuc_params_.http_response = fake_update_response_.GetNoUpdateResponse();
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_FALSE(response_.update_exists);
- EXPECT_FALSE(fake_prefs_->Exists(kPrefsUpdateFirstSeenAt));
-}
-
-TEST_F(OmahaRequestActionTest, InstallTest) {
- request_params_.set_is_install(true);
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}},
- {request_params_.GetDlcAppId("dlc_no_1"), {.name = "dlc_no_1"}}});
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- for (const auto& it : request_params_.dlc_apps_params()) {
- EXPECT_NE(string::npos, post_str_.find("appid=\"" + it.first + "\""));
- }
- EXPECT_NE(string::npos,
- post_str_.find("appid=\"" + fake_update_response_.app_id + "\""));
-
- // Count number of updatecheck tag in response_.
- int updatecheck_count = 0;
- size_t pos = 0;
- while ((pos = post_str_.find("<updatecheck", pos)) != string::npos) {
- updatecheck_count++;
- pos++;
- }
- EXPECT_EQ(request_params_.dlc_apps_params().size(), updatecheck_count);
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, InstallMissingPlatformVersionTest) {
- fake_update_response_.multi_app_skip_updatecheck = true;
- fake_update_response_.multi_app_no_update = false;
- request_params_.set_is_install(true);
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}},
- {request_params_.GetDlcAppId("dlc_no_1"), {.name = "dlc_no_1"}}});
- request_params_.set_app_id(fake_update_response_.app_id_skip_updatecheck);
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
- EXPECT_EQ(fake_update_response_.version, response_.version);
-}
-
-TEST_F(OmahaRequestActionTest, UpdateWithDlcTest) {
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
- fake_update_response_.dlc_app_update = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_EQ(response_.packages.size(), 2u);
- // Two candidate URLs.
- EXPECT_EQ(response_.packages[1].payload_urls.size(), 2u);
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, UpdateWithPartiallyExcludedDlcTest) {
- 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.
- EXPECT_CALL(mock_excluder_, IsExcluded(_))
- .WillOnce(Return(true))
- .WillOnce(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_EQ(response_.packages.size(), 2u);
- // 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) {
- 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.
- EXPECT_CALL(mock_excluder_, IsExcluded(_))
- .WillOnce(Return(true))
- .WillOnce(Return(true));
- ASSERT_TRUE(TestUpdateCheck());
-
- 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) {
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId2), {.name = kDlcId2}}});
- fake_update_response_.dlc_app_no_update = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, UpdateWithDlcAndDeprecatedDlcTest) {
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}},
- {request_params_.GetDlcAppId(kDlcId2), {.name = kDlcId2}}});
- fake_update_response_.dlc_app_update = true;
- fake_update_response_.dlc_app_no_update = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
-
- EXPECT_TRUE(response_.update_exists);
-}
-
-TEST_F(OmahaRequestActionTest, PastRollbackVersionsNoEntries) {
- fake_update_response_.rollback = true;
- fake_update_response_.rollback_allowed_milestones = 4;
- request_params_.set_rollback_allowed_milestones(4);
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = 4;
- tuc_params_.is_policy_loaded = true;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
- EXPECT_TRUE(response_.is_rollback);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.firmware_key);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.firmware);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.kernel_key);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.kernel);
-}
-
-TEST_F(OmahaRequestActionTest, PastRollbackVersionsValidEntries) {
- request_params_.set_rollback_allowed_milestones(4);
- fake_update_response_.rollback = true;
- fake_update_response_.rollback_allowed_milestones = 4;
- fake_update_response_.rollback_firmware_version = "4.3";
- fake_update_response_.rollback_kernel_version = "2.1";
- fake_update_response_.past_rollback_key_version =
- std::make_pair("16.15", "14.13");
- fake_update_response_.deadline = "20101020";
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = 4;
- tuc_params_.is_policy_loaded = true;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
- EXPECT_TRUE(response_.is_rollback);
- EXPECT_EQ(16, response_.past_rollback_key_version.firmware_key);
- EXPECT_EQ(15, response_.past_rollback_key_version.firmware);
- EXPECT_EQ(14, response_.past_rollback_key_version.kernel_key);
- EXPECT_EQ(13, response_.past_rollback_key_version.kernel);
-}
-
-TEST_F(OmahaRequestActionTest, MismatchNumberOfVersions) {
- fake_update_response_.rollback = true;
- fake_update_response_.rollback_allowed_milestones = 2;
- fake_update_response_.deadline = "20101020";
- request_params_.set_rollback_allowed_milestones(4);
-
- // Since |request_params_.rollback_allowed_milestones| is 4 but the response
- // is constructed with |fake_update_response_.rollback_allowed_milestones| set
- // to 2, OmahaRequestAction will look for the key values of N-4 version but
- // only the N-2 version will exist.
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- tuc_params_.is_consumer_device = false;
- tuc_params_.rollback_allowed_milestones = 2;
- tuc_params_.is_policy_loaded = true;
-
- EXPECT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(response_.update_exists);
- EXPECT_TRUE(response_.is_rollback);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.firmware_key);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.firmware);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.kernel_key);
- EXPECT_EQ(std::numeric_limits<uint16_t>::max(),
- response_.past_rollback_key_version.kernel);
-}
-
-TEST_F(OmahaRequestActionTest, IncludeRequisitionTest) {
- request_params_.set_device_requisition("remora");
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_NE(string::npos, post_str_.find("requisition=\"remora\""));
-}
-
-TEST_F(OmahaRequestActionTest, NoIncludeRequisitionTest) {
- request_params_.set_device_requisition("");
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_EQ(string::npos, post_str_.find("requisition"));
-}
-
-TEST_F(OmahaRequestActionTest, PersistEolDateTest) {
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><app appid=\"test-app-id\" status=\"ok\">"
- "<ping status=\"ok\"/><updatecheck status=\"noupdate\" "
- "_eol_date=\"200\" _foo=\"bar\"/></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- string eol_date;
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->GetString(kPrefsOmahaEolDate,
- &eol_date));
- EXPECT_EQ("200", eol_date);
-}
-
-TEST_F(OmahaRequestActionTest, PersistEolMissingDateTest) {
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><app appid=\"test-app-id\" status=\"ok\">"
- "<ping status=\"ok\"/><updatecheck status=\"noupdate\" "
- "_foo=\"bar\"/></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- const string kDate = "123";
- FakeSystemState::Get()->prefs()->SetString(kPrefsOmahaEolDate, kDate);
-
- ASSERT_TRUE(TestUpdateCheck());
-
- string eol_date;
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->GetString(kPrefsOmahaEolDate,
- &eol_date));
- EXPECT_EQ(kDate, eol_date);
-}
-
-TEST_F(OmahaRequestActionTest, PersistEolBadDateTest) {
- tuc_params_.http_response =
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?><response "
- "protocol=\"3.0\"><app appid=\"test-app-id\" status=\"ok\">"
- "<ping status=\"ok\"/><updatecheck status=\"noupdate\" "
- "_eol_date=\"bad\" foo=\"bar\"/></app></response>";
- tuc_params_.expected_check_result = metrics::CheckResult::kNoUpdateAvailable;
- tuc_params_.expected_check_reaction = metrics::CheckReaction::kUnset;
-
- ASSERT_TRUE(TestUpdateCheck());
-
- string eol_date;
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->GetString(kPrefsOmahaEolDate,
- &eol_date));
- EXPECT_EQ(kEolDateInvalid, StringToEolDate(eol_date));
-}
-
-TEST_F(OmahaRequestActionDlcPingTest, StorePingReplyNoPing) {
- OmahaRequestParams::AppParams app_param = {.name = dlc_id_};
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(dlc_id_), app_param}});
-
- ASSERT_TRUE(TestUpdateCheck());
-
- int64_t temp_int;
- // If there was no ping, the metadata files shouldn't exist yet.
- EXPECT_FALSE(fake_prefs_->GetInt64(active_key_, &temp_int));
- EXPECT_FALSE(fake_prefs_->GetInt64(last_active_key_, &temp_int));
- EXPECT_FALSE(fake_prefs_->GetInt64(last_rollcall_key_, &temp_int));
-}
-
-TEST_F(OmahaRequestActionDlcPingTest, StorePingReplyActiveTest) {
- // Create Active value
- fake_prefs_->SetInt64(active_key_, 0);
-
- OmahaRequestParams::AppParams app_param = {
- .active_counting_type = OmahaRequestParams::kDateBased,
- .name = dlc_id_,
- .ping_active = 1,
- .send_ping = true};
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(dlc_id_), app_param}});
-
- int64_t temp_int;
- string temp_str;
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(fake_prefs_->GetInt64(active_key_, &temp_int));
- EXPECT_EQ(temp_int, kPingInactiveValue);
- EXPECT_TRUE(fake_prefs_->GetString(last_active_key_, &temp_str));
- EXPECT_EQ(temp_str, "4763");
- EXPECT_TRUE(fake_prefs_->GetString(last_rollcall_key_, &temp_str));
- EXPECT_EQ(temp_str, "4763");
-}
-
-TEST_F(OmahaRequestActionDlcPingTest, StorePingReplyInactiveTest) {
- // Create Active value
- fake_prefs_->SetInt64(active_key_, 0);
-
- OmahaRequestParams::AppParams app_param = {
- .active_counting_type = OmahaRequestParams::kDateBased,
- .name = dlc_id_,
- .ping_active = 0,
- .send_ping = true};
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(dlc_id_), app_param}});
-
- // Set the previous active value to an older value than 4763.
- fake_prefs_->SetString(last_active_key_, "555");
-
- int64_t temp_int;
- ASSERT_TRUE(TestUpdateCheck());
- EXPECT_TRUE(fake_prefs_->GetInt64(active_key_, &temp_int));
- EXPECT_EQ(temp_int, kPingInactiveValue);
- string temp_str;
- EXPECT_TRUE(fake_prefs_->GetString(last_active_key_, &temp_str));
- EXPECT_EQ(temp_str, "555");
- EXPECT_TRUE(fake_prefs_->GetString(last_rollcall_key_, &temp_str));
- EXPECT_EQ(temp_str, "4763");
-}
-
-TEST_F(OmahaRequestActionTest, OmahaResponseUpdateCanExcludeCheck) {
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
- fake_update_response_.dlc_app_update = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
- ASSERT_TRUE(delegate_.omaha_response_);
- const auto& packages = delegate_.omaha_response_->packages;
- ASSERT_EQ(packages.size(), 2);
-
- EXPECT_FALSE(packages[0].can_exclude);
- EXPECT_TRUE(packages[1].can_exclude);
-}
-
-TEST_F(OmahaRequestActionTest, OmahaResponseInstallCannotExcludeCheck) {
- request_params_.set_is_install(true);
- request_params_.set_dlc_apps_params(
- {{request_params_.GetDlcAppId(kDlcId1), {.name = kDlcId1}}});
- fake_update_response_.dlc_app_update = true;
- tuc_params_.http_response = fake_update_response_.GetUpdateResponse();
-
- EXPECT_CALL(mock_excluder_, IsExcluded(_)).WillRepeatedly(Return(false));
- ASSERT_TRUE(TestUpdateCheck());
- ASSERT_TRUE(delegate_.omaha_response_);
- const auto& packages = delegate_.omaha_response_->packages;
- ASSERT_EQ(packages.size(), 2);
-
- EXPECT_FALSE(packages[0].can_exclude);
- EXPECT_FALSE(packages[1].can_exclude);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_request_builder_xml.cc b/cros/omaha_request_builder_xml.cc
deleted file mode 100644
index 6cd9ab80..00000000
--- a/cros/omaha_request_builder_xml.cc
+++ /dev/null
@@ -1,462 +0,0 @@
-//
-// Copyright (C) 2019 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/cros/omaha_request_builder_xml.h"
-
-#include <inttypes.h>
-
-#include <string>
-
-#include <base/guid.h>
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <base/time/time.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/omaha_request_params.h"
-
-using std::string;
-
-namespace chromeos_update_engine {
-
-const char kNoVersion[] = "0.0.0.0";
-const int kPingNeverPinged = -1;
-const int kPingUnknownValue = -2;
-const int kPingActiveValue = 1;
-const int kPingInactiveValue = 0;
-
-bool XmlEncode(const string& input, string* output) {
- if (std::find_if(input.begin(), input.end(), [](const char c) {
- return c & 0x80;
- }) != input.end()) {
- LOG(WARNING) << "Invalid ASCII-7 string passed to the XML encoder:";
- utils::HexDumpString(input);
- return false;
- }
- output->clear();
- // We need at least input.size() space in the output, but the code below will
- // handle it if we need more.
- output->reserve(input.size());
- for (char c : input) {
- switch (c) {
- case '\"':
- output->append("&quot;");
- break;
- case '\'':
- output->append("&apos;");
- break;
- case '&':
- output->append("&amp;");
- break;
- case '<':
- output->append("&lt;");
- break;
- case '>':
- output->append("&gt;");
- break;
- default:
- output->push_back(c);
- }
- }
- return true;
-}
-
-string XmlEncodeWithDefault(const string& input, const string& default_value) {
- string output;
- if (XmlEncode(input, &output))
- return output;
- return default_value;
-}
-
-string OmahaRequestBuilderXml::GetPing() const {
- // Returns an XML ping element attribute assignment with attribute
- // |name| and value |ping_days| if |ping_days| has a value that needs
- // to be sent, or an empty string otherwise.
- auto GetPingAttribute = [](const char* name, int ping_days) -> string {
- if (ping_days > 0 || ping_days == kPingNeverPinged)
- return base::StringPrintf(" %s=\"%d\"", name, ping_days);
- return "";
- };
-
- string ping_active = GetPingAttribute("a", ping_active_days_);
- string ping_roll_call = GetPingAttribute("r", ping_roll_call_days_);
- if (!ping_active.empty() || !ping_roll_call.empty()) {
- return base::StringPrintf(" <ping active=\"1\"%s%s></ping>\n",
- ping_active.c_str(),
- ping_roll_call.c_str());
- }
- return "";
-}
-
-string OmahaRequestBuilderXml::GetPingDateBased(
- const OmahaRequestParams::AppParams& app_params) const {
- if (!app_params.send_ping)
- return "";
- string ping_active = "";
- string ping_ad = "";
- if (app_params.ping_active == kPingActiveValue) {
- ping_active =
- base::StringPrintf(" active=\"%" PRId64 "\"", app_params.ping_active);
- ping_ad = base::StringPrintf(" ad=\"%" PRId64 "\"",
- app_params.ping_date_last_active);
- }
-
- string ping_rd = base::StringPrintf(" rd=\"%" PRId64 "\"",
- app_params.ping_date_last_rollcall);
-
- return base::StringPrintf(" <ping%s%s%s></ping>\n",
- ping_active.c_str(),
- ping_ad.c_str(),
- ping_rd.c_str());
-}
-
-string OmahaRequestBuilderXml::GetAppBody(const OmahaAppData& app_data) const {
- string app_body;
- if (event_ == nullptr) {
- if (app_data.app_params.send_ping) {
- switch (app_data.app_params.active_counting_type) {
- case OmahaRequestParams::kDayBased:
- app_body = GetPing();
- break;
- case OmahaRequestParams::kDateBased:
- app_body = GetPingDateBased(app_data.app_params);
- break;
- default:
- NOTREACHED();
- }
- }
- if (!ping_only_) {
- if (!app_data.skip_update) {
- const auto* params = SystemState::Get()->request_params();
- app_body += " <updatecheck";
- if (!params->target_version_prefix().empty()) {
- app_body += base::StringPrintf(
- " targetversionprefix=\"%s\"",
- XmlEncodeWithDefault(params->target_version_prefix()).c_str());
- // Rollback requires target_version_prefix set.
- if (params->rollback_allowed()) {
- 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";
- }
-
- // If this is the first update check after a reboot following a previous
- // update, generate an event containing the previous version number. If
- // the previous version preference file doesn't exist the event is still
- // generated with a previous version of 0.0.0.0 -- this is relevant for
- // older clients or new installs. The previous version event is not sent
- // for ping-only requests because they come before the client has
- // rebooted. The previous version event is also not sent if it was already
- // sent for this new version with a previous updatecheck.
- auto* prefs = SystemState::Get()->prefs();
- string prev_version;
- if (!prefs->GetString(kPrefsPreviousVersion, &prev_version)) {
- prev_version = kNoVersion;
- }
- // We only store a non-empty previous version value after a successful
- // update in the previous boot. After reporting it back to the server,
- // we clear the previous version value so it doesn't get reported again.
- if (!prev_version.empty()) {
- app_body += base::StringPrintf(
- " <event eventtype=\"%d\" eventresult=\"%d\" "
- "previousversion=\"%s\"></event>\n",
- OmahaEvent::kTypeRebootedAfterUpdate,
- OmahaEvent::kResultSuccess,
- XmlEncodeWithDefault(prev_version, kNoVersion).c_str());
- LOG_IF(WARNING, !prefs->SetString(kPrefsPreviousVersion, ""))
- << "Unable to reset the previous version.";
- }
- }
- } 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) {
- 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,
- error_code.c_str());
- }
-
- return app_body;
-}
-
-string OmahaRequestBuilderXml::GetCohortArg(
- const string& arg_name,
- const string& prefs_key,
- const string& override_value) const {
- string cohort_value;
- if (!override_value.empty()) {
- // |override_value| take precedence over pref value.
- cohort_value = override_value;
- } else {
- // There's nothing wrong with not having a given cohort setting, so we check
- // existence first to avoid the warning log message.
- const auto* prefs = SystemState::Get()->prefs();
- if (!prefs->Exists(prefs_key))
- return "";
- if (!prefs->GetString(prefs_key, &cohort_value) || cohort_value.empty())
- return "";
- }
- // This is a validity check to avoid sending a huge XML file back to Ohama due
- // to a compromised stateful partition making the update check fail in low
- // network environments envent after a reboot.
- if (cohort_value.size() > 1024) {
- LOG(WARNING) << "The omaha cohort setting " << arg_name
- << " has a too big value, which must be an error or an "
- "attacker trying to inhibit updates.";
- return "";
- }
-
- string escaped_xml_value;
- if (!XmlEncode(cohort_value, &escaped_xml_value)) {
- LOG(WARNING) << "The omaha cohort setting " << arg_name
- << " is ASCII-7 invalid, ignoring it.";
- return "";
- }
-
- return base::StringPrintf(
- "%s=\"%s\" ", arg_name.c_str(), escaped_xml_value.c_str());
-}
-
-bool IsValidComponentID(const string& id) {
- for (char c : id) {
- if (!isalnum(c) && c != '-' && c != '_' && c != '.')
- return false;
- }
- return true;
-}
-
-string OmahaRequestBuilderXml::GetApp(const OmahaAppData& app_data) const {
- string app_body = GetAppBody(app_data);
- string app_versions;
- const auto* params = SystemState::Get()->request_params();
-
- // If we are downgrading to a more stable channel and we are allowed to do
- // powerwash, then pass 0.0.0.0 as the version. This is needed to get the
- // highest-versioned payload on the destination channel.
- if (params->ShouldPowerwash()) {
- LOG(INFO) << "Passing OS version as 0.0.0.0 as we are set to powerwash "
- << "on downgrading to the version in the more stable channel";
- app_versions = "version=\"" + string(kNoVersion) + "\" from_version=\"" +
- XmlEncodeWithDefault(app_data.version, kNoVersion) + "\" ";
- } else {
- app_versions = "version=\"" +
- XmlEncodeWithDefault(app_data.version, kNoVersion) + "\" ";
- }
-
- string download_channel = params->download_channel();
- string app_channels =
- "track=\"" + XmlEncodeWithDefault(download_channel) + "\" ";
- if (params->current_channel() != download_channel) {
- app_channels += "from_track=\"" +
- XmlEncodeWithDefault(params->current_channel()) + "\" ";
- }
-
- string delta_okay_str =
- params->delta_okay() && !params->is_install() ? "true" : "false";
-
- // If install_date_days is not set (e.g. its value is -1 ), don't
- // include the attribute.
- string install_date_in_days_str = "";
- if (install_date_in_days_ >= 0) {
- install_date_in_days_str =
- base::StringPrintf("installdate=\"%d\" ", install_date_in_days_);
- }
-
- string app_cohort_args;
- string cohort_key = kPrefsOmahaCohort;
- string cohortname_key = kPrefsOmahaCohortName;
- string cohorthint_key = kPrefsOmahaCohortHint;
-
- // Override the cohort keys for DLC App IDs.
- const auto& dlc_apps_params = params->dlc_apps_params();
- auto itr = dlc_apps_params.find(app_data.id);
- if (itr != dlc_apps_params.end()) {
- auto dlc_id = itr->second.name;
- const auto* prefs = SystemState::Get()->prefs();
- cohort_key =
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohort});
- cohortname_key =
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohortName});
- cohorthint_key =
- prefs->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsOmahaCohortHint});
- }
-
- app_cohort_args += GetCohortArg("cohort", cohort_key);
- app_cohort_args += GetCohortArg("cohortname", cohortname_key);
- // Policy provided value overrides pref.
- app_cohort_args +=
- GetCohortArg("cohorthint",
- cohorthint_key,
- params->autoupdate_token() /* override_value */);
-
- string fingerprint_arg;
- if (!params->os_build_fingerprint().empty()) {
- fingerprint_arg = "fingerprint=\"" +
- XmlEncodeWithDefault(params->os_build_fingerprint()) +
- "\" ";
- }
-
- string buildtype_arg;
- if (!params->os_build_type().empty()) {
- buildtype_arg = "os_build_type=\"" +
- XmlEncodeWithDefault(params->os_build_type()) + "\" ";
- }
-
- string product_components_args;
- if (!params->ShouldPowerwash() && !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;
- }
- }
-
- string requisition_arg;
- if (!params->device_requisition().empty()) {
- requisition_arg = "requisition=\"" +
- XmlEncodeWithDefault(params->device_requisition()) +
- "\" ";
- }
-
- // 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 +
- "board=\"" + XmlEncodeWithDefault(params->os_board()) + "\" " +
- "hardware_class=\"" + XmlEncodeWithDefault(params->hwid()) + "\" " +
- "delta_okay=\"" + delta_okay_str + "\" " +
- install_date_in_days_str +
-
- // DLC excluded for installs and updates.
- (app_data.is_dlc ? "" :
- "lang=\"" + XmlEncodeWithDefault(params->app_lang(), "en-US") + "\" " +
- requisition_arg) +
-
- ">\n" +
- app_body +
- " </app>\n";
- // clang-format on
- return app_xml;
-}
-
-string OmahaRequestBuilderXml::GetOs() const {
- const auto* params = SystemState::Get()->request_params();
- string os_xml =
- " <os "
- "version=\"" +
- XmlEncodeWithDefault(params->os_version()) + "\" " + "platform=\"" +
- XmlEncodeWithDefault(params->os_platform()) + "\" " + "sp=\"" +
- XmlEncodeWithDefault(params->os_sp()) +
- "\">"
- "</os>\n";
- return os_xml;
-}
-
-string OmahaRequestBuilderXml::GetRequest() const {
- const auto* params = SystemState::Get()->request_params();
- string os_xml = GetOs();
- string app_xml = GetApps();
-
- string request_xml = base::StringPrintf(
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<request requestid=\"%s\" sessionid=\"%s\""
- " protocol=\"3.0\" updater=\"%s\" updaterversion=\"%s\""
- " installsource=\"%s\" ismachine=\"1\">\n%s%s</request>\n",
- base::GenerateGUID().c_str() /* requestid */,
- session_id_.c_str(),
- constants::kOmahaUpdaterID,
- kOmahaUpdaterVersion,
- params->interactive() ? "ondemandupdate" : "scheduler",
- os_xml.c_str(),
- app_xml.c_str());
-
- return request_xml;
-}
-
-string OmahaRequestBuilderXml::GetApps() const {
- const auto* params = SystemState::Get()->request_params();
- string app_xml = "";
- OmahaAppData product_app = {
- .id = params->GetAppId(),
- .version = params->app_version(),
- .product_components = params->product_components(),
- // Skips updatecheck for platform app in case of an install operation.
- .skip_update = params->is_install(),
- .is_dlc = false,
-
- .app_params = {.active_counting_type = OmahaRequestParams::kDayBased,
- .send_ping = include_ping_}};
- app_xml += GetApp(product_app);
- for (const auto& it : params->dlc_apps_params()) {
- OmahaAppData dlc_app_data = {
- .id = it.first,
- .version = params->is_install() ? kNoVersion : params->app_version(),
- .skip_update = false,
- .is_dlc = true,
- .app_params = it.second};
- app_xml += GetApp(dlc_app_data);
- }
- return app_xml;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_request_builder_xml.h b/cros/omaha_request_builder_xml.h
deleted file mode 100644
index 7c246f7f..00000000
--- a/cros/omaha_request_builder_xml.h
+++ /dev/null
@@ -1,192 +0,0 @@
-//
-// Copyright (C) 2019 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_CROS_OMAHA_REQUEST_BUILDER_XML_H_
-#define UPDATE_ENGINE_CROS_OMAHA_REQUEST_BUILDER_XML_H_
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-#include <brillo/secure_blob.h>
-#include <curl/curl.h>
-
-#include "update_engine/common/action.h"
-#include "update_engine/common/http_fetcher.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/omaha_response.h"
-
-namespace chromeos_update_engine {
-
-extern const char kNoVersion[];
-extern const int kPingNeverPinged;
-extern const int kPingUnknownValue;
-extern const int kPingActiveValue;
-extern const int kPingInactiveValue;
-
-// This struct encapsulates the Omaha event information. For a
-// complete list of defined event types and results, see
-// http://code.google.com/p/omaha/wiki/ServerProtocol#event
-struct OmahaEvent {
- // The Type values correspond to EVENT_TYPE values of Omaha.
- enum Type {
- kTypeUnknown = 0,
- kTypeDownloadComplete = 1,
- kTypeInstallComplete = 2,
- kTypeUpdateComplete = 3,
- kTypeUpdateDownloadStarted = 13,
- kTypeUpdateDownloadFinished = 14,
- // Chromium OS reserved type sent after the first reboot following an update
- // completed.
- kTypeRebootedAfterUpdate = 54,
- };
-
- // The Result values correspond to EVENT_RESULT values of Omaha.
- enum Result {
- kResultError = 0,
- kResultSuccess = 1,
- kResultUpdateDeferred = 9, // When we ignore/defer updates due to policy.
- };
-
- OmahaEvent()
- : type(kTypeUnknown),
- result(kResultError),
- error_code(ErrorCode::kError) {}
- explicit OmahaEvent(Type in_type)
- : type(in_type),
- result(kResultSuccess),
- error_code(ErrorCode::kSuccess) {}
- OmahaEvent(Type in_type, Result in_result, ErrorCode in_error_code)
- : type(in_type), result(in_result), error_code(in_error_code) {}
-
- Type type;
- Result result;
- ErrorCode error_code;
-};
-
-struct OmahaAppData {
- std::string id;
- std::string version;
- std::string product_components;
- bool skip_update;
- bool is_dlc;
- OmahaRequestParams::AppParams app_params;
-};
-
-// Encodes XML entities in a given string. Input must be ASCII-7 valid. If
-// the input is invalid, the default value is used instead.
-std::string XmlEncodeWithDefault(const std::string& input,
- const std::string& default_value = "");
-
-// Escapes text so it can be included as character data and attribute
-// values. The |input| string must be valid ASCII-7, no UTF-8 supported.
-// Returns whether the |input| was valid and escaped properly in |output|.
-bool XmlEncode(const std::string& input, std::string* output);
-
-// Returns a boolean based on examining each character on whether it's a valid
-// component (meaning all characters are an alphanum excluding '-', '_', '.').
-bool IsValidComponentID(const std::string& id);
-
-class OmahaRequestBuilder {
- public:
- OmahaRequestBuilder() = default;
- virtual ~OmahaRequestBuilder() = default;
-
- virtual std::string GetRequest() const = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(OmahaRequestBuilder);
-};
-
-class OmahaRequestBuilderXml : OmahaRequestBuilder {
- public:
- OmahaRequestBuilderXml(const OmahaEvent* event,
- bool ping_only,
- bool include_ping,
- int ping_active_days,
- int ping_roll_call_days,
- int install_date_in_days,
- const std::string& session_id)
- : event_(event),
- ping_only_(ping_only),
- include_ping_(include_ping),
- ping_active_days_(ping_active_days),
- ping_roll_call_days_(ping_roll_call_days),
- install_date_in_days_(install_date_in_days),
- session_id_(session_id) {}
-
- ~OmahaRequestBuilderXml() override = default;
-
- // Returns an XML that corresponds to the entire Omaha request.
- std::string GetRequest() const override;
-
- private:
- FRIEND_TEST(OmahaRequestBuilderXmlTest, PlatformGetAppTest);
- FRIEND_TEST(OmahaRequestBuilderXmlTest, DlcGetAppTest);
-
- // Returns an XML that corresponds to the entire <os> node of the Omaha
- // request based on the member variables.
- std::string GetOs() const;
-
- // Returns an XML that corresponds to all <app> nodes of the Omaha
- // request based on the given parameters.
- std::string GetApps() const;
-
- // Returns an XML that corresponds to the single <app> node of the Omaha
- // request based on the given parameters.
- std::string GetApp(const OmahaAppData& app_data) const;
-
- // Returns an XML that goes into the body of the <app> element of the Omaha
- // request based on the given parameters.
- std::string GetAppBody(const OmahaAppData& app_data) const;
-
- // Returns the cohort* argument to include in the <app> tag for the passed
- // |arg_name| and |prefs_key|, if any. The return value is suitable to
- // concatenate to the list of arguments and includes a space at the end.
- std::string GetCohortArg(const std::string& arg_name,
- const std::string& prefs_key,
- const std::string& override_value = "") const;
-
- // Returns an XML ping element if any of the elapsed days need to be
- // sent, or an empty string otherwise.
- std::string GetPing() const;
-
- // Returns an XML ping element if any of the elapsed days need to be
- // sent, or an empty string otherwise.
- std::string GetPingDateBased(
- const OmahaRequestParams::AppParams& app_params) const;
-
- const OmahaEvent* event_;
- bool ping_only_;
- bool include_ping_;
- int ping_active_days_;
- int ping_roll_call_days_;
- int install_date_in_days_;
- std::string session_id_;
-
- DISALLOW_COPY_AND_ASSIGN(OmahaRequestBuilderXml);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_OMAHA_REQUEST_BUILDER_XML_H_
diff --git a/cros/omaha_request_builder_xml_unittest.cc b/cros/omaha_request_builder_xml_unittest.cc
deleted file mode 100644
index 76a72411..00000000
--- a/cros/omaha_request_builder_xml_unittest.cc
+++ /dev/null
@@ -1,421 +0,0 @@
-//
-// Copyright (C) 2019 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/cros/omaha_request_builder_xml.h"
-
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <base/guid.h>
-#include <base/strings/stringprintf.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/cros/fake_system_state.h"
-
-using std::pair;
-using std::string;
-using std::vector;
-using testing::_;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace chromeos_update_engine {
-
-namespace {
-// Helper to find key and extract value from the given string |xml|, instead
-// of using a full parser. The attribute key will be followed by "=\"" as xml
-// attribute values must be within double quotes (not single quotes).
-static string FindAttributeKeyValueInXml(const string& xml,
- const string& key,
- const size_t val_size) {
- string key_with_quotes = key + "=\"";
- const size_t val_start_pos = xml.find(key);
- if (val_start_pos == string::npos)
- return "";
- return xml.substr(val_start_pos + key_with_quotes.size(), val_size);
-}
-// Helper to find the count of substring in a string.
-static size_t CountSubstringInString(const string& str, const string& substr) {
- size_t count = 0, pos = 0;
- while ((pos = str.find(substr, pos ? pos + 1 : 0)) != string::npos)
- ++count;
- return count;
-}
-} // namespace
-
-class OmahaRequestBuilderXmlTest : public ::testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
- FakeSystemState::Get()->set_request_params(&params_);
- }
- void TearDown() override {}
-
- static constexpr size_t kGuidSize = 36;
-
- OmahaRequestParams params_;
-};
-
-TEST_F(OmahaRequestBuilderXmlTest, XmlEncodeTest) {
- string output;
- vector<pair<string, string>> xml_encode_pairs = {
- {"ab", "ab"},
- {"a<b", "a&lt;b"},
- {"<&>\"\'\\", "&lt;&amp;&gt;&quot;&apos;\\"},
- {"&lt;&amp;&gt;", "&amp;lt;&amp;amp;&amp;gt;"}};
- for (const auto& xml_encode_pair : xml_encode_pairs) {
- const auto& before_encoding = xml_encode_pair.first;
- const auto& after_encoding = xml_encode_pair.second;
- EXPECT_TRUE(XmlEncode(before_encoding, &output));
- EXPECT_EQ(after_encoding, output);
- }
- // Check that unterminated UTF-8 strings are handled properly.
- EXPECT_FALSE(XmlEncode("\xc2", &output));
- // Fail with invalid ASCII-7 chars.
- EXPECT_FALSE(XmlEncode("This is an 'n' with a tilde: \xc3\xb1", &output));
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, XmlEncodeWithDefaultTest) {
- EXPECT_EQ("", XmlEncodeWithDefault(""));
- EXPECT_EQ("&lt;&amp;&gt;", XmlEncodeWithDefault("<&>", "something else"));
- EXPECT_EQ("<not escaped>", XmlEncodeWithDefault("\xc2", "<not escaped>"));
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, PlatformGetAppTest) {
- params_.set_device_requisition("device requisition");
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- OmahaAppData dlc_app_data = {.id = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
- .version = "",
- .skip_update = false,
- .is_dlc = false};
-
- // Verify that the attributes that shouldn't be missing for Platform AppID are
- // in fact present in the <app ...></app>.
- const string app = omaha_request.GetApp(dlc_app_data);
- EXPECT_NE(string::npos, app.find("lang="));
- EXPECT_NE(string::npos, app.find("requisition="));
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, DlcGetAppTest) {
- params_.set_device_requisition("device requisition");
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- OmahaAppData dlc_app_data = {
- .id = "_dlc_id", .version = "", .skip_update = false, .is_dlc = true};
-
- // Verify that the attributes that should be missing for DLC AppIDs are in
- // fact not present in the <app ...></app>.
- const string app = omaha_request.GetApp(dlc_app_data);
- EXPECT_EQ(string::npos, app.find("lang="));
- EXPECT_EQ(string::npos, app.find("requisition="));
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlRequestIdTest) {
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- const string key = "requestid";
- const string request_id =
- FindAttributeKeyValueInXml(request_xml, 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));
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlSessionIdTest) {
- const string gen_session_id = base::GenerateGUID();
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- gen_session_id};
- const string request_xml = omaha_request.GetRequest();
- const string key = "sessionid";
- const string session_id =
- FindAttributeKeyValueInXml(request_xml, 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));
- }
- EXPECT_EQ(gen_session_id, session_id);
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlPlatformUpdateTest) {
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(1, CountSubstringInString(request_xml, "<updatecheck"))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlPlatformUpdateWithDlcsTest) {
- params_.set_dlc_apps_params(
- {{params_.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}},
- {params_.GetDlcAppId("dlc_no_1"), {.name = "dlc_no_1"}}});
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(3, CountSubstringInString(request_xml, "<updatecheck"))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcInstallationTest) {
- const std::map<std::string, OmahaRequestParams::AppParams> dlcs = {
- {params_.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}},
- {params_.GetDlcAppId("dlc_no_1"), {.name = "dlc_no_1"}}};
- params_.set_dlc_apps_params(dlcs);
- params_.set_is_install(true);
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(2, CountSubstringInString(request_xml, "<updatecheck"))
- << request_xml;
-
- auto FindAppId = [request_xml](size_t pos) -> size_t {
- return request_xml.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;
- const string dlc_app_id_version = FindAttributeKeyValueInXml(
- request_xml.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());
- EXPECT_EQ(false_str, dlc_app_id_delta_okay);
- }
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcNoPing) {
- params_.set_dlc_apps_params(
- {{params_.GetDlcAppId("dlc_no_0"), {.name = "dlc_no_0"}}});
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(0, CountSubstringInString(request_xml, "<ping")) << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcPingRollCallNoActive) {
- params_.set_dlc_apps_params(
- {{params_.GetDlcAppId("dlc_no_0"),
- {.active_counting_type = OmahaRequestParams::kDateBased,
- .name = "dlc_no_0",
- .ping_date_last_active = 25,
- .ping_date_last_rollcall = 36,
- .send_ping = true}}});
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(1, CountSubstringInString(request_xml, "<ping rd=\"36\""))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcPingRollCallAndActive) {
- params_.set_dlc_apps_params(
- {{params_.GetDlcAppId("dlc_no_0"),
- {.active_counting_type = OmahaRequestParams::kDateBased,
- .name = "dlc_no_0",
- .ping_active = 1,
- .ping_date_last_active = 25,
- .ping_date_last_rollcall = 36,
- .send_ping = true}}});
- OmahaRequestBuilderXml omaha_request{nullptr,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(1,
- CountSubstringInString(request_xml,
- "<ping active=\"1\" ad=\"25\" rd=\"36\""))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlUpdateCompleteEvent) {
- OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
- OmahaRequestBuilderXml omaha_request{&event,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- LOG(INFO) << request_xml;
- EXPECT_EQ(
- 1,
- CountSubstringInString(
- request_xml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest,
- GetRequestXmlUpdateCompleteEventSomeDlcsExcluded) {
- params_.set_dlc_apps_params({
- {params_.GetDlcAppId("dlc_1"), {.updated = true}},
- {params_.GetDlcAppId("dlc_2"), {.updated = false}},
- });
- OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
- OmahaRequestBuilderXml omaha_request{&event,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(
- 2,
- CountSubstringInString(
- request_xml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
- << request_xml;
- EXPECT_EQ(
- 1,
- CountSubstringInString(
- request_xml,
- "<event eventtype=\"3\" eventresult=\"0\" errorcode=\"62\"></event>"))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest,
- GetRequestXmlUpdateCompleteEventAllDlcsExcluded) {
- params_.set_dlc_apps_params({
- {params_.GetDlcAppId("dlc_1"), {.updated = false}},
- {params_.GetDlcAppId("dlc_2"), {.updated = false}},
- });
- OmahaEvent event(OmahaEvent::kTypeUpdateComplete);
- OmahaRequestBuilderXml omaha_request{&event,
- false,
- false,
- 0,
- 0,
- 0,
- ""};
- const string request_xml = omaha_request.GetRequest();
- EXPECT_EQ(
- 1,
- CountSubstringInString(
- request_xml, "<event eventtype=\"3\" eventresult=\"1\"></event>"))
- << request_xml;
- EXPECT_EQ(
- 2,
- CountSubstringInString(
- request_xml,
- "<event eventtype=\"3\" eventresult=\"0\" errorcode=\"62\"></event>"))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcCohortMissingCheck) {
- constexpr char kDlcId[] = "test-dlc-id";
- params_.set_dlc_apps_params(
- {{params_.GetDlcAppId(kDlcId), {.name = kDlcId}}});
- OmahaEvent event(OmahaEvent::kTypeUpdateDownloadStarted);
- OmahaRequestBuilderXml omaha_request{&event, false, false, 0, 0, 0, ""};
- const string request_xml = omaha_request.GetRequest();
-
- // Check that no cohorts are in the request.
- EXPECT_EQ(0, CountSubstringInString(request_xml, "cohort=")) << request_xml;
- EXPECT_EQ(0, CountSubstringInString(request_xml, "cohortname="))
- << request_xml;
- EXPECT_EQ(0, CountSubstringInString(request_xml, "cohorthint="))
- << request_xml;
-}
-
-TEST_F(OmahaRequestBuilderXmlTest, GetRequestXmlDlcCohortCheck) {
- const string kDlcId = "test-dlc-id";
- params_.set_dlc_apps_params(
- {{params_.GetDlcAppId(kDlcId), {.name = kDlcId}}});
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- OmahaEvent event(OmahaEvent::kTypeUpdateDownloadStarted);
- OmahaRequestBuilderXml omaha_request{&event, false, false, 0, 0, 0, ""};
- // DLC App ID Expectations.
- const string dlc_cohort_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, kDlcId, kPrefsOmahaCohort});
- const string kDlcCohortVal = "test-cohort";
- EXPECT_TRUE(fake_prefs->SetString(dlc_cohort_key, kDlcCohortVal));
- const string dlc_cohort_name_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, kDlcId, kPrefsOmahaCohortName});
- const string kDlcCohortNameVal = "test-cohortname";
- EXPECT_TRUE(fake_prefs->SetString(dlc_cohort_name_key, kDlcCohortNameVal));
- const string dlc_cohort_hint_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, kDlcId, kPrefsOmahaCohortHint});
- const string kDlcCohortHintVal = "test-cohortval";
- EXPECT_TRUE(fake_prefs->SetString(dlc_cohort_hint_key, kDlcCohortHintVal));
- const string request_xml = omaha_request.GetRequest();
-
- EXPECT_EQ(1,
- CountSubstringInString(
- request_xml,
- base::StringPrintf(
- "cohort=\"%s\" cohortname=\"%s\" cohorthint=\"%s\"",
- kDlcCohortVal.c_str(),
- kDlcCohortNameVal.c_str(),
- kDlcCohortHintVal.c_str())))
- << request_xml;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_request_params.cc b/cros/omaha_request_params.cc
deleted file mode 100644
index adcfc759..00000000
--- a/cros/omaha_request_params.cc
+++ /dev/null
@@ -1,294 +0,0 @@
-//
-// Copyright (C) 2011 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/cros/omaha_request_params.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/utsname.h>
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <base/files/file_util.h>
-#include <base/stl_util.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/key_value_store.h>
-#include <brillo/strings/string_utils.h>
-#include <policy/device_policy.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/update_manager/policy.h"
-
-#define CALL_MEMBER_FN(object, member) ((object).*(member))
-
-using chromeos_update_manager::UpdateCheckParams;
-using std::string;
-
-namespace chromeos_update_engine {
-
-const char OmahaRequestParams::kOsVersion[] = "Indy";
-
-const char* kChannelsByStability[] = {
- // This list has to be sorted from least stable to most stable channel.
- "canary-channel",
- "dev-channel",
- "beta-channel",
- "stable-channel",
-};
-
-OmahaRequestParams::~OmahaRequestParams() {
- if (!root_.empty())
- test::SetImagePropertiesRootPrefix(nullptr);
-}
-
-bool OmahaRequestParams::Init(const string& app_version,
- const string& update_url,
- const UpdateCheckParams& params) {
- LOG(INFO) << "Initializing parameters for this update attempt";
- image_props_ = LoadImageProperties();
- mutable_image_props_ = LoadMutableImageProperties();
-
- // Validation check the channel names.
- if (!IsValidChannel(image_props_.current_channel))
- image_props_.current_channel = "stable-channel";
- if (!IsValidChannel(mutable_image_props_.target_channel))
- mutable_image_props_.target_channel = image_props_.current_channel;
- UpdateDownloadChannel();
-
- LOG(INFO) << "Running from channel " << image_props_.current_channel;
-
- os_platform_ = constants::kOmahaPlatformName;
- os_version_ = OmahaRequestParams::kOsVersion;
- if (!app_version.empty())
- image_props_.version = app_version;
-
- os_sp_ = image_props_.version + "_" + GetMachineType();
- app_lang_ = "en-US";
- hwid_ = SystemState::Get()->hardware()->GetHardwareClass();
- device_requisition_ = SystemState::Get()->hardware()->GetDeviceRequisition();
-
- if (image_props_.current_channel == mutable_image_props_.target_channel) {
- // deltas are only okay if the /.nodelta file does not exist. if we don't
- // know (i.e. stat() returns some unexpected error), then err on the side of
- // caution and say deltas are not okay.
- struct stat stbuf;
- delta_okay_ =
- (stat((root_ + "/.nodelta").c_str(), &stbuf) < 0) && (errno == ENOENT);
- } else {
- LOG(INFO) << "Disabling deltas as a channel change to "
- << mutable_image_props_.target_channel
- << " is pending, with is_powerwash_allowed="
- << utils::ToString(mutable_image_props_.is_powerwash_allowed);
- // For now, disable delta updates if the current channel is different from
- // the channel that we're sending to the update server because such updates
- // are destined to fail -- the current rootfs hash will be different than
- // the expected hash due to the different channel in /etc/lsb-release.
- delta_okay_ = false;
- }
-
- if (update_url.empty())
- update_url_ = image_props_.omaha_url;
- else
- update_url_ = update_url;
-
- // Set the interactive flag accordingly.
- interactive_ = params.interactive;
-
- dlc_apps_params_.clear();
- // Set false so it will do update by default.
- is_install_ = false;
-
- target_version_prefix_ = params.target_version_prefix;
-
- lts_tag_ = params.lts_tag;
-
- autoupdate_token_ = params.quick_fix_build_token;
-
- rollback_allowed_ = params.rollback_allowed;
-
- // Set whether saving data over rollback is requested.
- rollback_data_save_requested_ = params.rollback_data_save_requested;
-
- // Set how many milestones of rollback are allowed.
- rollback_allowed_milestones_ = params.rollback_allowed_milestones;
-
- // Set the target channel, if one was provided.
- if (params.target_channel.empty()) {
- LOG(INFO) << "No target channel mandated by policy.";
- } else {
- LOG(INFO) << "Setting target channel as mandated: "
- << params.target_channel;
- string error_message;
- if (!SetTargetChannel(params.target_channel,
- params.rollback_on_channel_downgrade,
- &error_message)) {
- LOG(ERROR) << "Setting the channel failed: " << error_message;
- }
-
- // Since this is the beginning of a new attempt, update the download
- // channel. The download channel won't be updated until the next attempt,
- // even if target channel changes meanwhile, so that how we'll know if we
- // should cancel the current download attempt if there's such a change in
- // target channel.
- UpdateDownloadChannel();
- }
-
- return true;
-}
-
-bool OmahaRequestParams::IsUpdateUrlOfficial() const {
- return (update_url_ == constants::kOmahaDefaultAUTestURL ||
- update_url_ == image_props_.omaha_url);
-}
-
-bool OmahaRequestParams::SetTargetChannel(const string& new_target_channel,
- bool is_powerwash_allowed,
- string* error_message) {
- LOG(INFO) << "SetTargetChannel called with " << new_target_channel
- << ", Is Powerwash Allowed = "
- << utils::ToString(is_powerwash_allowed)
- << ". Current channel = " << image_props_.current_channel
- << ", existing target channel = "
- << mutable_image_props_.target_channel
- << ", download channel = " << download_channel_;
- if (!IsValidChannel(new_target_channel, error_message)) {
- return false;
- }
-
- MutableImageProperties new_props;
- new_props.target_channel = new_target_channel;
- new_props.is_powerwash_allowed = is_powerwash_allowed;
-
- if (!StoreMutableImageProperties(new_props)) {
- if (error_message)
- *error_message = "Error storing the new channel value.";
- return false;
- }
- mutable_image_props_ = new_props;
- return true;
-}
-
-void OmahaRequestParams::UpdateDownloadChannel() {
- if (download_channel_ != mutable_image_props_.target_channel) {
- download_channel_ = mutable_image_props_.target_channel;
- LOG(INFO) << "Download channel for this attempt = " << download_channel_;
- }
-}
-
-string OmahaRequestParams::GetMachineType() const {
- struct utsname buf;
- string ret;
- if (uname(&buf) == 0)
- ret = buf.machine;
- return ret;
-}
-
-bool OmahaRequestParams::IsValidChannel(const string& channel,
- string* error_message) const {
- if (image_props_.allow_arbitrary_channels) {
- if (!base::EndsWith(channel, "-channel", base::CompareCase::SENSITIVE)) {
- if (error_message) {
- *error_message = base::StringPrintf(
- "Invalid channel name \"%s\", must ends with -channel.",
- channel.c_str());
- }
- return false;
- }
- return true;
- }
- if (GetChannelIndex(channel) < 0) {
- string valid_channels = brillo::string_utils::JoinRange(
- ", ", std::begin(kChannelsByStability), std::end(kChannelsByStability));
- if (error_message) {
- *error_message =
- base::StringPrintf("Invalid channel name \"%s\", valid names are: %s",
- channel.c_str(),
- valid_channels.c_str());
- }
- return false;
- }
- return true;
-}
-
-void OmahaRequestParams::set_root(const string& root) {
- root_ = root;
- test::SetImagePropertiesRootPrefix(root_.c_str());
-}
-
-int OmahaRequestParams::GetChannelIndex(const string& channel) const {
- for (size_t t = 0; t < base::size(kChannelsByStability); ++t)
- if (channel == kChannelsByStability[t])
- return t;
-
- return -1;
-}
-
-bool OmahaRequestParams::ToMoreStableChannel() const {
- int current_channel_index = GetChannelIndex(image_props_.current_channel);
- int download_channel_index = GetChannelIndex(download_channel_);
-
- return download_channel_index > current_channel_index;
-}
-
-bool OmahaRequestParams::ShouldPowerwash() const {
- if (!mutable_image_props_.is_powerwash_allowed)
- return false;
- // If arbitrary channels are allowed, always powerwash on channel change.
- if (image_props_.allow_arbitrary_channels)
- return image_props_.current_channel != download_channel_;
- // Otherwise only powerwash if we are moving from less stable (higher version)
- // to more stable channel (lower version).
- return ToMoreStableChannel();
-}
-
-string OmahaRequestParams::GetAppId() const {
- return download_channel_ == "canary-channel" ? image_props_.canary_product_id
- : image_props_.product_id;
-}
-
-string OmahaRequestParams::GetDlcAppId(const std::string& dlc_id) const {
- // Create APP ID according to |dlc_id| (sticking the current AppID to the
- // DLC module ID with an underscode).
- return GetAppId() + "_" + dlc_id;
-}
-
-bool OmahaRequestParams::IsDlcAppId(const std::string& app_id) const {
- return dlc_apps_params().find(app_id) != dlc_apps_params().end();
-}
-
-bool OmahaRequestParams::GetDlcId(const string& app_id, string* dlc_id) const {
- auto itr = dlc_apps_params_.find(app_id);
- if (itr == dlc_apps_params_.end())
- return false;
- *dlc_id = itr->second.name;
- return true;
-}
-
-void OmahaRequestParams::SetDlcNoUpdate(const string& app_id) {
- auto itr = dlc_apps_params_.find(app_id);
- if (itr == dlc_apps_params_.end())
- return;
- itr->second.updated = false;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_request_params.h b/cros/omaha_request_params.h
deleted file mode 100644
index fd4c2e23..00000000
--- a/cros/omaha_request_params.h
+++ /dev/null
@@ -1,418 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_OMAHA_REQUEST_PARAMS_H_
-#define UPDATE_ENGINE_CROS_OMAHA_REQUEST_PARAMS_H_
-
-#include <stdint.h>
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include <base/macros.h>
-#include <base/time/time.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/cros/image_properties.h"
-#include "update_engine/update_manager/policy.h"
-
-// This gathers local system information and prepares info used by the
-// Omaha request action.
-
-namespace chromeos_update_engine {
-
-// This class encapsulates the data Omaha gets for the request, along with
-// essential state needed for the processing of the request/response. The
-// strings in this struct should not be XML escaped.
-//
-// TODO(jaysri): chromium-os:39752 tracks the need to rename this class to
-// reflect its lifetime more appropriately.
-class OmahaRequestParams {
- public:
- OmahaRequestParams()
- : os_platform_(constants::kOmahaPlatformName),
- os_version_(kOsVersion),
- delta_okay_(true),
- interactive_(false),
- rollback_allowed_(false),
- rollback_data_save_requested_(false),
- wall_clock_based_wait_enabled_(false),
- update_check_count_wait_enabled_(false),
- min_update_checks_needed_(kDefaultMinUpdateChecks),
- max_update_checks_allowed_(kDefaultMaxUpdateChecks),
- is_install_(false) {}
-
- virtual ~OmahaRequestParams();
-
- enum ActiveCountingType {
- kDayBased = 0,
- kDateBased,
- };
-
- struct AppParams {
- ActiveCountingType active_counting_type;
- // |name| is only used for DLCs to store the DLC ID.
- std::string name;
- int64_t ping_active;
- int64_t ping_date_last_active;
- int64_t ping_date_last_rollcall;
- bool send_ping;
- // |updated| is only used for DLCs to decide sending DBus message to
- // dlcservice on an install/update completion.
- bool updated = true;
- };
-
- // Setters and getters for the various properties.
- inline std::string os_platform() const { return os_platform_; }
- inline std::string os_version() const { return os_version_; }
- inline std::string os_sp() const { return os_sp_; }
- inline std::string os_board() const { return image_props_.board; }
- inline std::string os_build_fingerprint() const {
- return image_props_.build_fingerprint;
- }
- inline std::string os_build_type() const { return image_props_.build_type; }
- inline std::string board_app_id() const { return image_props_.product_id; }
- inline std::string canary_app_id() const {
- return image_props_.canary_product_id;
- }
- inline void set_app_id(const std::string& app_id) {
- image_props_.product_id = app_id;
- image_props_.canary_product_id = app_id;
- }
- inline std::string app_lang() const { return app_lang_; }
- inline std::string hwid() const { return hwid_; }
- inline std::string device_requisition() const { return device_requisition_; }
-
- inline void set_app_version(const std::string& version) {
- image_props_.version = version;
- }
- inline std::string app_version() const { return image_props_.version; }
- inline std::string product_components() const {
- return image_props_.product_components;
- }
- inline void set_product_components(const std::string& product_components) {
- image_props_.product_components = product_components;
- }
-
- inline std::string current_channel() const {
- return image_props_.current_channel;
- }
- inline std::string target_channel() const {
- return mutable_image_props_.target_channel;
- }
- inline std::string download_channel() const { return download_channel_; }
-
- // Can client accept a delta ?
- inline void set_delta_okay(bool ok) { delta_okay_ = ok; }
- inline bool delta_okay() const { return delta_okay_; }
-
- // True if this is a user-initiated update check.
- inline void set_interactive(bool interactive) { interactive_ = interactive; }
- inline bool interactive() const { return interactive_; }
-
- inline void set_update_url(const std::string& url) { update_url_ = url; }
- inline std::string update_url() const { return update_url_; }
-
- inline void set_target_version_prefix(const std::string& prefix) {
- target_version_prefix_ = prefix;
- }
-
- inline std::string target_version_prefix() const {
- 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;
- }
-
- inline bool rollback_allowed() const { return rollback_allowed_; }
-
- inline void set_rollback_data_save_requested(
- bool rollback_data_save_requested) {
- rollback_data_save_requested_ = rollback_data_save_requested;
- }
-
- inline bool rollback_data_save_requested() const {
- return rollback_data_save_requested_;
- }
-
- inline void set_rollback_allowed_milestones(int rollback_allowed_milestones) {
- rollback_allowed_milestones_ = rollback_allowed_milestones;
- }
-
- inline int rollback_allowed_milestones() const {
- return rollback_allowed_milestones_;
- }
-
- inline void set_wall_clock_based_wait_enabled(bool enabled) {
- wall_clock_based_wait_enabled_ = enabled;
- }
- inline bool wall_clock_based_wait_enabled() const {
- return wall_clock_based_wait_enabled_;
- }
-
- inline void set_waiting_period(base::TimeDelta period) {
- waiting_period_ = period;
- }
- base::TimeDelta waiting_period() const { return waiting_period_; }
-
- inline void set_update_check_count_wait_enabled(bool enabled) {
- update_check_count_wait_enabled_ = enabled;
- }
-
- inline bool update_check_count_wait_enabled() const {
- return update_check_count_wait_enabled_;
- }
-
- inline void set_min_update_checks_needed(int64_t min) {
- min_update_checks_needed_ = min;
- }
- inline int64_t min_update_checks_needed() const {
- return min_update_checks_needed_;
- }
-
- inline void set_max_update_checks_allowed(int64_t max) {
- max_update_checks_allowed_ = max;
- }
- inline int64_t max_update_checks_allowed() const {
- return max_update_checks_allowed_;
- }
- inline void set_dlc_apps_params(
- const std::map<std::string, AppParams>& dlc_apps_params) {
- dlc_apps_params_ = dlc_apps_params;
- }
- inline const std::map<std::string, AppParams>& dlc_apps_params() const {
- return dlc_apps_params_;
- }
- inline void set_is_install(bool is_install) { is_install_ = is_install; }
- inline bool is_install() const { return is_install_; }
-
- inline void set_autoupdate_token(const std::string& token) {
- autoupdate_token_ = token;
- }
- inline const std::string& autoupdate_token() const {
- return autoupdate_token_;
- }
-
- // Returns the App ID corresponding to the current value of the
- // download channel.
- virtual std::string GetAppId() const;
-
- // Returns the DLC app ID.
- virtual std::string GetDlcAppId(const std::string& dlc_id) const;
-
- // Returns true if the App ID is a DLC App ID that is currently part of the
- // request parameters.
- virtual bool IsDlcAppId(const std::string& app_id) const;
-
- // Returns the DLC App ID if the given App ID is a DLC that is currently part
- // of the request parameters.
- virtual bool GetDlcId(const std::string& app_id, std::string* dlc_id) const;
-
- // If the App ID is a DLC App ID will set to no update.
- void SetDlcNoUpdate(const std::string& app_id);
-
- // Suggested defaults
- static const char kOsVersion[];
- static const int64_t kDefaultMinUpdateChecks = 0;
- static const int64_t kDefaultMaxUpdateChecks = 8;
-
- // Initializes all the data in the object. Non-empty
- // |in_app_version| or |in_update_url| prevents automatic detection
- // of the parameter. Returns true on success, false otherwise.
- bool Init(const std::string& in_app_version,
- const std::string& in_update_url,
- const chromeos_update_manager::UpdateCheckParams& params);
-
- // Permanently changes the release channel to |channel|. Performs a
- // powerwash, if required and allowed.
- // Returns true on success, false otherwise. Note: This call will fail if
- // there's a channel change pending already. This is to serialize all the
- // channel changes done by the user in order to avoid having to solve
- // numerous edge cases around ensuring the powerwash happens as intended in
- // all such cases.
- virtual bool SetTargetChannel(const std::string& channel,
- bool is_powerwash_allowed,
- std::string* error_message);
-
- // Updates the download channel for this particular attempt from the current
- // value of target channel. This method takes a "snapshot" of the current
- // value of target channel and uses it for all subsequent Omaha requests for
- // this attempt (i.e. initial request as well as download progress/error
- // event requests). The snapshot will be updated only when either this method
- // or Init is called again.
- virtual void UpdateDownloadChannel();
-
- // Returns whether we should powerwash for this update. Note that this is
- // just an indication, the final decision to powerwash or not is made in the
- // response handler.
- bool ShouldPowerwash() const;
-
- // Check if the provided update URL is official, meaning either the default
- // autoupdate server or the autoupdate autotest server.
- virtual bool IsUpdateUrlOfficial() const;
-
- // For unit-tests.
- void set_root(const std::string& root);
- void set_current_channel(const std::string& channel) {
- image_props_.current_channel = channel;
- }
- void set_target_channel(const std::string& channel) {
- mutable_image_props_.target_channel = channel;
- }
- void set_os_sp(const std::string& os_sp) { os_sp_ = os_sp; }
- void set_os_board(const std::string& os_board) {
- image_props_.board = os_board;
- }
- void set_app_lang(const std::string& app_lang) { app_lang_ = app_lang; }
- void set_hwid(const std::string& hwid) { hwid_ = hwid; }
- void set_is_powerwash_allowed(bool powerwash_allowed) {
- mutable_image_props_.is_powerwash_allowed = powerwash_allowed;
- }
- bool is_powerwash_allowed() {
- return mutable_image_props_.is_powerwash_allowed;
- }
-
- void set_device_requisition(const std::string& requisition) {
- device_requisition_ = requisition;
- }
-
- private:
- FRIEND_TEST(OmahaRequestParamsTest, ChannelIndexTest);
- FRIEND_TEST(OmahaRequestParamsTest, IsValidChannelTest);
- FRIEND_TEST(OmahaRequestParamsTest, SetIsPowerwashAllowedTest);
- FRIEND_TEST(OmahaRequestParamsTest, SetTargetChannelInvalidTest);
- FRIEND_TEST(OmahaRequestParamsTest, SetTargetChannelTest);
- FRIEND_TEST(OmahaRequestParamsTest, ShouldPowerwashTest);
- FRIEND_TEST(OmahaRequestParamsTest, ToMoreStableChannelFlagTest);
-
- // Returns true if |channel| is a valid channel, otherwise write error to
- // |error_message| if passed and return false.
- bool IsValidChannel(const std::string& channel,
- std::string* error_message) const;
- bool IsValidChannel(const std::string& channel) const {
- return IsValidChannel(channel, nullptr);
- }
-
- // Returns the index of the given channel.
- int GetChannelIndex(const std::string& channel) const;
-
- // True if we're trying to update to a more stable channel.
- // i.e. index(target_channel) > index(current_channel).
- bool ToMoreStableChannel() const;
-
- // Gets the machine type (e.g. "i686").
- std::string GetMachineType() const;
-
- // The system image properties.
- ImageProperties image_props_;
- MutableImageProperties mutable_image_props_;
-
- // Basic properties of the OS and Application that go into the Omaha request.
- std::string os_platform_;
- std::string os_version_;
- std::string os_sp_;
- std::string app_lang_;
-
- // There are three channel values we deal with:
- // * The channel we got the image we are running from or "current channel"
- // stored in |image_props_.current_channel|.
- //
- // * The release channel we are tracking, where we should get updates from,
- // stored in |mutable_image_props_.target_channel|. This channel is
- // normally the same as the current_channel, except when the user changes
- // the channel. In that case it'll have the release channel the user
- // switched to, regardless of whether we downloaded an update from that
- // channel or not, or if we are in the middle of a download from a
- // previously selected channel (as opposed to download channel
- // which gets updated only at the start of next download).
- //
- // * The channel from which we're downloading the payload. This should
- // normally be the same as target channel. But if the user made another
- // channel change after we started the download, then they'd be different,
- // in which case, we'd detect elsewhere that the target channel has been
- // 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
- // TODO(b:133324571) tracks removal of this field once it is no longer
- // needed in AU requests. Remove by October 1st 2019.
- std::string device_requisition_; // Chrome OS Requisition type.
- bool delta_okay_; // If this client can accept a delta
- bool interactive_; // Whether this is a user-initiated update check
-
- // The URL to send the Omaha request to.
- std::string update_url_;
-
- // Prefix of the target OS version that the enterprise wants this device
- // to be pinned to. It's empty otherwise.
- std::string target_version_prefix_;
-
- // Whether the client is accepting rollback images too.
- bool rollback_allowed_;
-
- // Whether rollbacks should preserve some system state during powerwash.
- bool rollback_data_save_requested_;
-
- // How many milestones the client can rollback to.
- int rollback_allowed_milestones_;
-
- // True if scattering or staging are enabled, in which case waiting_period_
- // specifies the amount of absolute time that we've to wait for before sending
- // a request to Omaha.
- bool wall_clock_based_wait_enabled_;
- base::TimeDelta waiting_period_;
-
- // True if scattering or staging are enabled to denote the number of update
- // checks we've to skip before we can send a request to Omaha. The min and max
- // values establish the bounds for a random number to be chosen within that
- // range to enable such a wait.
- bool update_check_count_wait_enabled_;
- int64_t min_update_checks_needed_;
- int64_t max_update_checks_allowed_;
-
- // When reading files, prepend root_ to the paths. Useful for testing.
- std::string root_;
-
- // A list of DLC modules to install. A mapping from DLC App ID to |AppParams|.
- std::map<std::string, AppParams> dlc_apps_params_;
-
- // This variable defines whether the payload is being installed in the current
- // partition. At the moment, this is used for installing DLC modules on the
- // current active partition instead of the inactive partition.
- bool is_install_;
-
- // Token used when making an update request for a specific build.
- // For example: Token for a Quick Fix Build:
- // https://cloud.google.com/docs/chrome-enterprise/policies/?policy=DeviceQuickFixBuildToken
- std::string autoupdate_token_;
-
- DISALLOW_COPY_AND_ASSIGN(OmahaRequestParams);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_OMAHA_REQUEST_PARAMS_H_
diff --git a/cros/omaha_request_params_unittest.cc b/cros/omaha_request_params_unittest.cc
deleted file mode 100644
index 2d67ec09..00000000
--- a/cros/omaha_request_params_unittest.cc
+++ /dev/null
@@ -1,294 +0,0 @@
-//
-// Copyright (C) 2011 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/cros/omaha_request_params.h"
-
-#include <stdio.h>
-
-#include <string>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/fake_system_state.h"
-
-using chromeos_update_engine::test_utils::WriteFileString;
-using std::string;
-
-namespace chromeos_update_engine {
-
-class OmahaRequestParamsTest : public ::testing::Test {
- public:
- OmahaRequestParamsTest() : params_() {}
-
- protected:
- void SetUp() override {
- // Create a uniquely named test directory.
- ASSERT_TRUE(tempdir_.CreateUniqueTempDir());
- params_.set_root(tempdir_.GetPath().value());
- FakeSystemState::CreateInstance();
- SetLockDown(false);
- }
-
- void SetLockDown(bool locked_down) {
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(locked_down);
- FakeSystemState::Get()->fake_hardware()->SetIsNormalBootMode(locked_down);
- }
-
- OmahaRequestParams params_;
- base::ScopedTempDir tempdir_;
-};
-
-namespace {
-string GetMachineType() {
- string machine_type;
- if (!utils::ReadPipe("uname -m", &machine_type))
- return "";
- // Strip anything from the first newline char.
- size_t newline_pos = machine_type.find('\n');
- if (newline_pos != string::npos)
- machine_type.erase(newline_pos);
- return machine_type;
-}
-} // namespace
-
-TEST_F(OmahaRequestParamsTest, MissingChannelTest) {
- EXPECT_TRUE(params_.Init("", "", {}));
- // By default, if no channel is set, we should track the stable-channel.
- EXPECT_EQ("stable-channel", params_.target_channel());
-}
-
-TEST_F(OmahaRequestParamsTest, ForceVersionTest) {
- EXPECT_TRUE(params_.Init("ForcedVersion", "", {}));
- EXPECT_EQ(string("ForcedVersion_") + GetMachineType(), params_.os_sp());
- EXPECT_EQ("ForcedVersion", params_.app_version());
-}
-
-TEST_F(OmahaRequestParamsTest, ForcedURLTest) {
- EXPECT_TRUE(params_.Init("", "http://forced.google.com", {}));
- EXPECT_EQ("http://forced.google.com", params_.update_url());
-}
-
-TEST_F(OmahaRequestParamsTest, MissingURLTest) {
- EXPECT_TRUE(params_.Init("", "", {}));
- EXPECT_EQ(constants::kOmahaDefaultProductionURL, params_.update_url());
-}
-
-TEST_F(OmahaRequestParamsTest, DeltaOKTest) {
- EXPECT_TRUE(params_.Init("", "", {}));
- EXPECT_TRUE(params_.delta_okay());
-}
-
-TEST_F(OmahaRequestParamsTest, NoDeltasTest) {
- ASSERT_TRUE(
- WriteFileString(tempdir_.GetPath().Append(".nodelta").value(), ""));
- EXPECT_TRUE(params_.Init("", "", {}));
- EXPECT_FALSE(params_.delta_okay());
-}
-
-TEST_F(OmahaRequestParamsTest, SetTargetChannelTest) {
- {
- OmahaRequestParams params;
- params.set_root(tempdir_.GetPath().value());
- EXPECT_TRUE(params.Init("", "", {}));
- EXPECT_TRUE(params.SetTargetChannel("canary-channel", false, nullptr));
- EXPECT_FALSE(params.mutable_image_props_.is_powerwash_allowed);
- }
- params_.set_root(tempdir_.GetPath().value());
- EXPECT_TRUE(params_.Init("", "", {}));
- EXPECT_EQ("canary-channel", params_.target_channel());
- EXPECT_FALSE(params_.mutable_image_props_.is_powerwash_allowed);
-}
-
-TEST_F(OmahaRequestParamsTest, SetIsPowerwashAllowedTest) {
- {
- OmahaRequestParams params;
- params.set_root(tempdir_.GetPath().value());
- EXPECT_TRUE(params.Init("", "", {}));
- EXPECT_TRUE(params.SetTargetChannel("canary-channel", true, nullptr));
- EXPECT_TRUE(params.mutable_image_props_.is_powerwash_allowed);
- }
- params_.set_root(tempdir_.GetPath().value());
- EXPECT_TRUE(params_.Init("", "", {}));
- EXPECT_EQ("canary-channel", params_.target_channel());
- EXPECT_TRUE(params_.mutable_image_props_.is_powerwash_allowed);
-}
-
-TEST_F(OmahaRequestParamsTest, SetTargetChannelInvalidTest) {
- {
- OmahaRequestParams params;
- params.set_root(tempdir_.GetPath().value());
- SetLockDown(true);
- EXPECT_TRUE(params.Init("", "", {}));
- params.image_props_.allow_arbitrary_channels = false;
- string error_message;
- EXPECT_FALSE(
- params.SetTargetChannel("dogfood-channel", true, &error_message));
- // The error message should include a message about the valid channels.
- EXPECT_NE(string::npos, error_message.find("stable-channel"));
- EXPECT_FALSE(params.mutable_image_props_.is_powerwash_allowed);
- }
- params_.set_root(tempdir_.GetPath().value());
- EXPECT_TRUE(params_.Init("", "", {}));
- EXPECT_EQ("stable-channel", params_.target_channel());
- EXPECT_FALSE(params_.mutable_image_props_.is_powerwash_allowed);
-}
-
-TEST_F(OmahaRequestParamsTest, IsValidChannelTest) {
- EXPECT_TRUE(params_.IsValidChannel("canary-channel"));
- EXPECT_TRUE(params_.IsValidChannel("stable-channel"));
- EXPECT_TRUE(params_.IsValidChannel("beta-channel"));
- EXPECT_TRUE(params_.IsValidChannel("dev-channel"));
- EXPECT_FALSE(params_.IsValidChannel("testimage-channel"));
- EXPECT_FALSE(params_.IsValidChannel("dogfood-channel"));
- EXPECT_FALSE(params_.IsValidChannel("some-channel"));
- EXPECT_FALSE(params_.IsValidChannel(""));
- params_.image_props_.allow_arbitrary_channels = true;
- EXPECT_TRUE(params_.IsValidChannel("some-channel"));
- EXPECT_FALSE(params_.IsValidChannel("wrong-suffix"));
- EXPECT_FALSE(params_.IsValidChannel(""));
-}
-
-TEST_F(OmahaRequestParamsTest, SetTargetChannelWorks) {
- params_.set_target_channel("dev-channel");
- EXPECT_EQ("dev-channel", params_.target_channel());
-
- // When an invalid value is set, it should be ignored.
- EXPECT_FALSE(params_.SetTargetChannel("invalid-channel", false, nullptr));
- EXPECT_EQ("dev-channel", params_.target_channel());
-
- // When set to a valid value, it should take effect.
- EXPECT_TRUE(params_.SetTargetChannel("beta-channel", true, nullptr));
- EXPECT_EQ("beta-channel", params_.target_channel());
-
- // When set to the same value, it should be idempotent.
- EXPECT_TRUE(params_.SetTargetChannel("beta-channel", true, nullptr));
- EXPECT_EQ("beta-channel", params_.target_channel());
-
- // When set to a valid value while a change is already pending, it should
- // succeed.
- EXPECT_TRUE(params_.SetTargetChannel("stable-channel", true, nullptr));
- EXPECT_EQ("stable-channel", params_.target_channel());
-
- // Set a different channel in mutable_image_props_.
- params_.set_target_channel("stable-channel");
-
- // When set to a valid value while a change is already pending, it should
- // succeed.
- params_.Init("", "", {});
- EXPECT_TRUE(params_.SetTargetChannel("beta-channel", true, nullptr));
- // The target channel should reflect the change, but the download channel
- // should continue to retain the old value ...
- EXPECT_EQ("beta-channel", params_.target_channel());
- EXPECT_EQ("stable-channel", params_.download_channel());
-
- // ... until we update the download channel explicitly.
- params_.UpdateDownloadChannel();
- EXPECT_EQ("beta-channel", params_.download_channel());
- EXPECT_EQ("beta-channel", params_.target_channel());
-}
-
-TEST_F(OmahaRequestParamsTest, ChannelIndexTest) {
- int canary = params_.GetChannelIndex("canary-channel");
- int dev = params_.GetChannelIndex("dev-channel");
- int beta = params_.GetChannelIndex("beta-channel");
- int stable = params_.GetChannelIndex("stable-channel");
- EXPECT_LE(canary, dev);
- EXPECT_LE(dev, beta);
- EXPECT_LE(beta, stable);
-
- // testimage-channel or other names are not recognized, so index will be -1.
- int testimage = params_.GetChannelIndex("testimage-channel");
- int bogus = params_.GetChannelIndex("bogus-channel");
- EXPECT_EQ(-1, testimage);
- EXPECT_EQ(-1, bogus);
-}
-
-TEST_F(OmahaRequestParamsTest, ToMoreStableChannelFlagTest) {
- params_.image_props_.current_channel = "canary-channel";
- params_.download_channel_ = "stable-channel";
- EXPECT_TRUE(params_.ToMoreStableChannel());
- params_.image_props_.current_channel = "stable-channel";
- EXPECT_FALSE(params_.ToMoreStableChannel());
- params_.download_channel_ = "beta-channel";
- EXPECT_FALSE(params_.ToMoreStableChannel());
-}
-
-TEST_F(OmahaRequestParamsTest, TargetChannelHintTest) {
- EXPECT_TRUE(params_.Init("", "", {}));
- 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());
- params_.mutable_image_props_.is_powerwash_allowed = true;
- params_.image_props_.allow_arbitrary_channels = true;
- params_.image_props_.current_channel = "foo-channel";
- params_.download_channel_ = "bar-channel";
- EXPECT_TRUE(params_.ShouldPowerwash());
- params_.image_props_.allow_arbitrary_channels = false;
- params_.image_props_.current_channel = "canary-channel";
- params_.download_channel_ = "stable-channel";
- EXPECT_TRUE(params_.ShouldPowerwash());
-}
-
-TEST_F(OmahaRequestParamsTest, RequisitionIsSetTest) {
- EXPECT_TRUE(params_.Init("", "", {}));
- EXPECT_EQ("fake_requisition", params_.device_requisition());
-}
-
-TEST_F(OmahaRequestParamsTest, GetMissingDlcId) {
- EXPECT_TRUE(params_.Init("", "", {}));
-
- string dlc_id;
- EXPECT_FALSE(params_.GetDlcId("some-dlc-app-id", &dlc_id));
-}
-
-TEST_F(OmahaRequestParamsTest, GetDlcId) {
- EXPECT_TRUE(params_.Init("", "", {}));
- const string kExpectedDlcId = "test-dlc";
- const string dlc_app_id = params_.GetDlcAppId(kExpectedDlcId);
- params_.set_dlc_apps_params({{dlc_app_id, {.name = kExpectedDlcId}}});
-
- string dlc_id;
- EXPECT_TRUE(params_.GetDlcId(dlc_app_id, &dlc_id));
- EXPECT_EQ(kExpectedDlcId, dlc_id);
-}
-
-TEST_F(OmahaRequestParamsTest, GetDlcAppId) {
- EXPECT_TRUE(params_.Init("", "", {}));
- const string kAppId = "test-app-id";
- params_.set_app_id(kAppId);
- const string kDlcId = "test-dlc";
- const string expected_dlc_app_id = kAppId + "_" + kDlcId;
-
- EXPECT_EQ(expected_dlc_app_id, params_.GetDlcAppId(kDlcId));
-}
-
-TEST_F(OmahaRequestParamsTest, AutoUpdateTokenTest) {
- EXPECT_TRUE(params_.Init("", "", {.quick_fix_build_token = "foo-token"}));
- EXPECT_EQ("foo-token", params_.autoupdate_token());
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_response.h b/cros/omaha_response.h
deleted file mode 100644
index 3b07745a..00000000
--- a/cros/omaha_response.h
+++ /dev/null
@@ -1,123 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_OMAHA_RESPONSE_H_
-#define UPDATE_ENGINE_CROS_OMAHA_RESPONSE_H_
-
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <limits>
-#include <string>
-#include <vector>
-
-namespace chromeos_update_engine {
-
-// This struct encapsulates the data Omaha's response for the request.
-// The strings in this struct are not XML escaped.
-struct OmahaResponse {
- // True iff there is an update to be downloaded.
- bool update_exists = false;
-
- // If non-zero, server-dictated poll interval in seconds.
- int poll_interval = 0;
-
- // These are only valid if update_exists is true:
- std::string version;
-
- struct Package {
- // The ordered list of URLs in the Omaha response. Each item is a complete
- // URL (i.e. in terms of Omaha XML, each value is a urlBase + packageName)
- std::vector<std::string> payload_urls;
- uint64_t size = 0;
- uint64_t metadata_size = 0;
- std::string metadata_signature;
- std::string hash;
- // True if the payload described in this response is a delta payload.
- // False if it's a full payload.
- bool is_delta = false;
- // 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;
- // The unique fingerprint value associated with the package.
- std::string fp;
- };
- std::vector<Package> packages;
-
- std::string more_info_url;
- std::string deadline;
- int max_days_to_scatter = 0;
- // The number of URL-related failures to tolerate before moving on to the
- // next URL in the current pass. This is a configurable value from the
- // Omaha Response attribute, if ever we need to fine tune the behavior.
- uint32_t max_failure_count_per_url = 0;
- bool prompt = false;
-
- // True if the Omaha rule instructs us to disable the back-off logic
- // on the client altogether. False otherwise.
- bool disable_payload_backoff = false;
-
- // True if the Omaha rule instructs us to disable p2p for downloading.
- bool disable_p2p_for_downloading = false;
-
- // True if the Omaha rule instructs us to disable p2p for sharing.
- bool disable_p2p_for_sharing = false;
-
- // True if the Omaha rule instructs us to powerwash.
- bool powerwash_required = false;
-
- // If not blank, a base-64 encoded representation of the PEM-encoded
- // public key in the response.
- std::string public_key_rsa;
-
- // If not -1, the number of days since the epoch Jan 1, 2007 0:00
- // PST, according to the Omaha Server's clock and timezone (PST8PDT,
- // aka "Pacific Time".)
- int install_date_days = -1;
-
- // True if the returned image is a rollback for the device.
- bool is_rollback = false;
-
- struct RollbackKeyVersion {
- // Kernel key version. 0xffff if the value is unknown.
- uint16_t kernel_key = std::numeric_limits<uint16_t>::max();
- // Kernel version. 0xffff if the value is unknown.
- uint16_t kernel = std::numeric_limits<uint16_t>::max();
- // Firmware key verison. 0xffff if the value is unknown.
- uint16_t firmware_key = std::numeric_limits<uint16_t>::max();
- // Firmware version. 0xffff if the value is unknown.
- uint16_t firmware = std::numeric_limits<uint16_t>::max();
- };
-
- // Key versions of the returned rollback image. Values are 0xffff if the
- // image not a rollback, or the fields were not present.
- RollbackKeyVersion rollback_key_version;
-
- // Key versions of the N - rollback_allowed_milestones release. For example,
- // if the current version is 70 and rollback_allowed_milestones is 4, this
- // will contain the key versions of version 66. This is used to ensure that
- // the kernel and firmware keys are at most those of v66 so that v66 can be
- // rolled back to.
- RollbackKeyVersion past_rollback_key_version;
-};
-static_assert(sizeof(off_t) == 8, "off_t not 64 bit");
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_OMAHA_RESPONSE_H_
diff --git a/cros/omaha_response_handler_action.cc b/cros/omaha_response_handler_action.cc
deleted file mode 100644
index 04cae3e1..00000000
--- a/cros/omaha_response_handler_action.cc
+++ /dev/null
@@ -1,339 +0,0 @@
-//
-// Copyright (C) 2011 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/cros/omaha_response_handler_action.h"
-
-#include <limits>
-#include <string>
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/version.h>
-#include <policy/device_policy.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/prefs_interface.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/connection_manager_interface.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/payload_state_interface.h"
-#include "update_engine/payload_consumer/delta_performer.h"
-#include "update_engine/update_manager/policy.h"
-#include "update_engine/update_manager/update_manager.h"
-
-using chromeos_update_manager::kRollforwardInfinity;
-using chromeos_update_manager::Policy;
-using chromeos_update_manager::UpdateManager;
-using std::numeric_limits;
-using std::string;
-
-namespace chromeos_update_engine {
-
-OmahaResponseHandlerAction::OmahaResponseHandlerAction()
- : deadline_file_(constants::kOmahaResponseDeadlineFile) {}
-
-void OmahaResponseHandlerAction::PerformAction() {
- CHECK(HasInputObject());
- ScopedActionCompleter completer(processor_, this);
- const OmahaResponse& response = GetInputObject();
- if (!response.update_exists) {
- LOG(INFO) << "There are no updates. Aborting.";
- completer.set_code(ErrorCode::kNoUpdate);
- return;
- }
-
- // All decisions as to which URL should be used have already been done. So,
- // make the current URL as the download URL.
- string current_url = SystemState::Get()->payload_state()->GetCurrentUrl();
- if (current_url.empty()) {
- // This shouldn't happen as we should always supply the HTTPS backup URL.
- // Handling this anyway, just in case.
- LOG(ERROR) << "There are no suitable URLs in the response to use.";
- completer.set_code(ErrorCode::kOmahaResponseInvalid);
- return;
- }
-
- // This is the url to the first package, not all packages.
- // (For updates): All |Action|s prior to this must pass in non-excluded URLs
- // within the |OmahaResponse|, reference exlusion logic in
- // |OmahaRequestAction| and keep the enforcement of exclusions for updates.
- install_plan_.download_url = current_url;
- install_plan_.version = response.version;
-
- OmahaRequestParams* const params = SystemState::Get()->request_params();
- PayloadStateInterface* const payload_state =
- SystemState::Get()->payload_state();
-
- // If we're using p2p to download and there is a local peer, use it.
- if (payload_state->GetUsingP2PForDownloading() &&
- !payload_state->GetP2PUrl().empty()) {
- LOG(INFO) << "Replacing URL " << install_plan_.download_url
- << " with local URL " << payload_state->GetP2PUrl()
- << " since p2p is enabled.";
- install_plan_.download_url = payload_state->GetP2PUrl();
- payload_state->SetUsingP2PForDownloading(true);
- }
-
- // Fill up the other properties based on the response.
- string update_check_response_hash;
- for (const auto& package : response.packages) {
- brillo::Blob raw_hash;
- if (!base::HexStringToBytes(package.hash, &raw_hash)) {
- LOG(ERROR) << "Failed to convert payload hash from hex string to bytes: "
- << package.hash;
- completer.set_code(ErrorCode::kOmahaResponseInvalid);
- return;
- }
- install_plan_.payloads.push_back(
- {.payload_urls = package.payload_urls,
- .size = package.size,
- .metadata_size = package.metadata_size,
- .metadata_signature = package.metadata_signature,
- .hash = raw_hash,
- .type = package.is_delta ? InstallPayloadType::kDelta
- : InstallPayloadType::kFull,
- .fp = package.fp,
- .app_id = package.app_id});
- update_check_response_hash += package.hash + ":";
- }
- install_plan_.public_key_rsa = response.public_key_rsa;
- install_plan_.hash_checks_mandatory = AreHashChecksMandatory(response);
- install_plan_.is_resume = DeltaPerformer::CanResumeUpdate(
- SystemState::Get()->prefs(), update_check_response_hash);
- if (install_plan_.is_resume) {
- payload_state->UpdateResumed();
- } else {
- payload_state->UpdateRestarted();
- LOG_IF(WARNING,
- !DeltaPerformer::ResetUpdateProgress(SystemState::Get()->prefs(),
- false))
- << "Unable to reset the update progress.";
- LOG_IF(WARNING,
- !SystemState::Get()->prefs()->SetString(
- kPrefsUpdateCheckResponseHash, update_check_response_hash))
- << "Unable to save the update check response hash.";
- }
-
- if (params->is_install()) {
- install_plan_.target_slot =
- SystemState::Get()->boot_control()->GetCurrentSlot();
- install_plan_.source_slot = BootControlInterface::kInvalidSlot;
- } else {
- install_plan_.source_slot =
- SystemState::Get()->boot_control()->GetCurrentSlot();
- install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0;
- }
-
- // The Omaha response doesn't include the channel name for this image, so we
- // use the download_channel we used during the request to tag the target slot.
- // This will be used in the next boot to know the channel the image was
- // downloaded from.
- string current_channel_key =
- kPrefsChannelOnSlotPrefix + std::to_string(install_plan_.target_slot);
- SystemState::Get()->prefs()->SetString(current_channel_key,
- params->download_channel());
-
- // Checking whether device is able to boot up the returned rollback image.
- if (response.is_rollback) {
- if (!params->rollback_allowed()) {
- LOG(ERROR) << "Received rollback image but rollback is not allowed.";
- completer.set_code(ErrorCode::kOmahaResponseInvalid);
- return;
- }
-
- // Calculate the values on the version values on current device.
- auto min_kernel_key_version = static_cast<uint32_t>(
- SystemState::Get()->hardware()->GetMinKernelKeyVersion());
- auto min_firmware_key_version = static_cast<uint32_t>(
- SystemState::Get()->hardware()->GetMinFirmwareKeyVersion());
-
- uint32_t kernel_key_version =
- static_cast<uint32_t>(response.rollback_key_version.kernel_key) << 16 |
- static_cast<uint32_t>(response.rollback_key_version.kernel);
- uint32_t firmware_key_version =
- static_cast<uint32_t>(response.rollback_key_version.firmware_key)
- << 16 |
- static_cast<uint32_t>(response.rollback_key_version.firmware);
-
- LOG(INFO) << "Rollback image versions:"
- << " device_kernel_key_version=" << min_kernel_key_version
- << " image_kernel_key_version=" << kernel_key_version
- << " device_firmware_key_version=" << min_firmware_key_version
- << " image_firmware_key_version=" << firmware_key_version;
-
- // Don't attempt a rollback if the versions are incompatible or the
- // target image does not specify the version information.
- if (kernel_key_version == numeric_limits<uint32_t>::max() ||
- firmware_key_version == numeric_limits<uint32_t>::max() ||
- kernel_key_version < min_kernel_key_version ||
- firmware_key_version < min_firmware_key_version) {
- LOG(ERROR) << "Device won't be able to boot up the rollback image.";
- completer.set_code(ErrorCode::kRollbackNotPossible);
- return;
- }
- install_plan_.is_rollback = true;
- install_plan_.rollback_data_save_requested =
- params->rollback_data_save_requested();
- }
-
- // Powerwash if either the response requires it or the parameters indicated
- // powerwash (usually because there was a channel downgrade) and we are
- // downgrading the version. Enterprise rollback, indicated by
- // |response.is_rollback| is dealt with separately above.
- if (response.powerwash_required) {
- install_plan_.powerwash_required = true;
- } else if (params->ShouldPowerwash() && !response.is_rollback) {
- base::Version new_version(response.version);
- base::Version current_version(params->app_version());
-
- if (!new_version.IsValid()) {
- LOG(WARNING) << "Not powerwashing,"
- << " the update's version number is unreadable."
- << " Update's version number: " << response.version;
- } else if (!current_version.IsValid()) {
- LOG(WARNING) << "Not powerwashing,"
- << " the current version number is unreadable."
- << " Current version number: " << params->app_version();
- } else if (new_version < current_version) {
- install_plan_.powerwash_required = true;
- // Always try to preserve enrollment and wifi data for enrolled devices.
- install_plan_.rollback_data_save_requested =
- SystemState::Get()->device_policy() &&
- SystemState::Get()->device_policy()->IsEnterpriseEnrolled();
- }
- }
-
- TEST_AND_RETURN(HasOutputPipe());
- if (HasOutputPipe())
- SetOutputObject(install_plan_);
- install_plan_.Dump();
-
- // Send the deadline data (if any) to Chrome through a file. This is a pretty
- // hacky solution but should be OK for now.
- //
- // TODO(petkov): Re-architect this to avoid communication through a
- // file. Ideally, we would include this information in D-Bus's GetStatus
- // method and UpdateStatus signal. A potential issue is that update_engine may
- // be unresponsive during an update download.
- if (!deadline_file_.empty()) {
- if (payload_state->GetRollbackHappened()) {
- // Don't do forced update if rollback has happened since the last update
- // check where policy was present.
- LOG(INFO) << "Not forcing update because a rollback happened.";
- utils::WriteFile(deadline_file_.c_str(), nullptr, 0);
- } else {
- utils::WriteFile(deadline_file_.c_str(),
- response.deadline.data(),
- response.deadline.size());
- }
- chmod(deadline_file_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- }
-
- // Check the generated install-plan with the Policy to confirm that
- // it can be applied at this time (or at all).
- UpdateManager* const update_manager = SystemState::Get()->update_manager();
- CHECK(update_manager);
- auto ec = ErrorCode::kSuccess;
- update_manager->PolicyRequest(
- &Policy::UpdateCanBeApplied, &ec, &install_plan_);
- completer.set_code(ec);
-
- const auto allowed_milestones = params->rollback_allowed_milestones();
- if (allowed_milestones > 0) {
- auto max_firmware_rollforward = numeric_limits<uint32_t>::max();
- auto max_kernel_rollforward = numeric_limits<uint32_t>::max();
-
- // Determine the version to update the max rollforward verified boot
- // value.
- OmahaResponse::RollbackKeyVersion version =
- response.past_rollback_key_version;
-
- // Determine the max rollforward values to be set in the TPM.
- max_firmware_rollforward = static_cast<uint32_t>(version.firmware_key)
- << 16 |
- static_cast<uint32_t>(version.firmware);
- max_kernel_rollforward = static_cast<uint32_t>(version.kernel_key) << 16 |
- static_cast<uint32_t>(version.kernel);
-
- // In the case that the value is 0xffffffff, log a warning because the
- // device should not be installing a rollback image without having version
- // information.
- if (max_firmware_rollforward == numeric_limits<uint32_t>::max() ||
- max_kernel_rollforward == numeric_limits<uint32_t>::max()) {
- LOG(WARNING)
- << "Max rollforward values were not sent in rollback response: "
- << " max_kernel_rollforward=" << max_kernel_rollforward
- << " max_firmware_rollforward=" << max_firmware_rollforward
- << " rollback_allowed_milestones="
- << params->rollback_allowed_milestones();
- } else {
- LOG(INFO) << "Setting the max rollforward values: "
- << " max_kernel_rollforward=" << max_kernel_rollforward
- << " max_firmware_rollforward=" << max_firmware_rollforward
- << " rollback_allowed_milestones="
- << params->rollback_allowed_milestones();
- SystemState::Get()->hardware()->SetMaxKernelKeyRollforward(
- max_kernel_rollforward);
- // TODO(crbug/783998): Set max firmware rollforward when implemented.
- }
- } else {
- LOG(INFO) << "Rollback is not allowed. Setting max rollforward values"
- << " to infinity";
- // When rollback is not allowed, explicitly set the max roll forward to
- // infinity.
- SystemState::Get()->hardware()->SetMaxKernelKeyRollforward(
- kRollforwardInfinity);
- // TODO(crbug/783998): Set max firmware rollforward when implemented.
- }
-}
-
-bool OmahaResponseHandlerAction::AreHashChecksMandatory(
- const OmahaResponse& response) {
- // We sometimes need to waive the hash checks in order to download from
- // sources that don't provide hashes, such as dev server.
- // At this point UpdateAttempter::IsAnyUpdateSourceAllowed() has already been
- // checked, so an unofficial update URL won't get this far unless it's OK to
- // use without a hash. Additionally, we want to always waive hash checks on
- // unofficial builds (i.e. dev/test images).
- // The end result is this:
- // * Base image:
- // - Official URLs require a hash.
- // - Unofficial URLs only get this far if the IsAnyUpdateSourceAllowed()
- // devmode/debugd checks pass, in which case the hash is waived.
- // * Dev/test image:
- // - Any URL is allowed through with no hash checking.
- if (!SystemState::Get()->request_params()->IsUpdateUrlOfficial() ||
- !SystemState::Get()->hardware()->IsOfficialBuild()) {
- // Still do a hash check if a public key is included.
- if (!response.public_key_rsa.empty()) {
- // The autoupdate_CatchBadSignatures test checks for this string
- // in log-files. Keep in sync.
- LOG(INFO) << "Mandating payload hash checks since Omaha Response "
- << "for unofficial build includes public RSA key.";
- return true;
- } else {
- LOG(INFO) << "Waiving payload hash checks for unofficial update URL.";
- return false;
- }
- }
-
- LOG(INFO) << "Mandating hash checks for official URL on official build.";
- return true;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_response_handler_action.h b/cros/omaha_response_handler_action.h
deleted file mode 100644
index 9842c942..00000000
--- a/cros/omaha_response_handler_action.h
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-// Copyright (C) 2011 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_CROS_OMAHA_RESPONSE_HANDLER_ACTION_H_
-#define UPDATE_ENGINE_CROS_OMAHA_RESPONSE_HANDLER_ACTION_H_
-
-#include <string>
-
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-#include "update_engine/common/action.h"
-#include "update_engine/cros/omaha_request_action.h"
-#include "update_engine/payload_consumer/install_plan.h"
-
-// This class reads in an Omaha response and converts what it sees into
-// an install plan which is passed out.
-
-namespace chromeos_update_engine {
-
-class OmahaResponseHandlerAction;
-
-template <>
-class ActionTraits<OmahaResponseHandlerAction> {
- public:
- typedef OmahaResponse InputObjectType;
- typedef InstallPlan OutputObjectType;
-};
-
-class OmahaResponseHandlerAction : public Action<OmahaResponseHandlerAction> {
- public:
- OmahaResponseHandlerAction();
-
- typedef ActionTraits<OmahaResponseHandlerAction>::InputObjectType
- InputObjectType;
- typedef ActionTraits<OmahaResponseHandlerAction>::OutputObjectType
- OutputObjectType;
- void PerformAction() override;
-
- // This is a synchronous action, and thus TerminateProcessing() should
- // never be called
- void TerminateProcessing() override { CHECK(false); }
-
- const InstallPlan& install_plan() const { return install_plan_; }
-
- // Debugging/logging
- static std::string StaticType() { return "OmahaResponseHandlerAction"; }
- std::string Type() const override { return StaticType(); }
-
- private:
- // Returns true if payload hash checks are mandatory based on the state
- // of the system and the contents of the Omaha response. False otherwise.
- bool AreHashChecksMandatory(const OmahaResponse& response);
-
- // The install plan, if we have an update.
- InstallPlan install_plan_;
-
- // File used for communication deadline to Chrome.
- std::string deadline_file_;
-
- friend class OmahaResponseHandlerActionTest;
- friend class OmahaResponseHandlerActionProcessorDelegate;
- FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventResumedTest);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackFailure);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackFailure);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackSuccess);
- FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedNotRollback);
- FRIEND_TEST(UpdateAttempterTest, SetRollbackHappenedRollback);
- FRIEND_TEST(UpdateAttempterTest, UpdateDeferredByPolicyTest);
-
- DISALLOW_COPY_AND_ASSIGN(OmahaResponseHandlerAction);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_OMAHA_RESPONSE_HANDLER_ACTION_H_
diff --git a/cros/omaha_response_handler_action_unittest.cc b/cros/omaha_response_handler_action_unittest.cc
deleted file mode 100644
index c9b46b15..00000000
--- a/cros/omaha_response_handler_action_unittest.cc
+++ /dev/null
@@ -1,1022 +0,0 @@
-//
-// Copyright (C) 2011 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/cros/omaha_response_handler_action.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/cros/mock_payload_state.h"
-#include "update_engine/payload_consumer/payload_constants.h"
-#include "update_engine/update_manager/mock_policy.h"
-
-using chromeos_update_engine::test_utils::System;
-using chromeos_update_engine::test_utils::WriteFileString;
-using chromeos_update_manager::EvalStatus;
-using chromeos_update_manager::FakeUpdateManager;
-using chromeos_update_manager::kRollforwardInfinity;
-using chromeos_update_manager::MockPolicy;
-using std::string;
-using testing::_;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace chromeos_update_engine {
-
-class OmahaResponseHandlerActionProcessorDelegate
- : public ActionProcessorDelegate {
- public:
- OmahaResponseHandlerActionProcessorDelegate()
- : code_(ErrorCode::kError), code_set_(false) {}
- void ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) {
- if (action->Type() == OmahaResponseHandlerAction::StaticType()) {
- auto response_handler_action =
- static_cast<OmahaResponseHandlerAction*>(action);
- code_ = code;
- code_set_ = true;
- response_handler_action_install_plan_.reset(
- new InstallPlan(response_handler_action->install_plan_));
- } else if (action->Type() ==
- ObjectCollectorAction<InstallPlan>::StaticType()) {
- auto collector_action =
- static_cast<ObjectCollectorAction<InstallPlan>*>(action);
- collector_action_install_plan_.reset(
- new InstallPlan(collector_action->object()));
- }
- }
- ErrorCode code_;
- bool code_set_;
- std::unique_ptr<InstallPlan> collector_action_install_plan_;
- std::unique_ptr<InstallPlan> response_handler_action_install_plan_;
-};
-
-class OmahaResponseHandlerActionTest : public ::testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
- // Enable MockPrefs;
- FakeSystemState::Get()->set_prefs(nullptr);
- FakeBootControl* fake_boot_control =
- FakeSystemState::Get()->fake_boot_control();
- fake_boot_control->SetPartitionDevice(kPartitionNameKernel, 0, "/dev/sdz2");
- fake_boot_control->SetPartitionDevice(kPartitionNameRoot, 0, "/dev/sdz3");
- fake_boot_control->SetPartitionDevice(kPartitionNameKernel, 1, "/dev/sdz4");
- fake_boot_control->SetPartitionDevice(kPartitionNameRoot, 1, "/dev/sdz5");
- }
-
- // Return true iff the OmahaResponseHandlerAction succeeded.
- // If out is non-null, it's set w/ the response from the action.
- bool DoTest(const OmahaResponse& in,
- const string& deadline_file,
- InstallPlan* out);
-
- // Delegate passed to the ActionProcessor.
- OmahaResponseHandlerActionProcessorDelegate delegate_;
-
- // Captures the action's result code, for tests that need to directly verify
- // it in non-success cases.
- ErrorCode action_result_code_;
-
- // "Hash+"
- const brillo::Blob expected_hash_ = {0x48, 0x61, 0x73, 0x68, 0x2b};
-};
-
-namespace {
-const char* const kLongName =
- "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
- "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
- "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
- "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
- "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
- "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
- "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
- "-the_update_a.b.c.d_DELTA_.tgz";
-const char* const kBadVersion = "don't update me";
-const char* const kPayloadHashHex = "486173682b";
-const char* const kPayloadFp1 = "1.755aff78ec73dfc7f590893ac";
-const char* const kPayloadFp2 = "1.98ba213e0ccec0d0e8cdc74a5";
-const char* const kPayloadAppId = "test_app_id";
-} // namespace
-
-bool OmahaResponseHandlerActionTest::DoTest(const OmahaResponse& in,
- const string& test_deadline_file,
- InstallPlan* out) {
- brillo::FakeMessageLoop loop(nullptr);
- loop.SetAsCurrent();
- ActionProcessor processor;
- processor.set_delegate(&delegate_);
-
- auto feeder_action = std::make_unique<ObjectFeederAction<OmahaResponse>>();
- feeder_action->set_obj(in);
- if (in.update_exists && in.version != kBadVersion) {
- string expected_hash;
- for (const auto& package : in.packages)
- expected_hash += package.hash + ":";
- EXPECT_CALL(*(FakeSystemState::Get()->mock_prefs()),
- SetString(kPrefsUpdateCheckResponseHash, expected_hash))
- .WillOnce(Return(true));
-
- int slot =
- FakeSystemState::Get()->request_params()->is_install()
- ? FakeSystemState::Get()->fake_boot_control()->GetCurrentSlot()
- : 1 - FakeSystemState::Get()->fake_boot_control()->GetCurrentSlot();
- string key = kPrefsChannelOnSlotPrefix + std::to_string(slot);
- EXPECT_CALL(*(FakeSystemState::Get()->mock_prefs()),
- SetString(key, testing::_))
- .WillOnce(Return(true));
- }
-
- string current_url = in.packages.size() ? in.packages[0].payload_urls[0] : "";
- EXPECT_CALL(*(FakeSystemState::Get()->mock_payload_state()), GetCurrentUrl())
- .WillRepeatedly(Return(current_url));
-
- auto response_handler_action = std::make_unique<OmahaResponseHandlerAction>();
- if (!test_deadline_file.empty())
- response_handler_action->deadline_file_ = test_deadline_file;
-
- auto collector_action =
- std::make_unique<ObjectCollectorAction<InstallPlan>>();
-
- BondActions(feeder_action.get(), response_handler_action.get());
- BondActions(response_handler_action.get(), collector_action.get());
- processor.EnqueueAction(std::move(feeder_action));
- processor.EnqueueAction(std::move(response_handler_action));
- processor.EnqueueAction(std::move(collector_action));
- processor.StartProcessing();
- EXPECT_TRUE(!processor.IsRunning())
- << "Update test to handle non-async actions";
-
- if (out && delegate_.collector_action_install_plan_)
- *out = *delegate_.collector_action_install_plan_;
-
- EXPECT_TRUE(delegate_.code_set_);
- action_result_code_ = delegate_.code_;
- return delegate_.code_ == ErrorCode::kSuccess;
-}
-
-TEST_F(OmahaResponseHandlerActionTest, SimpleTest) {
- ScopedTempFile test_deadline_file(
- "omaha_response_handler_action_unittest-XXXXXX");
- {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"http://foo/the_update_a.b.c.d.tgz"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- in.prompt = false;
- in.deadline = "20101020";
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(1U, install_plan.target_slot);
- string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
- EXPECT_EQ("20101020", deadline);
- struct stat deadline_stat;
- EXPECT_EQ(0, stat(test_deadline_file.path().c_str(), &deadline_stat));
- EXPECT_EQ(
- static_cast<mode_t>(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH),
- deadline_stat.st_mode);
- EXPECT_EQ(in.version, install_plan.version);
- }
- {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"http://foo/the_update_a.b.c.d.tgz"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- in.prompt = true;
- InstallPlan install_plan;
- // Set the other slot as current.
- FakeSystemState::Get()->fake_boot_control()->SetCurrentSlot(1);
- EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(0U, install_plan.target_slot);
- string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline) &&
- deadline.empty());
- EXPECT_EQ(in.version, install_plan.version);
- }
- {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back({.payload_urls = {kLongName},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- in.prompt = true;
- in.deadline = "some-deadline";
- InstallPlan install_plan;
- FakeSystemState::Get()->fake_boot_control()->SetCurrentSlot(0);
- // Because rollback happened, the deadline shouldn't be written into the
- // file.
- EXPECT_CALL(*(FakeSystemState::Get()->mock_payload_state()),
- GetRollbackHappened())
- .WillOnce(Return(true));
- EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(1U, install_plan.target_slot);
- string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
- EXPECT_TRUE(deadline.empty());
- EXPECT_EQ(in.version, install_plan.version);
- }
- {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back({.payload_urls = {kLongName},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- in.prompt = true;
- in.deadline = "some-deadline";
- InstallPlan install_plan;
- FakeSystemState::Get()->fake_boot_control()->SetCurrentSlot(0);
- EXPECT_CALL(*(FakeSystemState::Get()->mock_payload_state()),
- GetRollbackHappened())
- .WillOnce(Return(false));
- EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(1U, install_plan.target_slot);
- string deadline;
- EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
- EXPECT_EQ("some-deadline", deadline);
- EXPECT_EQ(in.version, install_plan.version);
- }
-}
-
-TEST_F(OmahaResponseHandlerActionTest, NoUpdatesTest) {
- OmahaResponse in;
- in.update_exists = false;
- InstallPlan install_plan;
- EXPECT_FALSE(DoTest(in, "", &install_plan));
- EXPECT_TRUE(install_plan.partitions.empty());
-}
-
-TEST_F(OmahaResponseHandlerActionTest, InstallTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {kLongName}, .size = 1, .hash = kPayloadHashHex});
- in.packages.push_back(
- {.payload_urls = {kLongName}, .size = 2, .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- OmahaRequestParams params;
- params.set_is_install(true);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(install_plan.source_slot, UINT_MAX);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, MultiPackageTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back({.payload_urls = {"http://package/1"},
- .size = 1,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.packages.push_back({.payload_urls = {"http://package/2"},
- .size = 2,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp2});
- in.more_info_url = "http://more/info";
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(2u, install_plan.payloads.size());
- EXPECT_EQ(in.packages[0].size, install_plan.payloads[0].size);
- EXPECT_EQ(in.packages[1].size, install_plan.payloads[1].size);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(expected_hash_, install_plan.payloads[1].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[1].app_id, install_plan.payloads[1].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(in.packages[1].fp, install_plan.payloads[1].fp);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, HashChecksForHttpTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"http://test.should/need/hash.checks.signed"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- // Hash checks are always skipped for non-official update URLs.
- EXPECT_CALL(*(FakeSystemState::Get()->mock_request_params()),
- IsUpdateUrlOfficial())
- .WillRepeatedly(Return(true));
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_TRUE(install_plan.hash_checks_mandatory);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, HashChecksForUnofficialUpdateUrl) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"http://url.normally/needs/hash.checks.signed"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- EXPECT_CALL(*(FakeSystemState::Get()->mock_request_params()),
- IsUpdateUrlOfficial())
- .WillRepeatedly(Return(false));
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_FALSE(install_plan.hash_checks_mandatory);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-TEST_F(OmahaResponseHandlerActionTest,
- HashChecksForOfficialUrlUnofficialBuildTest) {
- // Official URLs for unofficial builds (dev/test images) don't require hash.
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"http://url.normally/needs/hash.checks.signed"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- EXPECT_CALL(*(FakeSystemState::Get()->mock_request_params()),
- IsUpdateUrlOfficial())
- .WillRepeatedly(Return(true));
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(false);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_FALSE(install_plan.hash_checks_mandatory);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, HashChecksForHttpsTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"https://test.should/need/hash.checks.signed"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- EXPECT_CALL(*(FakeSystemState::Get()->mock_request_params()),
- IsUpdateUrlOfficial())
- .WillRepeatedly(Return(true));
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_TRUE(install_plan.hash_checks_mandatory);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, HashChecksForBothHttpAndHttpsTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"http://test.should.still/need/hash.checks",
- "https://test.should.still/need/hash.checks"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
- EXPECT_CALL(*(FakeSystemState::Get()->mock_request_params()),
- IsUpdateUrlOfficial())
- .WillRepeatedly(Return(true));
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_TRUE(install_plan.hash_checks_mandatory);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToMoreStableVersionAndChannelTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "1.0.0.0";
- in.packages.push_back({.payload_urls = {"https://MoreStableChannelTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(false);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("canary-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("2.0.0.0");
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_TRUE(install_plan.powerwash_required);
-}
-
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToMoreStableVersionAndChannelPowerwashNotAllowedTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "1.0.0.0";
- in.packages.push_back({.payload_urls = {"https://MoreStableChannelTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(false);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("canary-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", false, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("2.0.0.0");
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_FALSE(install_plan.powerwash_required);
-}
-
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToMoreStableChannelButNewerVersionTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "12345.96.0.0";
- in.packages.push_back({.payload_urls = {"https://ChannelDownVersionUp"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(false);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("beta-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("12345.48.0.0");
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_FALSE(install_plan.powerwash_required);
-}
-
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToMoreStableChannelButSameVersionTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "12345.0.0.0";
- in.packages.push_back({.payload_urls = {"https://ChannelDownVersionUp"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(false);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("beta-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("12345.0.0.0");
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_FALSE(install_plan.powerwash_required);
- EXPECT_FALSE(install_plan.rollback_data_save_requested);
-}
-
-// On an enrolled device, the rollback data restore should be attempted when
-// doing a powerwash and channel downgrade.
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToMoreStableChannelEnrolledDataRestore) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "12345.96.0.0";
- in.packages.push_back({.payload_urls = {"https://ChannelDownEnrolled"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(true);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("beta-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("12347.48.0.0");
-
- testing::NiceMock<policy::MockDevicePolicy> mock_device_policy;
- EXPECT_CALL(mock_device_policy, IsEnterpriseEnrolled())
- .WillOnce(Return(true));
- FakeSystemState::Get()->set_device_policy(&mock_device_policy);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_TRUE(install_plan.rollback_data_save_requested);
-}
-
-// Never attempt rollback data restore if the device is not enrolled.
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToMoreStableChannelUnenrolledNoDataRestore) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "12345.96.0.0";
- in.packages.push_back({.payload_urls = {"https://ChannelDownEnrolled"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(true);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("beta-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("12347.48.0.0");
-
- testing::NiceMock<policy::MockDevicePolicy> mock_device_policy;
- EXPECT_CALL(mock_device_policy, IsEnterpriseEnrolled())
- .WillOnce(Return(false));
- FakeSystemState::Get()->set_device_policy(&mock_device_policy);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_FALSE(install_plan.rollback_data_save_requested);
-}
-
-// Never attempt rollback data restore if powerwash is not allowed.
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToMoreStableChannelNoPowerwashNoDataRestore) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "12345.96.0.0";
- in.packages.push_back(
- {.payload_urls = {"https://URL"}, .size = 1, .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(true);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("beta-channel");
- EXPECT_TRUE(params.SetTargetChannel("stable-channel", false, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("12347.48.0.0");
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_FALSE(install_plan.rollback_data_save_requested);
-}
-
-TEST_F(OmahaResponseHandlerActionTest,
- ChangeToLessStableVersionAndChannelTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "2.0.0.0";
- in.packages.push_back({.payload_urls = {"https://LessStableChannelTest"},
- .size = 15,
- .hash = kPayloadHashHex});
- in.more_info_url = "http://more/info";
-
- // Create a uniquely named test directory.
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
-
- OmahaRequestParams params;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(false);
- params.set_root(tempdir.GetPath().value());
- params.set_current_channel("stable-channel");
- EXPECT_TRUE(params.SetTargetChannel("canary-channel", false, nullptr));
- params.UpdateDownloadChannel();
- params.set_app_version("1.0.0.0");
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_FALSE(install_plan.powerwash_required);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, P2PUrlIsUsedAndHashChecksMandatory) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back(
- {.payload_urls = {"https://would.not/cause/hash/checks"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.more_info_url = "http://more/info";
-
- OmahaRequestParams params;
- // We're using a real OmahaRequestParams object here so we can't mock
- // IsUpdateUrlOfficial(), but setting the update URL to the AutoUpdate test
- // server will cause IsUpdateUrlOfficial() to return true.
- params.set_update_url(constants::kOmahaDefaultAUTestURL);
- FakeSystemState::Get()->set_request_params(&params);
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- SetUsingP2PForDownloading(true));
-
- string p2p_url = "http://9.8.7.6/p2p";
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(), GetP2PUrl())
- .WillRepeatedly(Return(p2p_url));
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- GetUsingP2PForDownloading())
- .WillRepeatedly(Return(true));
-
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(p2p_url, install_plan.download_url);
- EXPECT_TRUE(install_plan.hash_checks_mandatory);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, RollbackTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.packages.push_back({.payload_urls = {"https://RollbackTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.is_rollback = true;
-
- // The rollback payload is 2 versions behind stable.
- in.rollback_key_version.kernel = 24;
- in.rollback_key_version.kernel = 23;
- in.rollback_key_version.firmware_key = 22;
- in.rollback_key_version.firmware = 21;
-
- OmahaResponse::RollbackKeyVersion m4;
- m4.firmware_key = 16;
- m4.firmware = 15;
- m4.kernel_key = 14;
- m4.kernel = 13;
-
- in.past_rollback_key_version = m4;
-
- FakeSystemState::Get()->fake_hardware()->SetMinKernelKeyVersion(0x00010002);
- FakeSystemState::Get()->fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
-
- FakeSystemState::Get()->fake_hardware()->SetMaxKernelKeyRollforward(
- 0xaaaaaaaa);
- // TODO(crbug/783998): Add support for firmware when implemented.
-
- OmahaRequestParams params;
- params.set_rollback_allowed(true);
- params.set_rollback_allowed_milestones(4);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_TRUE(install_plan.is_rollback);
-
- // The max rollforward should be set the values of the image
- // rollback_allowed_milestones (4 for this test) in the past.
- const uint32_t expected_max_kernel_rollforward =
- static_cast<uint32_t>(m4.kernel_key) << 16 |
- static_cast<uint32_t>(m4.kernel);
- EXPECT_EQ(
- expected_max_kernel_rollforward,
- FakeSystemState::Get()->fake_hardware()->GetMaxKernelKeyRollforward());
- // TODO(crbug/783998): Add support for firmware when implemented.
-}
-
-TEST_F(OmahaResponseHandlerActionTest, RollbackKernelVersionErrorTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.packages.push_back({.payload_urls = {"https://RollbackTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.is_rollback = true;
- in.rollback_key_version.kernel_key = 1;
- in.rollback_key_version.kernel = 1; // This is lower than the minimum.
- in.rollback_key_version.firmware_key = 3;
- in.rollback_key_version.firmware = 4;
-
- OmahaResponse::RollbackKeyVersion m4;
- m4.firmware_key = 16;
- m4.firmware = 15;
- m4.kernel_key = 14;
- m4.kernel = 13;
- in.past_rollback_key_version = m4;
-
- FakeSystemState::Get()->fake_hardware()->SetMinKernelKeyVersion(0x00010002);
- FakeSystemState::Get()->fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
- const uint32_t current_kernel_max_rollforward = 0xaaaaaaaa;
- FakeSystemState::Get()->fake_hardware()->SetMaxKernelKeyRollforward(
- current_kernel_max_rollforward);
-
- OmahaRequestParams params;
- params.set_rollback_allowed(true);
- params.set_rollback_allowed_milestones(4);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_FALSE(DoTest(in, "", &install_plan));
-
- // Max rollforward is not changed in error cases.
- EXPECT_EQ(
- current_kernel_max_rollforward,
- FakeSystemState::Get()->fake_hardware()->GetMaxKernelKeyRollforward());
- // TODO(crbug/783998): Add support for firmware when implemented.
-}
-
-TEST_F(OmahaResponseHandlerActionTest, RollbackFirmwareVersionErrorTest) {
- // TODO(crbug/783998): Add handling for max_firmware_rollforward when
- // implemented.
- OmahaResponse in;
- in.update_exists = true;
- in.packages.push_back({.payload_urls = {"https://RollbackTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.is_rollback = true;
- in.rollback_key_version.kernel_key = 1;
- in.rollback_key_version.kernel = 2;
- in.rollback_key_version.firmware_key = 3;
- in.rollback_key_version.firmware = 3; // This is lower than the minimum.
-
- FakeSystemState::Get()->fake_hardware()->SetMinKernelKeyVersion(0x00010002);
- FakeSystemState::Get()->fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
-
- OmahaRequestParams params;
- params.set_rollback_allowed(true);
- params.set_rollback_allowed_milestones(4);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_FALSE(DoTest(in, "", &install_plan));
-}
-
-TEST_F(OmahaResponseHandlerActionTest, RollbackNotRollbackTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.packages.push_back({.payload_urls = {"https://RollbackTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.is_rollback = false;
-
- const uint32_t current_kernel_max_rollforward = 0xaaaaaaaa;
- FakeSystemState::Get()->fake_hardware()->SetMaxKernelKeyRollforward(
- current_kernel_max_rollforward);
-
- OmahaRequestParams params;
- params.set_rollback_allowed(true);
- params.set_rollback_allowed_milestones(4);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_FALSE(install_plan.is_rollback);
-
- // Max rollforward is not changed for non-rollback cases.
- EXPECT_EQ(
- current_kernel_max_rollforward,
- FakeSystemState::Get()->fake_hardware()->GetMaxKernelKeyRollforward());
- // TODO(crbug/783998): Add support for firmware when implemented.
-}
-
-TEST_F(OmahaResponseHandlerActionTest, RollbackNotAllowedTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.packages.push_back({.payload_urls = {"https://RollbackTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.is_rollback = true;
-
- OmahaRequestParams params;
- params.set_rollback_allowed(false);
- params.set_rollback_allowed_milestones(4);
-
- const uint32_t current_kernel_max_rollforward = 0xaaaaaaaa;
- FakeSystemState::Get()->fake_hardware()->SetMaxKernelKeyRollforward(
- current_kernel_max_rollforward);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_FALSE(DoTest(in, "", &install_plan));
-
- // This case generates an error so, do not update max rollforward.
- EXPECT_EQ(
- current_kernel_max_rollforward,
- FakeSystemState::Get()->fake_hardware()->GetMaxKernelKeyRollforward());
- // TODO(crbug/783998): Add support for firmware when implemented.
-}
-
-TEST_F(OmahaResponseHandlerActionTest, NormalUpdateWithZeroMilestonesAllowed) {
- OmahaResponse in;
- in.update_exists = true;
- in.packages.push_back({.payload_urls = {"https://RollbackTest"},
- .size = 1,
- .hash = kPayloadHashHex});
- in.is_rollback = false;
-
- OmahaRequestParams params;
- params.set_rollback_allowed(true);
- params.set_rollback_allowed_milestones(0);
-
- const uint32_t current_kernel_max_rollforward = 0xaaaaaaaa;
- FakeSystemState::Get()->fake_hardware()->SetMaxKernelKeyRollforward(
- current_kernel_max_rollforward);
-
- FakeSystemState::Get()->set_request_params(&params);
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
-
- // When allowed_milestones is 0, this is set to infinity.
- EXPECT_EQ(
- kRollforwardInfinity,
- FakeSystemState::Get()->fake_hardware()->GetMaxKernelKeyRollforward());
- // TODO(crbug/783998): Add support for firmware when implemented.
-}
-
-TEST_F(OmahaResponseHandlerActionTest, SystemVersionTest) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back({.payload_urls = {"http://package/1"},
- .size = 1,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- in.packages.push_back({.payload_urls = {"http://package/2"},
- .size = 2,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp2});
- in.more_info_url = "http://more/info";
- InstallPlan install_plan;
- EXPECT_TRUE(DoTest(in, "", &install_plan));
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(2u, install_plan.payloads.size());
- EXPECT_EQ(in.packages[0].size, install_plan.payloads[0].size);
- EXPECT_EQ(in.packages[1].size, install_plan.payloads[1].size);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(expected_hash_, install_plan.payloads[1].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[1].app_id, install_plan.payloads[1].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(in.packages[1].fp, install_plan.payloads[1].fp);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-TEST_F(OmahaResponseHandlerActionTest, TestDeferredByPolicy) {
- OmahaResponse in;
- in.update_exists = true;
- in.version = "a.b.c.d";
- in.packages.push_back({.payload_urls = {"http://foo/the_update_a.b.c.d.tgz"},
- .size = 12,
- .hash = kPayloadHashHex,
- .app_id = kPayloadAppId,
- .fp = kPayloadFp1});
- // Setup the UpdateManager to disallow the update.
- MockPolicy* mock_policy = new MockPolicy();
- FakeUpdateManager* fake_update_manager =
- FakeSystemState::Get()->fake_update_manager();
- fake_update_manager->set_policy(mock_policy);
- EXPECT_CALL(*mock_policy, UpdateCanBeApplied(_, _, _, _, _))
- .WillOnce(
- DoAll(SetArgPointee<3>(ErrorCode::kOmahaUpdateDeferredPerPolicy),
- Return(EvalStatus::kSucceeded)));
- // Perform the Action. It should "fail" with kOmahaUpdateDeferredPerPolicy.
- InstallPlan install_plan;
- EXPECT_FALSE(DoTest(in, "", &install_plan));
- EXPECT_EQ(ErrorCode::kOmahaUpdateDeferredPerPolicy, action_result_code_);
- // Verify that DoTest() didn't set the output install plan.
- EXPECT_EQ("", install_plan.version);
- // Now verify the InstallPlan that was generated.
- install_plan = *delegate_.response_handler_action_install_plan_;
- EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
- EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
- EXPECT_EQ(in.packages[0].app_id, install_plan.payloads[0].app_id);
- EXPECT_EQ(in.packages[0].fp, install_plan.payloads[0].fp);
- EXPECT_EQ(1U, install_plan.target_slot);
- EXPECT_EQ(in.version, install_plan.version);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_utils.cc b/cros/omaha_utils.cc
deleted file mode 100644
index fc05cb9b..00000000
--- a/cros/omaha_utils.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// Copyright (C) 2016 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/cros/omaha_utils.h"
-
-#include <base/logging.h>
-#include <base/strings/string_number_conversions.h>
-
-namespace chromeos_update_engine {
-
-const EolDate kEolDateInvalid = -9999;
-
-std::string EolDateToString(EolDate eol_date) {
- return base::NumberToString(eol_date);
-}
-
-EolDate StringToEolDate(const std::string& eol_date) {
- EolDate date = kEolDateInvalid;
- if (!base::StringToInt64(eol_date, &date))
- return kEolDateInvalid;
- return date;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/omaha_utils.h b/cros/omaha_utils.h
deleted file mode 100644
index 67416353..00000000
--- a/cros/omaha_utils.h
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// Copyright (C) 2016 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_CROS_OMAHA_UTILS_H_
-#define UPDATE_ENGINE_CROS_OMAHA_UTILS_H_
-
-#include <string>
-
-namespace chromeos_update_engine {
-
-using EolDate = int64_t;
-
-// |EolDate| indicating an invalid end-of-life date.
-extern const EolDate kEolDateInvalid;
-
-// Returns the string representation of the |eol_date|.
-std::string EolDateToString(EolDate eol_date);
-
-// Converts the end-of-life date string to an EolDate numeric value. In case
-// of an invalid string, the default |kEolDateInvalid| value will be used
-// instead.
-EolDate StringToEolDate(const std::string& eol_date);
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_OMAHA_UTILS_H_
diff --git a/cros/omaha_utils_unittest.cc b/cros/omaha_utils_unittest.cc
deleted file mode 100644
index f89f6902..00000000
--- a/cros/omaha_utils_unittest.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// Copyright (C) 2016 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/cros/omaha_utils.h"
-
-#include <gtest/gtest.h>
-#include <vector>
-
-namespace chromeos_update_engine {
-
-class OmahaUtilsTest : public ::testing::Test {};
-
-TEST(OmahaUtilsTest, EolDateTest) {
- // Supported values are converted back and forth properly.
- const std::vector<EolDate> tests = {kEolDateInvalid, -1, 0, 1};
- for (EolDate eol_date : tests) {
- EXPECT_EQ(eol_date, StringToEolDate(EolDateToString(eol_date)))
- << "The StringToEolDate() was " << EolDateToString(eol_date);
- }
-
- // Invalid values are assumed as "supported".
- EXPECT_EQ(kEolDateInvalid, StringToEolDate(""));
- EXPECT_EQ(kEolDateInvalid, StringToEolDate("hello, world!"));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/p2p_manager.cc b/cros/p2p_manager.cc
deleted file mode 100644
index 19e2600e..00000000
--- a/cros/p2p_manager.cc
+++ /dev/null
@@ -1,732 +0,0 @@
-//
-// Copyright (C) 2013 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.
-//
-
-// This provides access to timestamps with nanosecond resolution in
-// struct stat, See NOTES in stat(2) for details.
-#ifndef _DEFAULT_SOURCE
-#define _DEFAULT_SOURCE
-#endif
-#ifndef _BSD_SOURCE
-#define _BSD_SOURCE
-#endif
-
-#include "update_engine/cros/p2p_manager.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/falloc.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/types.h>
-#include <sys/xattr.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <map>
-#include <memory>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/files/file_enumerator.h>
-#include <base/files/file_path.h>
-#include <base/format_macros.h>
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-
-#include "update_engine/common/subprocess.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/update_manager/policy.h"
-#include "update_engine/update_manager/update_manager.h"
-
-using base::Bind;
-using base::Callback;
-using base::FilePath;
-using base::StringPrintf;
-using base::Time;
-using base::TimeDelta;
-using brillo::MessageLoop;
-using chromeos_update_manager::EvalStatus;
-using chromeos_update_manager::Policy;
-using chromeos_update_manager::UpdateManager;
-using std::pair;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-
-namespace chromeos_update_engine {
-
-namespace {
-
-// The default p2p directory.
-const char kDefaultP2PDir[] = "/var/cache/p2p";
-
-// The p2p xattr used for conveying the final size of a file - see the
-// p2p ddoc for details.
-const char kCrosP2PFileSizeXAttrName[] = "user.cros-p2p-filesize";
-
-} // namespace
-
-// The default P2PManager::Configuration implementation.
-class ConfigurationImpl : public P2PManager::Configuration {
- public:
- ConfigurationImpl() {}
-
- FilePath GetP2PDir() override { return FilePath(kDefaultP2PDir); }
-
- vector<string> GetInitctlArgs(bool is_start) override {
- vector<string> args;
- args.push_back("initctl");
- args.push_back(is_start ? "start" : "stop");
- args.push_back("p2p");
- return args;
- }
-
- vector<string> GetP2PClientArgs(const string& file_id,
- size_t minimum_size) override {
- vector<string> args;
- args.push_back("p2p-client");
- args.push_back(string("--get-url=") + file_id);
- args.push_back(StringPrintf("--minimum-size=%" PRIuS, minimum_size));
- return args;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConfigurationImpl);
-};
-
-// The default P2PManager implementation.
-class P2PManagerImpl : public P2PManager {
- public:
- P2PManagerImpl(Configuration* configuration,
- UpdateManager* update_manager,
- const string& file_extension,
- const int num_files_to_keep,
- const TimeDelta& max_file_age);
-
- // P2PManager methods.
- void SetDevicePolicy(const policy::DevicePolicy* device_policy) override;
- bool IsP2PEnabled() override;
- bool EnsureP2PRunning() override;
- bool EnsureP2PNotRunning() override;
- bool PerformHousekeeping() override;
- void LookupUrlForFile(const string& file_id,
- size_t minimum_size,
- TimeDelta max_time_to_wait,
- LookupCallback callback) override;
- bool FileShare(const string& file_id, size_t expected_size) override;
- FilePath FileGetPath(const string& file_id) override;
- ssize_t FileGetSize(const string& file_id) override;
- ssize_t FileGetExpectedSize(const string& file_id) override;
- bool FileGetVisible(const string& file_id, bool* out_result) override;
- bool FileMakeVisible(const string& file_id) override;
- int CountSharedFiles() override;
-
- private:
- // Enumeration for specifying visibility.
- enum Visibility { kVisible, kNonVisible };
-
- // Returns "." + |file_extension_| + ".p2p" if |visibility| is
- // |kVisible|. Returns the same concatenated with ".tmp" otherwise.
- string GetExt(Visibility visibility);
-
- // Gets the on-disk path for |file_id| depending on if the file
- // is visible or not.
- FilePath GetPath(const string& file_id, Visibility visibility);
-
- // Utility function used by EnsureP2PRunning() and EnsureP2PNotRunning().
- bool EnsureP2P(bool should_be_running);
-
- // Utility function to delete a file given by |path| and log the
- // path as well as |reason|. Returns false on failure.
- bool DeleteP2PFile(const FilePath& path, const string& reason);
-
- // Schedules an async request for tracking changes in P2P enabled status.
- void ScheduleEnabledStatusChange();
-
- // An async callback used by the above.
- void OnEnabledStatusChange(EvalStatus status, const bool& result);
-
- // The device policy being used or null if no policy is being used.
- const policy::DevicePolicy* device_policy_ = nullptr;
-
- // Configuration object.
- unique_ptr<Configuration> configuration_;
-
- // A pointer to the global Update Manager.
- UpdateManager* update_manager_;
-
- // A short string unique to the application (for example "cros_au")
- // used to mark a file as being owned by a particular application.
- const string file_extension_;
-
- // If non-zero, this number denotes how many files in /var/cache/p2p
- // owned by the application (cf. |file_extension_|) to keep after
- // performing housekeeping.
- const int num_files_to_keep_;
-
- // If non-zero, files older than this will not be kept after
- // performing housekeeping.
- const TimeDelta max_file_age_;
-
- // The string ".p2p".
- static const char kP2PExtension[];
-
- // The string ".tmp".
- static const char kTmpExtension[];
-
- // Whether P2P service may be running; initially, we assume it may be.
- bool may_be_running_ = true;
-
- // The current known enabled status of the P2P feature (initialized lazily),
- // and whether an async status check has been scheduled.
- bool is_enabled_;
- bool waiting_for_enabled_status_change_ = false;
-
- DISALLOW_COPY_AND_ASSIGN(P2PManagerImpl);
-};
-
-const char P2PManagerImpl::kP2PExtension[] = ".p2p";
-
-const char P2PManagerImpl::kTmpExtension[] = ".tmp";
-
-P2PManagerImpl::P2PManagerImpl(Configuration* configuration,
- UpdateManager* update_manager,
- const string& file_extension,
- const int num_files_to_keep,
- const TimeDelta& max_file_age)
- : update_manager_(update_manager),
- file_extension_(file_extension),
- num_files_to_keep_(num_files_to_keep),
- max_file_age_(max_file_age) {
- configuration_.reset(configuration != nullptr ? configuration
- : new ConfigurationImpl());
-}
-
-void P2PManagerImpl::SetDevicePolicy(
- const policy::DevicePolicy* device_policy) {
- device_policy_ = device_policy;
-}
-
-bool P2PManagerImpl::IsP2PEnabled() {
- if (!waiting_for_enabled_status_change_) {
- // Get and store an initial value.
- if (update_manager_->PolicyRequest(&Policy::P2PEnabled, &is_enabled_) ==
- EvalStatus::kFailed) {
- is_enabled_ = false;
- LOG(ERROR) << "Querying P2P enabled status failed, disabling.";
- }
-
- // Track future changes (async).
- ScheduleEnabledStatusChange();
- }
-
- return is_enabled_;
-}
-
-bool P2PManagerImpl::EnsureP2P(bool should_be_running) {
- int return_code = 0;
- string stderr;
-
- may_be_running_ = true; // Unless successful, we must be conservative.
-
- vector<string> args = configuration_->GetInitctlArgs(should_be_running);
- if (!Subprocess::SynchronousExec(args, &return_code, nullptr, &stderr)) {
- LOG(ERROR) << "Error spawning " << utils::StringVectorToString(args);
- return false;
- }
-
- // If initctl(8) does not exit normally (exit status other than zero), ensure
- // that the error message is not benign by scanning stderr; this is a
- // necessity because initctl does not offer actions such as "start if not
- // running" or "stop if running".
- // TODO(zeuthen,chromium:277051): Avoid doing this.
- if (return_code != 0) {
- const char* expected_error_message =
- should_be_running ? "initctl: Job is already running: p2p\n"
- : "initctl: Unknown instance \n";
- if (stderr != expected_error_message)
- return false;
- }
-
- may_be_running_ = should_be_running; // Successful after all.
- return true;
-}
-
-bool P2PManagerImpl::EnsureP2PRunning() {
- return EnsureP2P(true);
-}
-
-bool P2PManagerImpl::EnsureP2PNotRunning() {
- return EnsureP2P(false);
-}
-
-// Returns True if the timestamp in the first pair is greater than the
-// timestamp in the latter. If used with std::sort() this will yield a
-// sequence of elements where newer (high timestamps) elements precede
-// older ones (low timestamps).
-static bool MatchCompareFunc(const pair<FilePath, Time>& a,
- const pair<FilePath, Time>& b) {
- return a.second > b.second;
-}
-
-string P2PManagerImpl::GetExt(Visibility visibility) {
- string ext = string(".") + file_extension_ + kP2PExtension;
- switch (visibility) {
- case kVisible:
- break;
- case kNonVisible:
- ext += kTmpExtension;
- break;
- // Don't add a default case to let the compiler warn about newly
- // added enum values.
- }
- return ext;
-}
-
-FilePath P2PManagerImpl::GetPath(const string& file_id, Visibility visibility) {
- return configuration_->GetP2PDir().Append(file_id + GetExt(visibility));
-}
-
-bool P2PManagerImpl::DeleteP2PFile(const FilePath& path, const string& reason) {
- LOG(INFO) << "Deleting p2p file " << path.value() << " (reason: " << reason
- << ")";
- if (unlink(path.value().c_str()) != 0) {
- PLOG(ERROR) << "Error deleting p2p file " << path.value();
- return false;
- }
- return true;
-}
-
-bool P2PManagerImpl::PerformHousekeeping() {
- // Open p2p dir.
- FilePath p2p_dir = configuration_->GetP2PDir();
- const string ext_visible = GetExt(kVisible);
- const string ext_non_visible = GetExt(kNonVisible);
-
- bool deletion_failed = false;
- vector<pair<FilePath, Time>> matches;
-
- base::FileEnumerator dir(p2p_dir, false, base::FileEnumerator::FILES);
- // Go through all files and collect their mtime.
- for (FilePath name = dir.Next(); !name.empty(); name = dir.Next()) {
- if (!(base::EndsWith(
- name.value(), ext_visible, base::CompareCase::SENSITIVE) ||
- base::EndsWith(
- name.value(), ext_non_visible, base::CompareCase::SENSITIVE))) {
- continue;
- }
-
- Time time = dir.GetInfo().GetLastModifiedTime();
-
- // If instructed to keep only files younger than a given age
- // (|max_file_age_| != 0), delete files satisfying this criteria
- // right now. Otherwise add it to a list we'll consider for later.
- if (max_file_age_ != TimeDelta() &&
- SystemState::Get()->clock()->GetWallclockTime() - time >
- max_file_age_) {
- if (!DeleteP2PFile(name, "file too old"))
- deletion_failed = true;
- } else {
- matches.push_back(std::make_pair(name, time));
- }
- }
-
- // If instructed to only keep N files (|max_files_to_keep_ != 0),
- // sort list of matches, newest (biggest time) to oldest (lowest
- // time). Then delete starting at element |num_files_to_keep_|.
- if (num_files_to_keep_ > 0) {
- std::sort(matches.begin(), matches.end(), MatchCompareFunc);
- vector<pair<FilePath, Time>>::const_iterator i;
- for (i = matches.begin() + num_files_to_keep_; i < matches.end(); ++i) {
- if (!DeleteP2PFile(i->first, "too many files"))
- deletion_failed = true;
- }
- }
-
- return !deletion_failed;
-}
-
-// Helper class for implementing LookupUrlForFile().
-class LookupData {
- public:
- explicit LookupData(P2PManager::LookupCallback callback)
- : callback_(callback) {}
-
- ~LookupData() {
- if (timeout_task_ != MessageLoop::kTaskIdNull)
- MessageLoop::current()->CancelTask(timeout_task_);
- if (child_pid_)
- Subprocess::Get().KillExec(child_pid_);
- }
-
- void InitiateLookup(const vector<string>& cmd, TimeDelta timeout) {
- // NOTE: if we fail early (i.e. in this method), we need to schedule
- // an idle to report the error. This is because we guarantee that
- // the callback is always called from the message loop (this
- // guarantee is useful for testing).
-
- // We expect to run just "p2p-client" and find it in the path.
- child_pid_ = Subprocess::Get().ExecFlags(
- cmd,
- Subprocess::kSearchPath,
- {},
- Bind(&LookupData::OnLookupDone, base::Unretained(this)));
-
- if (!child_pid_) {
- LOG(ERROR) << "Error spawning " << utils::StringVectorToString(cmd);
- ReportErrorAndDeleteInIdle();
- return;
- }
-
- if (timeout > TimeDelta()) {
- timeout_task_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- Bind(&LookupData::OnTimeout, base::Unretained(this)),
- timeout);
- }
- }
-
- private:
- void ReportErrorAndDeleteInIdle() {
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind(&LookupData::OnIdleForReportErrorAndDelete,
- base::Unretained(this)));
- }
-
- void OnIdleForReportErrorAndDelete() {
- ReportError();
- delete this;
- }
-
- void IssueCallback(const string& url) {
- if (!callback_.is_null())
- callback_.Run(url);
- }
-
- void ReportError() {
- if (reported_)
- return;
- IssueCallback("");
- reported_ = true;
- }
-
- void ReportSuccess(const string& output) {
- if (reported_)
- return;
- string url = output;
- size_t newline_pos = url.find('\n');
- if (newline_pos != string::npos)
- url.resize(newline_pos);
-
- // Since p2p-client(1) is constructing this URL itself strictly
- // speaking there's no need to validate it... but, anyway, can't
- // hurt.
- if (url.compare(0, 7, "http://") == 0) {
- IssueCallback(url);
- } else {
- LOG(ERROR) << "p2p URL '" << url << "' does not look right. Ignoring.";
- ReportError();
- }
- reported_ = true;
- }
-
- void OnLookupDone(int return_code, const string& output) {
- child_pid_ = 0;
- if (return_code != 0) {
- LOG(INFO) << "Child exited with non-zero exit code " << return_code;
- ReportError();
- } else {
- ReportSuccess(output);
- }
- delete this;
- }
-
- void OnTimeout() {
- timeout_task_ = MessageLoop::kTaskIdNull;
- ReportError();
- delete this;
- }
-
- P2PManager::LookupCallback callback_;
-
- // The Subprocess tag of the running process. A value of 0 means that the
- // process is not running.
- pid_t child_pid_{0};
-
- // The timeout task_id we are waiting on, if any.
- MessageLoop::TaskId timeout_task_{MessageLoop::kTaskIdNull};
-
- bool reported_{false};
-};
-
-void P2PManagerImpl::LookupUrlForFile(const string& file_id,
- size_t minimum_size,
- TimeDelta max_time_to_wait,
- LookupCallback callback) {
- LookupData* lookup_data = new LookupData(callback);
- string file_id_with_ext = file_id + "." + file_extension_;
- vector<string> args =
- configuration_->GetP2PClientArgs(file_id_with_ext, minimum_size);
- lookup_data->InitiateLookup(args, max_time_to_wait);
-}
-
-bool P2PManagerImpl::FileShare(const string& file_id, size_t expected_size) {
- // Check if file already exist.
- FilePath path = FileGetPath(file_id);
- if (!path.empty()) {
- // File exists - double check its expected size though.
- ssize_t file_expected_size = FileGetExpectedSize(file_id);
- if (file_expected_size == -1 ||
- static_cast<size_t>(file_expected_size) != expected_size) {
- LOG(ERROR) << "Existing p2p file " << path.value()
- << " with expected_size=" << file_expected_size
- << " does not match the passed in"
- << " expected_size=" << expected_size;
- return false;
- }
- return true;
- }
-
- // Before creating the file, bail if statvfs(3) indicates that at
- // least twice the size is not available in P2P_DIR.
- struct statvfs statvfsbuf;
- FilePath p2p_dir = configuration_->GetP2PDir();
- if (statvfs(p2p_dir.value().c_str(), &statvfsbuf) != 0) {
- PLOG(ERROR) << "Error calling statvfs() for dir " << p2p_dir.value();
- return false;
- }
- size_t free_bytes =
- static_cast<size_t>(statvfsbuf.f_bsize) * statvfsbuf.f_bavail;
- if (free_bytes < 2 * expected_size) {
- // This can easily happen and is worth reporting.
- LOG(INFO) << "Refusing to allocate p2p file of " << expected_size
- << " bytes since the directory " << p2p_dir.value()
- << " only has " << free_bytes
- << " bytes available and this is less than twice the"
- << " requested size.";
- return false;
- }
-
- // Okie-dokey looks like enough space is available - create the file.
- path = GetPath(file_id, kNonVisible);
- int fd = open(path.value().c_str(), O_CREAT | O_RDWR, 0644);
- if (fd == -1) {
- PLOG(ERROR) << "Error creating file with path " << path.value();
- return false;
- }
- ScopedFdCloser fd_closer(&fd);
-
- // If the final size is known, allocate the file (e.g. reserve disk
- // space) and set the user.cros-p2p-filesize xattr.
- if (expected_size != 0) {
- if (fallocate(fd,
- FALLOC_FL_KEEP_SIZE, // Keep file size as 0.
- 0,
- expected_size) != 0) {
- if (errno == ENOSYS || errno == EOPNOTSUPP) {
- // If the filesystem doesn't support the fallocate, keep
- // going. This is helpful when running unit tests on build
- // machines with ancient filesystems and/or OSes.
- PLOG(WARNING) << "Ignoring fallocate(2) failure";
- } else {
- // ENOSPC can happen (funky race though, cf. the statvfs() check
- // above), handle it gracefully, e.g. use logging level INFO.
- PLOG(INFO) << "Error allocating " << expected_size << " bytes for file "
- << path.value();
- if (unlink(path.value().c_str()) != 0) {
- PLOG(ERROR) << "Error deleting file with path " << path.value();
- }
- return false;
- }
- }
-
- string decimal_size = std::to_string(expected_size);
- if (fsetxattr(fd,
- kCrosP2PFileSizeXAttrName,
- decimal_size.c_str(),
- decimal_size.size(),
- 0) != 0) {
- PLOG(ERROR) << "Error setting xattr " << path.value();
- return false;
- }
- }
-
- return true;
-}
-
-FilePath P2PManagerImpl::FileGetPath(const string& file_id) {
- struct stat statbuf;
- FilePath path;
-
- path = GetPath(file_id, kVisible);
- if (stat(path.value().c_str(), &statbuf) == 0) {
- return path;
- }
-
- path = GetPath(file_id, kNonVisible);
- if (stat(path.value().c_str(), &statbuf) == 0) {
- return path;
- }
-
- path.clear();
- return path;
-}
-
-bool P2PManagerImpl::FileGetVisible(const string& file_id, bool* out_result) {
- FilePath path = FileGetPath(file_id);
- if (path.empty()) {
- LOG(ERROR) << "No file for id " << file_id;
- return false;
- }
- if (out_result != nullptr)
- *out_result = path.MatchesExtension(kP2PExtension);
- return true;
-}
-
-bool P2PManagerImpl::FileMakeVisible(const string& file_id) {
- FilePath path = FileGetPath(file_id);
- if (path.empty()) {
- LOG(ERROR) << "No file for id " << file_id;
- return false;
- }
-
- // Already visible?
- if (path.MatchesExtension(kP2PExtension))
- return true;
-
- LOG_ASSERT(path.MatchesExtension(kTmpExtension));
- FilePath new_path = path.RemoveExtension();
- LOG_ASSERT(new_path.MatchesExtension(kP2PExtension));
- if (rename(path.value().c_str(), new_path.value().c_str()) != 0) {
- PLOG(ERROR) << "Error renaming " << path.value() << " to "
- << new_path.value();
- return false;
- }
-
- return true;
-}
-
-ssize_t P2PManagerImpl::FileGetSize(const string& file_id) {
- FilePath path = FileGetPath(file_id);
- if (path.empty())
- return -1;
-
- return utils::FileSize(path.value());
-}
-
-ssize_t P2PManagerImpl::FileGetExpectedSize(const string& file_id) {
- FilePath path = FileGetPath(file_id);
- if (path.empty())
- return -1;
-
- char ea_value[64] = {0};
- ssize_t ea_size;
- ea_size = getxattr(path.value().c_str(),
- kCrosP2PFileSizeXAttrName,
- &ea_value,
- sizeof(ea_value) - 1);
- if (ea_size == -1) {
- PLOG(ERROR) << "Error calling getxattr() on file " << path.value();
- return -1;
- }
-
- char* endp = nullptr;
- long long int val = strtoll(ea_value, &endp, 0); // NOLINT(runtime/int)
- if (*endp != '\0') {
- LOG(ERROR) << "Error parsing the value '" << ea_value << "' of the xattr "
- << kCrosP2PFileSizeXAttrName << " as an integer";
- return -1;
- }
-
- return val;
-}
-
-int P2PManagerImpl::CountSharedFiles() {
- int num_files = 0;
-
- FilePath p2p_dir = configuration_->GetP2PDir();
- const string ext_visible = GetExt(kVisible);
- const string ext_non_visible = GetExt(kNonVisible);
-
- base::FileEnumerator dir(p2p_dir, false, base::FileEnumerator::FILES);
- for (FilePath name = dir.Next(); !name.empty(); name = dir.Next()) {
- if (base::EndsWith(
- name.value(), ext_visible, base::CompareCase::SENSITIVE) ||
- base::EndsWith(
- name.value(), ext_non_visible, base::CompareCase::SENSITIVE)) {
- num_files += 1;
- }
- }
-
- return num_files;
-}
-
-void P2PManagerImpl::ScheduleEnabledStatusChange() {
- if (waiting_for_enabled_status_change_)
- return;
-
- Callback<void(EvalStatus, const bool&)> callback =
- Bind(&P2PManagerImpl::OnEnabledStatusChange, base::Unretained(this));
- update_manager_->AsyncPolicyRequest(
- callback, &Policy::P2PEnabledChanged, is_enabled_);
- waiting_for_enabled_status_change_ = true;
-}
-
-void P2PManagerImpl::OnEnabledStatusChange(EvalStatus status,
- const bool& result) {
- waiting_for_enabled_status_change_ = false;
-
- if (status == EvalStatus::kSucceeded) {
- if (result == is_enabled_) {
- LOG(WARNING) << "P2P enabled status did not change, which means that it "
- "is permanent; not scheduling further checks.";
- waiting_for_enabled_status_change_ = true;
- return;
- }
-
- is_enabled_ = result;
-
- // If P2P is running but shouldn't be, make sure it isn't.
- if (may_be_running_ && !is_enabled_ && !EnsureP2PNotRunning()) {
- LOG(WARNING) << "Failed to stop P2P service.";
- }
- } else {
- LOG(WARNING)
- << "P2P enabled tracking failed (possibly timed out); retrying.";
- }
-
- ScheduleEnabledStatusChange();
-}
-
-P2PManager* P2PManager::Construct(Configuration* configuration,
- UpdateManager* update_manager,
- const string& file_extension,
- const int num_files_to_keep,
- const TimeDelta& max_file_age) {
- return new P2PManagerImpl(configuration,
- update_manager,
- file_extension,
- num_files_to_keep,
- max_file_age);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/p2p_manager.h b/cros/p2p_manager.h
deleted file mode 100644
index bef78063..00000000
--- a/cros/p2p_manager.h
+++ /dev/null
@@ -1,184 +0,0 @@
-//
-// Copyright (C) 2013 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_CROS_P2P_MANAGER_H_
-#define UPDATE_ENGINE_CROS_P2P_MANAGER_H_
-
-#include <string>
-#include <vector>
-
-#include <base/callback.h>
-#include <base/files/file_path.h>
-#include <base/memory/ref_counted.h>
-#include <base/time/time.h>
-#include <policy/device_policy.h>
-#include <policy/libpolicy.h>
-
-#include "update_engine/common/prefs_interface.h"
-#include "update_engine/update_manager/update_manager.h"
-
-namespace chromeos_update_engine {
-
-// Interface for sharing and discovering files via p2p.
-class P2PManager {
- public:
- // Interface used for P2PManager implementations. The sole reason
- // for this interface is unit testing.
- class Configuration {
- public:
- virtual ~Configuration() {}
-
- // Gets the path to the p2p dir being used, e.g. /var/cache/p2p.
- virtual base::FilePath GetP2PDir() = 0;
-
- // Gets the argument vector for starting (if |is_start| is True)
- // resp. stopping (if |is_start| is False) the p2p service
- // e.g. ["initctl", "start", "p2p"] or ["initctl", "stop", "p2p"].
- virtual std::vector<std::string> GetInitctlArgs(bool is_start) = 0;
-
- // Gets the argument vector for invoking p2p-client, e.g.
- // "p2p-client --get-url=file_id_we_want --minimum-size=42123".
- virtual std::vector<std::string> GetP2PClientArgs(
- const std::string& file_id, size_t minimum_size) = 0;
- };
-
- virtual ~P2PManager() {}
-
- // The type for the callback used in LookupUrlForFile().
- // If the lookup failed, |url| is empty.
- typedef base::Callback<void(const std::string& url)> LookupCallback;
-
- // Use the device policy specified by |device_policy|. If this is
- // null, then no device policy is used.
- virtual void SetDevicePolicy(const policy::DevicePolicy* device_policy) = 0;
-
- // Returns true iff P2P is currently allowed for use on this device. This
- // value is determined and maintained by the Update Manager.
- virtual bool IsP2PEnabled() = 0;
-
- // Ensures that the p2p subsystem is running (e.g. starts it if it's
- // not already running) and blocks until this is so. Returns false
- // if an error occurred.
- virtual bool EnsureP2PRunning() = 0;
-
- // Ensures that the p2p subsystem is not running (e.g. stops it if
- // it's running) and blocks until this is so. Returns false if an
- // error occurred.
- virtual bool EnsureP2PNotRunning() = 0;
-
- // Cleans up files in /var/cache/p2p owned by this application as
- // per the |file_extension| and |num_files_to_keep| values passed
- // when the object was constructed. This may be called even if
- // the p2p subsystem is not running.
- virtual bool PerformHousekeeping() = 0;
-
- // Asynchronously finds a peer that serves the file identified by
- // |file_id|. If |minimum_size| is non-zero, will find a peer that
- // has at least that many bytes. When the result is ready |callback|
- // is called from the current message loop.
- //
- // This operation may take a very long time to complete because part
- // of the p2p protocol involves waiting for the LAN-wide sum of all
- // num-connections to drop below a given threshold. However, if
- // |max_time_to_wait| is non-zero, the operation is guaranteed to
- // not exceed this duration.
- //
- // If the file is not available on the LAN (or if mDNS/DNS-SD is
- // filtered), this is guaranteed to not take longer than 5 seconds.
- virtual void LookupUrlForFile(const std::string& file_id,
- size_t minimum_size,
- base::TimeDelta max_time_to_wait,
- LookupCallback callback) = 0;
-
- // Shares a file identified by |file_id| in the directory
- // /var/cache/p2p. Initially the file will not be visible, that is,
- // it will have a .tmp extension and not be shared via p2p. Use the
- // FileMakeVisible() method to change this.
- //
- // If you know the final size of the file, pass it in the
- // |expected_size| parameter. Otherwise pass zero. If non-zero, the
- // amount of free space in /var/cache/p2p is checked and if there is
- // less than twice the amount of space available, this method
- // fails. Additionally, disk space will be reserved via fallocate(2)
- // and |expected_size| is written to the user.cros-p2p-filesize
- // xattr of the created file.
- //
- // If the file already exists, true is returned. Any on-disk xattr
- // is not updated.
- virtual bool FileShare(const std::string& file_id, size_t expected_size) = 0;
-
- // Gets a fully qualified path for the file identified by |file_id|.
- // If the file has not been shared already using the FileShare()
- // method, an empty base::FilePath is returned - use FilePath::empty() to
- // find out.
- virtual base::FilePath FileGetPath(const std::string& file_id) = 0;
-
- // Gets the actual size of the file identified by |file_id|. This is
- // equivalent to reading the value of the st_size field of the
- // struct stat on the file given by FileGetPath(). Returns -1 if an
- // error occurs.
- //
- // For a file just created with FileShare() this will return 0.
- virtual ssize_t FileGetSize(const std::string& file_id) = 0;
-
- // Gets the expected size of the file identified by |file_id|. This
- // is equivalent to reading the value of the user.cros-p2p-filesize
- // xattr on the file given by FileGetPath(). Returns -1 if an error
- // occurs.
- //
- // For a file just created with FileShare() this will return the
- // value of the |expected_size| parameter passed to that method.
- virtual ssize_t FileGetExpectedSize(const std::string& file_id) = 0;
-
- // Gets whether the file identified by |file_id| is publicly
- // visible. If |out_result| is not null, the result is returned
- // there. Returns false if an error occurs.
- virtual bool FileGetVisible(const std::string& file_id, bool* out_result) = 0;
-
- // Makes the file identified by |file_id| publicly visible
- // (e.g. removes the .tmp extension). If the file is already
- // visible, this method does nothing. Returns False if
- // the method fails or there is no file for |file_id|.
- virtual bool FileMakeVisible(const std::string& file_id) = 0;
-
- // Counts the number of shared files used by this application
- // (cf. the |file_extension parameter|. Returns -1 if an error
- // occurred.
- virtual int CountSharedFiles() = 0;
-
- // Creates a suitable P2PManager instance and initializes the object
- // so it's ready for use. The |file_extension| parameter is used to
- // identify your application, use e.g. "cros_au". If
- // |configuration| is non-null, the P2PManager will take ownership
- // of the Configuration object and use it (hence, it must be
- // heap-allocated).
- //
- // The |num_files_to_keep| parameter specifies how many files to
- // keep after performing housekeeping (cf. the PerformHousekeeping()
- // method) - pass zero to allow infinitely many files. The
- // |max_file_age| parameter specifies the maximum file age after
- // performing housekeeping (pass zero to allow files of any age).
- static P2PManager* Construct(
- Configuration* configuration,
- chromeos_update_manager::UpdateManager* update_manager,
- const std::string& file_extension,
- const int num_files_to_keep,
- const base::TimeDelta& max_file_age);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_P2P_MANAGER_H_
diff --git a/cros/p2p_manager_unittest.cc b/cros/p2p_manager_unittest.cc
deleted file mode 100644
index 17c48865..00000000
--- a/cros/p2p_manager_unittest.cc
+++ /dev/null
@@ -1,536 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/p2p_manager.h"
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/xattr.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/callback.h>
-#include <base/files/file_util.h>
-#if BASE_VER < 780000 // Android
-#include <base/message_loop/message_loop.h>
-#endif // BASE_VER < 780000
-#include <base/strings/stringprintf.h>
-#if BASE_VER >= 780000 // CrOS
-#include <base/task/single_thread_task_executor.h>
-#endif // BASE_VER >= 780000
-#include <brillo/asynchronous_signal_handler.h>
-#include <brillo/message_loops/base_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <policy/libpolicy.h>
-#include <policy/mock_device_policy.h>
-
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/subprocess.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/fake_p2p_manager_configuration.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/fake_update_manager.h"
-#include "update_engine/update_manager/mock_policy.h"
-
-using base::TimeDelta;
-using brillo::MessageLoop;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-using testing::_;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace chromeos_update_engine {
-
-// Test fixture that sets up a testing configuration (with e.g. a
-// temporary p2p dir) for P2PManager and cleans up when the test is
-// done.
-class P2PManagerTest : public testing::Test {
- protected:
- P2PManagerTest() = default;
- ~P2PManagerTest() override = default;
-
- // Derived from testing::Test.
- void SetUp() override {
- loop_.SetAsCurrent();
- FakeSystemState::CreateInstance();
- async_signal_handler_.Init();
- subprocess_.Init(&async_signal_handler_);
- test_conf_ = new FakeP2PManagerConfiguration();
-
- // Allocate and install a mock policy implementation in the fake Update
- // Manager. Note that the FakeUpdateManager takes ownership of the policy
- // object.
- mock_policy_ = new chromeos_update_manager::MockPolicy();
- fake_um_.set_policy(mock_policy_);
-
- // Construct the P2P manager under test.
- manager_.reset(P2PManager::Construct(test_conf_,
- &fake_um_,
- "cros_au",
- 3,
- TimeDelta::FromDays(5)));
- }
-
-#if BASE_VER < 780000 // Android
- base::MessageLoopForIO base_loop_;
- brillo::BaseMessageLoop loop_{&base_loop_};
-#else // CrOS
- base::SingleThreadTaskExecutor base_loop_{base::MessagePumpType::IO};
- brillo::BaseMessageLoop loop_{base_loop_.task_runner()};
-#endif // BASE_VER < 780000
- brillo::AsynchronousSignalHandler async_signal_handler_;
- Subprocess subprocess_;
-
- // The P2PManager::Configuration instance used for testing.
- FakeP2PManagerConfiguration* test_conf_;
-
- chromeos_update_manager::MockPolicy* mock_policy_ = nullptr;
- chromeos_update_manager::FakeUpdateManager fake_um_;
-
- unique_ptr<P2PManager> manager_;
-};
-
-// Check that IsP2PEnabled() polls the policy correctly, with the value not
-// changing between calls.
-TEST_F(P2PManagerTest, P2PEnabledInitAndNotChanged) {
- EXPECT_CALL(*mock_policy_, P2PEnabled(_, _, _, _));
- EXPECT_CALL(*mock_policy_, P2PEnabledChanged(_, _, _, _, false));
-
- EXPECT_FALSE(manager_->IsP2PEnabled());
- brillo::MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_FALSE(manager_->IsP2PEnabled());
-}
-
-// Check that IsP2PEnabled() polls the policy correctly, with the value changing
-// between calls.
-TEST_F(P2PManagerTest, P2PEnabledInitAndChanged) {
- EXPECT_CALL(*mock_policy_, P2PEnabled(_, _, _, _))
- .WillOnce(DoAll(SetArgPointee<3>(true),
- Return(chromeos_update_manager::EvalStatus::kSucceeded)));
- EXPECT_CALL(*mock_policy_, P2PEnabledChanged(_, _, _, _, true));
- EXPECT_CALL(*mock_policy_, P2PEnabledChanged(_, _, _, _, false));
-
- EXPECT_TRUE(manager_->IsP2PEnabled());
- brillo::MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_FALSE(manager_->IsP2PEnabled());
-}
-
-// Check that we keep the $N newest files with the .$EXT.p2p extension.
-TEST_F(P2PManagerTest, HousekeepingCountLimit) {
- // Specifically pass 0 for |max_file_age| to allow files of any age. Note that
- // we need to reallocate the test_conf_ member, whose currently aliased object
- // will be freed.
- test_conf_ = new FakeP2PManagerConfiguration();
- manager_.reset(P2PManager::Construct(test_conf_,
- &fake_um_,
- "cros_au",
- 3,
- TimeDelta() /* max_file_age */));
- EXPECT_EQ(manager_->CountSharedFiles(), 0);
-
- base::Time start_time = base::Time::FromDoubleT(1246996800.);
- // Generate files with different timestamps matching our pattern and generate
- // other files not matching the pattern.
- for (int n = 0; n < 5; n++) {
- base::FilePath path = test_conf_->GetP2PDir().Append(
- base::StringPrintf("file_%d.cros_au.p2p", n));
- base::Time file_time = start_time + TimeDelta::FromMinutes(n);
- EXPECT_EQ(0, base::WriteFile(path, nullptr, 0));
- EXPECT_TRUE(base::TouchFile(path, file_time, file_time));
-
- path = test_conf_->GetP2PDir().Append(
- base::StringPrintf("file_%d.OTHER.p2p", n));
- EXPECT_EQ(0, base::WriteFile(path, nullptr, 0));
- EXPECT_TRUE(base::TouchFile(path, file_time, file_time));
- }
- // CountSharedFiles() only counts 'cros_au' files.
- EXPECT_EQ(manager_->CountSharedFiles(), 5);
-
- EXPECT_TRUE(manager_->PerformHousekeeping());
-
- // At this point - after HouseKeeping - we should only have
- // eight files left.
- for (int n = 0; n < 5; n++) {
- string file_name;
- bool expect;
-
- expect = (n >= 2);
- file_name = base::StringPrintf(
- "%s/file_%d.cros_au.p2p", test_conf_->GetP2PDir().value().c_str(), n);
- EXPECT_EQ(expect, utils::FileExists(file_name.c_str()));
-
- file_name = base::StringPrintf(
- "%s/file_%d.OTHER.p2p", test_conf_->GetP2PDir().value().c_str(), n);
- EXPECT_TRUE(utils::FileExists(file_name.c_str()));
- }
- // CountSharedFiles() only counts 'cros_au' files.
- EXPECT_EQ(manager_->CountSharedFiles(), 3);
-}
-
-// Check that we keep files with the .$EXT.p2p extension not older
-// than some specific age (5 days, in this test).
-TEST_F(P2PManagerTest, HousekeepingAgeLimit) {
- // We set the cutoff time to be 1 billion seconds (01:46:40 UTC on 9
- // September 2001 - arbitrary number, but constant to avoid test
- // flakiness) since the epoch and then we put two files before that
- // date and three files after.
- base::Time cutoff_time = base::Time::FromTimeT(1000000000);
- TimeDelta age_limit = TimeDelta::FromDays(5);
-
- // Set the clock just so files with a timestamp before |cutoff_time|
- // will be deleted at housekeeping.
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(cutoff_time +
- age_limit);
-
- // Specifically pass 0 for |num_files_to_keep| to allow any number of files.
- // Note that we need to reallocate the test_conf_ member, whose currently
- // aliased object will be freed.
- test_conf_ = new FakeP2PManagerConfiguration();
- manager_.reset(P2PManager::Construct(test_conf_,
- &fake_um_,
- "cros_au",
- 0 /* num_files_to_keep */,
- age_limit));
- EXPECT_EQ(manager_->CountSharedFiles(), 0);
-
- // Generate files with different timestamps matching our pattern and generate
- // other files not matching the pattern.
- for (int n = 0; n < 5; n++) {
- base::FilePath path = test_conf_->GetP2PDir().Append(
- base::StringPrintf("file_%d.cros_au.p2p", n));
-
- // With five files and aiming for two of them to be before
- // |cutoff_time|, we distribute it like this:
- //
- // -------- 0 -------- 1 -------- 2 -------- 3 -------- 4 --------
- // |
- // cutoff_time
- //
- base::Time file_date = cutoff_time + (n - 2) * TimeDelta::FromDays(1) +
- TimeDelta::FromHours(12);
-
- EXPECT_EQ(0, base::WriteFile(path, nullptr, 0));
- EXPECT_TRUE(base::TouchFile(path, file_date, file_date));
-
- path = test_conf_->GetP2PDir().Append(
- base::StringPrintf("file_%d.OTHER.p2p", n));
- EXPECT_EQ(0, base::WriteFile(path, nullptr, 0));
- EXPECT_TRUE(base::TouchFile(path, file_date, file_date));
- }
- // CountSharedFiles() only counts 'cros_au' files.
- EXPECT_EQ(manager_->CountSharedFiles(), 5);
-
- EXPECT_TRUE(manager_->PerformHousekeeping());
-
- // At this point - after HouseKeeping - we should only have
- // eight files left.
- for (int n = 0; n < 5; n++) {
- string file_name;
- bool expect;
-
- expect = (n >= 2);
- file_name = base::StringPrintf(
- "%s/file_%d.cros_au.p2p", test_conf_->GetP2PDir().value().c_str(), n);
- EXPECT_EQ(expect, utils::FileExists(file_name.c_str()));
-
- file_name = base::StringPrintf(
- "%s/file_%d.OTHER.p2p", test_conf_->GetP2PDir().value().c_str(), n);
- EXPECT_TRUE(utils::FileExists(file_name.c_str()));
- }
- // CountSharedFiles() only counts 'cros_au' files.
- EXPECT_EQ(manager_->CountSharedFiles(), 3);
-}
-
-static bool CheckP2PFile(const string& p2p_dir,
- const string& file_name,
- ssize_t expected_size,
- ssize_t expected_size_xattr) {
- string path = p2p_dir + "/" + file_name;
- char ea_value[64] = {0};
- ssize_t ea_size;
-
- off_t p2p_size = utils::FileSize(path);
- if (p2p_size < 0) {
- LOG(ERROR) << "File " << path << " does not exist";
- return false;
- }
-
- if (expected_size != 0) {
- if (p2p_size != expected_size) {
- LOG(ERROR) << "Expected size " << expected_size << " but size was "
- << p2p_size;
- return false;
- }
- }
-
- if (expected_size_xattr == 0) {
- ea_size = getxattr(
- path.c_str(), "user.cros-p2p-filesize", &ea_value, sizeof ea_value - 1);
- if (ea_size == -1 && errno == ENODATA) {
- // This is valid behavior as we support files without the xattr set.
- } else {
- PLOG(ERROR) << "getxattr() didn't fail with ENODATA as expected, "
- << "ea_size=" << ea_size << ", errno=" << errno;
- return false;
- }
- } else {
- ea_size = getxattr(
- path.c_str(), "user.cros-p2p-filesize", &ea_value, sizeof ea_value - 1);
- if (ea_size < 0) {
- LOG(ERROR) << "Error getting xattr attribute";
- return false;
- }
- char* endp = nullptr;
- long long int val = strtoll(ea_value, &endp, 0); // NOLINT(runtime/int)
- if (endp == nullptr || *endp != '\0') {
- LOG(ERROR) << "Error parsing xattr '" << ea_value << "' as an integer";
- return false;
- }
- if (val != expected_size_xattr) {
- LOG(ERROR) << "Expected xattr size " << expected_size_xattr
- << " but size was " << val;
- return false;
- }
- }
-
- return true;
-}
-
-static bool CreateP2PFile(string p2p_dir,
- string file_name,
- size_t size,
- size_t size_xattr) {
- string path = p2p_dir + "/" + file_name;
-
- int fd = open(path.c_str(), O_CREAT | O_RDWR, 0644);
- if (fd == -1) {
- PLOG(ERROR) << "Error creating file with path " << path;
- return false;
- }
- if (ftruncate(fd, size) != 0) {
- PLOG(ERROR) << "Error truncating " << path << " to size " << size;
- close(fd);
- return false;
- }
-
- if (size_xattr != 0) {
- string decimal_size = std::to_string(size_xattr);
- if (fsetxattr(fd,
- "user.cros-p2p-filesize",
- decimal_size.c_str(),
- decimal_size.size(),
- 0) != 0) {
- PLOG(ERROR) << "Error setting xattr on " << path;
- close(fd);
- return false;
- }
- }
-
- close(fd);
- return true;
-}
-
-// Check that sharing a *new* file works.
-TEST_F(P2PManagerTest, ShareFile) {
- const int kP2PTestFileSize = 1000 * 8; // 8 KB
-
- EXPECT_TRUE(manager_->FileShare("foo", kP2PTestFileSize));
- EXPECT_EQ(manager_->FileGetPath("foo"),
- test_conf_->GetP2PDir().Append("foo.cros_au.p2p.tmp"));
- EXPECT_TRUE(CheckP2PFile(test_conf_->GetP2PDir().value(),
- "foo.cros_au.p2p.tmp",
- 0,
- kP2PTestFileSize));
-
- // Sharing it again - with the same expected size - should return true
- EXPECT_TRUE(manager_->FileShare("foo", kP2PTestFileSize));
-
- // ... but if we use the wrong size, it should fail
- EXPECT_FALSE(manager_->FileShare("foo", kP2PTestFileSize + 1));
-}
-
-// Check that making a shared file visible, does what is expected.
-TEST_F(P2PManagerTest, MakeFileVisible) {
- const int kP2PTestFileSize = 1000 * 8; // 8 KB
-
- // First, check that it's not visible.
- manager_->FileShare("foo", kP2PTestFileSize);
- EXPECT_EQ(manager_->FileGetPath("foo"),
- test_conf_->GetP2PDir().Append("foo.cros_au.p2p.tmp"));
- EXPECT_TRUE(CheckP2PFile(test_conf_->GetP2PDir().value(),
- "foo.cros_au.p2p.tmp",
- 0,
- kP2PTestFileSize));
- // Make the file visible and check that it changed its name. Do it
- // twice to check that FileMakeVisible() is idempotent.
- for (int n = 0; n < 2; n++) {
- manager_->FileMakeVisible("foo");
- EXPECT_EQ(manager_->FileGetPath("foo"),
- test_conf_->GetP2PDir().Append("foo.cros_au.p2p"));
- EXPECT_TRUE(CheckP2PFile(test_conf_->GetP2PDir().value(),
- "foo.cros_au.p2p",
- 0,
- kP2PTestFileSize));
- }
-}
-
-// Check that we return the right values for existing files in P2P_DIR.
-TEST_F(P2PManagerTest, ExistingFiles) {
- bool visible;
-
- // Check that errors are returned if the file does not exist
- EXPECT_EQ(manager_->FileGetPath("foo"), base::FilePath());
- EXPECT_EQ(manager_->FileGetSize("foo"), -1);
- EXPECT_EQ(manager_->FileGetExpectedSize("foo"), -1);
- EXPECT_FALSE(manager_->FileGetVisible("foo", nullptr));
- // ... then create the file ...
- EXPECT_TRUE(CreateP2PFile(
- test_conf_->GetP2PDir().value(), "foo.cros_au.p2p", 42, 43));
- // ... and then check that the expected values are returned
- EXPECT_EQ(manager_->FileGetPath("foo"),
- test_conf_->GetP2PDir().Append("foo.cros_au.p2p"));
- EXPECT_EQ(manager_->FileGetSize("foo"), 42);
- EXPECT_EQ(manager_->FileGetExpectedSize("foo"), 43);
- EXPECT_TRUE(manager_->FileGetVisible("foo", &visible));
- EXPECT_TRUE(visible);
-
- // One more time, this time with a .tmp variant. First ensure it errors out..
- EXPECT_EQ(manager_->FileGetPath("bar"), base::FilePath());
- EXPECT_EQ(manager_->FileGetSize("bar"), -1);
- EXPECT_EQ(manager_->FileGetExpectedSize("bar"), -1);
- EXPECT_FALSE(manager_->FileGetVisible("bar", nullptr));
- // ... then create the file ...
- EXPECT_TRUE(CreateP2PFile(
- test_conf_->GetP2PDir().value(), "bar.cros_au.p2p.tmp", 44, 45));
- // ... and then check that the expected values are returned
- EXPECT_EQ(manager_->FileGetPath("bar"),
- test_conf_->GetP2PDir().Append("bar.cros_au.p2p.tmp"));
- EXPECT_EQ(manager_->FileGetSize("bar"), 44);
- EXPECT_EQ(manager_->FileGetExpectedSize("bar"), 45);
- EXPECT_TRUE(manager_->FileGetVisible("bar", &visible));
- EXPECT_FALSE(visible);
-}
-
-// This is a little bit ugly but short of mocking a 'p2p' service this
-// will have to do. E.g. we essentially simulate the various
-// behaviours of initctl(8) that we rely on.
-TEST_F(P2PManagerTest, StartP2P) {
- // Check that we can start the service
- test_conf_->SetInitctlStartCommand({"true"});
- EXPECT_TRUE(manager_->EnsureP2PRunning());
- test_conf_->SetInitctlStartCommand({"false"});
- EXPECT_FALSE(manager_->EnsureP2PRunning());
- test_conf_->SetInitctlStartCommand(
- {"sh", "-c", "echo \"initctl: Job is already running: p2p\" >&2; false"});
- EXPECT_TRUE(manager_->EnsureP2PRunning());
- test_conf_->SetInitctlStartCommand(
- {"sh", "-c", "echo something else >&2; false"});
- EXPECT_FALSE(manager_->EnsureP2PRunning());
-}
-
-// Same comment as for StartP2P
-TEST_F(P2PManagerTest, StopP2P) {
- // Check that we can start the service
- test_conf_->SetInitctlStopCommand({"true"});
- EXPECT_TRUE(manager_->EnsureP2PNotRunning());
- test_conf_->SetInitctlStopCommand({"false"});
- EXPECT_FALSE(manager_->EnsureP2PNotRunning());
- test_conf_->SetInitctlStopCommand(
- {"sh", "-c", "echo \"initctl: Unknown instance \" >&2; false"});
- EXPECT_TRUE(manager_->EnsureP2PNotRunning());
- test_conf_->SetInitctlStopCommand(
- {"sh", "-c", "echo something else >&2; false"});
- EXPECT_FALSE(manager_->EnsureP2PNotRunning());
-}
-
-static void ExpectUrl(const string& expected_url, const string& url) {
- EXPECT_EQ(url, expected_url);
- MessageLoop::current()->BreakLoop();
-}
-
-// Like StartP2P, we're mocking the different results that p2p-client
-// can return. It's not pretty but it works.
-TEST_F(P2PManagerTest, LookupURL) {
- // Emulate p2p-client returning valid URL with "fooX", 42 and "cros_au"
- // being propagated in the right places.
- test_conf_->SetP2PClientCommand(
- {"echo", "http://1.2.3.4/{file_id}_{minsize}"});
- manager_->LookupUrlForFile(
- "fooX",
- 42,
- TimeDelta(),
- base::Bind(ExpectUrl, "http://1.2.3.4/fooX.cros_au_42"));
- loop_.Run();
-
- // Emulate p2p-client returning invalid URL.
- test_conf_->SetP2PClientCommand({"echo", "not_a_valid_url"});
- manager_->LookupUrlForFile(
- "foobar", 42, TimeDelta(), base::Bind(ExpectUrl, ""));
- loop_.Run();
-
- // Emulate p2p-client conveying failure.
- test_conf_->SetP2PClientCommand({"false"});
- manager_->LookupUrlForFile(
- "foobar", 42, TimeDelta(), base::Bind(ExpectUrl, ""));
- loop_.Run();
-
- // Emulate p2p-client not existing.
- test_conf_->SetP2PClientCommand({"/path/to/non/existent/helper/program"});
- manager_->LookupUrlForFile(
- "foobar", 42, TimeDelta(), base::Bind(ExpectUrl, ""));
- loop_.Run();
-
- // Emulate p2p-client crashing.
- test_conf_->SetP2PClientCommand({"sh", "-c", "kill -SEGV $$"});
- manager_->LookupUrlForFile(
- "foobar", 42, TimeDelta(), base::Bind(ExpectUrl, ""));
- loop_.Run();
-
- // Emulate p2p-client exceeding its timeout.
- test_conf_->SetP2PClientCommand(
- {"sh",
- "-c",
- // The 'sleep' launched below could be left behind as an orphaned
- // process when the 'sh' process is terminated by SIGTERM. As a
- // remedy, trap SIGTERM and kill the 'sleep' process, which requires
- // launching 'sleep' in background and then waiting for it.
- "cleanup() { kill \"${sleep_pid}\"; exit 0; }; "
- "trap cleanup TERM; "
- "sleep 5 & "
- "sleep_pid=$!; "
- "echo http://1.2.3.4/; "
- "wait"});
- manager_->LookupUrlForFile("foobar",
- 42,
- TimeDelta::FromMilliseconds(500),
- base::Bind(ExpectUrl, ""));
- loop_.Run();
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/payload_state.cc b/cros/payload_state.cc
deleted file mode 100644
index d417ef58..00000000
--- a/cros/payload_state.cc
+++ /dev/null
@@ -1,1438 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/payload_state.h"
-
-#include <algorithm>
-#include <string>
-
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <metrics/metrics_library.h>
-#include <policy/device_policy.h>
-
-#include "update_engine/common/clock.h"
-#include "update_engine/common/constants.h"
-#include "update_engine/common/error_code_utils.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/metrics_reporter_interface.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/connection_manager_interface.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/update_attempter.h"
-#include "update_engine/metrics_utils.h"
-#include "update_engine/payload_consumer/install_plan.h"
-
-using base::Time;
-using base::TimeDelta;
-using std::min;
-using std::string;
-
-namespace chromeos_update_engine {
-
-using metrics_utils::GetPersistedValue;
-
-const TimeDelta PayloadState::kDurationSlack = TimeDelta::FromSeconds(600);
-
-// We want to upperbound backoffs to 16 days
-static const int kMaxBackoffDays = 16;
-
-// We want to randomize retry attempts after the backoff by +/- 6 hours.
-static const uint32_t kMaxBackoffFuzzMinutes = 12 * 60;
-
-// Limit persisting current update duration uptime to once per second
-static const uint64_t kUptimeResolution = 1;
-
-PayloadState::PayloadState()
- : prefs_(nullptr),
- powerwash_safe_prefs_(nullptr),
- excluder_(nullptr),
- using_p2p_for_downloading_(false),
- p2p_num_attempts_(0),
- payload_attempt_number_(0),
- full_payload_attempt_number_(0),
- url_index_(0),
- url_failure_count_(0),
- url_switch_count_(0),
- rollback_happened_(false),
- attempt_num_bytes_downloaded_(0),
- attempt_connection_type_(metrics::ConnectionType::kUnknown),
- attempt_type_(AttemptType::kUpdate) {
- for (int i = 0; i <= kNumDownloadSources; i++)
- total_bytes_downloaded_[i] = current_bytes_downloaded_[i] = 0;
-}
-
-bool PayloadState::Initialize() {
- prefs_ = SystemState::Get()->prefs();
- powerwash_safe_prefs_ = SystemState::Get()->powerwash_safe_prefs();
- excluder_ = SystemState::Get()->update_attempter()->GetExcluder();
- LoadResponseSignature();
- LoadPayloadAttemptNumber();
- LoadFullPayloadAttemptNumber();
- LoadUrlIndex();
- LoadUrlFailureCount();
- LoadUrlSwitchCount();
- LoadBackoffExpiryTime();
- LoadUpdateTimestampStart();
- // The LoadUpdateDurationUptime() method relies on LoadUpdateTimestampStart()
- // being called before it. Don't reorder.
- LoadUpdateDurationUptime();
- for (int i = 0; i < kNumDownloadSources; i++) {
- DownloadSource source = static_cast<DownloadSource>(i);
- LoadCurrentBytesDownloaded(source);
- LoadTotalBytesDownloaded(source);
- }
- LoadNumReboots();
- LoadNumResponsesSeen();
- LoadRollbackHappened();
- LoadRollbackVersion();
- LoadP2PFirstAttemptTimestamp();
- LoadP2PNumAttempts();
- return true;
-}
-
-void PayloadState::SetResponse(const OmahaResponse& omaha_response) {
- // Always store the latest response.
- response_ = omaha_response;
-
- // Compute the candidate URLs first as they are used to calculate the
- // response signature so that a change in enterprise policy for
- // HTTP downloads being enabled or not could be honored as soon as the
- // next update check happens.
- ComputeCandidateUrls();
-
- // Check if the "signature" of this response (i.e. the fields we care about)
- // has changed.
- string new_response_signature = CalculateResponseSignature();
- bool has_response_changed = (response_signature_ != new_response_signature);
-
- // If the response has changed, we should persist the new signature and
- // clear away all the existing state.
- if (has_response_changed) {
- LOG(INFO) << "Resetting all persisted state as this is a new response";
- SetNumResponsesSeen(num_responses_seen_ + 1);
- SetResponseSignature(new_response_signature);
- ResetPersistedState();
- return;
- }
-
- // Always start from payload index 0, even for resume, to download partition
- // info from previous payloads.
- payload_index_ = 0;
-
- // This is the earliest point at which we can validate whether the URL index
- // we loaded from the persisted state is a valid value. If the response
- // hasn't changed but the URL index is invalid, it's indicative of some
- // tampering of the persisted state.
- if (payload_index_ >= candidate_urls_.size() ||
- url_index_ >= candidate_urls_[payload_index_].size()) {
- LOG(INFO) << "Resetting all payload state as the url index seems to have "
- "been tampered with";
- ResetPersistedState();
- return;
- }
-
- // Update the current download source which depends on the latest value of
- // the response.
- UpdateCurrentDownloadSource();
-}
-
-void PayloadState::SetUsingP2PForDownloading(bool value) {
- using_p2p_for_downloading_ = value;
- // Update the current download source which depends on whether we are
- // using p2p or not.
- UpdateCurrentDownloadSource();
-}
-
-void PayloadState::DownloadComplete() {
- LOG(INFO) << "Payload downloaded successfully";
- IncrementPayloadAttemptNumber();
- IncrementFullPayloadAttemptNumber();
-}
-
-void PayloadState::DownloadProgress(size_t count) {
- if (count == 0)
- return;
-
- CalculateUpdateDurationUptime();
- UpdateBytesDownloaded(count);
-
- // We've received non-zero bytes from a recent download operation. Since our
- // URL failure count is meant to penalize a URL only for consecutive
- // failures, downloading bytes successfully means we should reset the failure
- // count (as we know at least that the URL is working). In future, we can
- // design this to be more sophisticated to check for more intelligent failure
- // patterns, but right now, even 1 byte downloaded will mark the URL to be
- // good unless it hits 10 (or configured number of) consecutive failures
- // again.
-
- if (GetUrlFailureCount() == 0)
- return;
-
- LOG(INFO) << "Resetting failure count of Url" << GetUrlIndex()
- << " to 0 as we received " << count << " bytes successfully";
- SetUrlFailureCount(0);
-}
-
-void PayloadState::AttemptStarted(AttemptType attempt_type) {
- // Flush previous state from abnormal attempt failure, if any.
- ReportAndClearPersistedAttemptMetrics();
-
- attempt_type_ = attempt_type;
-
- const auto* clock = SystemState::Get()->clock();
- attempt_start_time_boot_ = clock->GetBootTime();
- attempt_start_time_monotonic_ = clock->GetMonotonicTime();
- attempt_num_bytes_downloaded_ = 0;
-
- metrics::ConnectionType type;
- ConnectionType network_connection_type;
- ConnectionTethering tethering;
- ConnectionManagerInterface* connection_manager =
- SystemState::Get()->connection_manager();
- if (!connection_manager->GetConnectionProperties(&network_connection_type,
- &tethering)) {
- LOG(ERROR) << "Failed to determine connection type.";
- type = metrics::ConnectionType::kUnknown;
- } else {
- type = metrics_utils::GetConnectionType(network_connection_type, tethering);
- }
- attempt_connection_type_ = type;
-
- if (attempt_type == AttemptType::kUpdate)
- PersistAttemptMetrics();
-}
-
-void PayloadState::UpdateResumed() {
- LOG(INFO) << "Resuming an update that was previously started.";
- UpdateNumReboots();
- AttemptStarted(AttemptType::kUpdate);
-}
-
-void PayloadState::UpdateRestarted() {
- LOG(INFO) << "Starting a new update";
- ResetDownloadSourcesOnNewUpdate();
- SetNumReboots(0);
- AttemptStarted(AttemptType::kUpdate);
-}
-
-void PayloadState::UpdateSucceeded() {
- // Send the relevant metrics that are tracked in this class to UMA.
- CalculateUpdateDurationUptime();
- SetUpdateTimestampEnd(SystemState::Get()->clock()->GetWallclockTime());
-
- switch (attempt_type_) {
- case AttemptType::kUpdate:
- CollectAndReportAttemptMetrics(ErrorCode::kSuccess);
- CollectAndReportSuccessfulUpdateMetrics();
- ClearPersistedAttemptMetrics();
- break;
-
- case AttemptType::kRollback:
- SystemState::Get()->metrics_reporter()->ReportRollbackMetrics(
- metrics::RollbackResult::kSuccess);
- break;
- }
-
- // Reset the number of responses seen since it counts from the last
- // successful update, e.g. now.
- SetNumResponsesSeen(0);
- SetPayloadIndex(0);
-
- metrics_utils::SetSystemUpdatedMarker(SystemState::Get()->clock(), prefs_);
-}
-
-void PayloadState::UpdateFailed(ErrorCode error) {
- ErrorCode base_error = utils::GetBaseErrorCode(error);
- LOG(INFO) << "Updating payload state for error code: " << base_error << " ("
- << utils::ErrorCodeToString(base_error) << ")";
-
- if (candidate_urls_.size() == 0) {
- // This means we got this error even before we got a valid Omaha response
- // or don't have any valid candidates in the Omaha response.
- // So we should not advance the url_index_ in such cases.
- LOG(INFO) << "Ignoring failures until we get a valid Omaha response.";
- return;
- }
-
- switch (attempt_type_) {
- case AttemptType::kUpdate:
- CollectAndReportAttemptMetrics(base_error);
- ClearPersistedAttemptMetrics();
- break;
-
- case AttemptType::kRollback:
- SystemState::Get()->metrics_reporter()->ReportRollbackMetrics(
- metrics::RollbackResult::kFailed);
- break;
- }
-
- switch (base_error) {
- // Errors which are good indicators of a problem with a particular URL or
- // the protocol used in the URL or entities in the communication channel
- // (e.g. proxies). We should try the next available URL in the next update
- // check to quickly recover from these errors.
- case ErrorCode::kPayloadHashMismatchError:
- case ErrorCode::kPayloadSizeMismatchError:
- case ErrorCode::kDownloadPayloadVerificationError:
- case ErrorCode::kDownloadPayloadPubKeyVerificationError:
- case ErrorCode::kSignedDeltaPayloadExpectedError:
- case ErrorCode::kDownloadInvalidMetadataMagicString:
- case ErrorCode::kDownloadSignatureMissingInManifest:
- case ErrorCode::kDownloadManifestParseError:
- case ErrorCode::kDownloadMetadataSignatureError:
- case ErrorCode::kDownloadMetadataSignatureVerificationError:
- case ErrorCode::kDownloadMetadataSignatureMismatch:
- case ErrorCode::kDownloadOperationHashVerificationError:
- case ErrorCode::kDownloadOperationExecutionError:
- case ErrorCode::kDownloadOperationHashMismatch:
- case ErrorCode::kDownloadInvalidMetadataSize:
- case ErrorCode::kDownloadInvalidMetadataSignature:
- case ErrorCode::kDownloadOperationHashMissingError:
- case ErrorCode::kDownloadMetadataSignatureMissingError:
- case ErrorCode::kPayloadMismatchedType:
- case ErrorCode::kUnsupportedMajorPayloadVersion:
- case ErrorCode::kUnsupportedMinorPayloadVersion:
- case ErrorCode::kPayloadTimestampError:
- case ErrorCode::kVerityCalculationError:
- ExcludeCurrentPayload();
- IncrementUrlIndex();
- break;
-
- // Errors which seem to be just transient network/communication related
- // failures and do not indicate any inherent problem with the URL itself.
- // So, we should keep the current URL but just increment the
- // failure count to give it more chances. This way, while we maximize our
- // chances of downloading from the URLs that appear earlier in the
- // response (because download from a local server URL that appears earlier
- // in a response is preferable than downloading from the next URL which
- // could be a internet URL and thus could be more expensive).
-
- case ErrorCode::kError:
- case ErrorCode::kDownloadTransferError:
- case ErrorCode::kDownloadWriteError:
- case ErrorCode::kDownloadStateInitializationError:
- case ErrorCode::kOmahaErrorInHTTPResponse: // Aggregate for HTTP errors.
- IncrementFailureCount();
- break;
-
- // Errors which are not specific to a URL and hence shouldn't result in
- // the URL being penalized. This can happen in two cases:
- // 1. We haven't started downloading anything: These errors don't cost us
- // anything in terms of actual payload bytes, so we should just do the
- // regular retries at the next update check.
- // 2. We have successfully downloaded the payload: In this case, the
- // payload attempt number would have been incremented and would take care
- // of the backoff at the next update check.
- // In either case, there's no need to update URL index or failure count.
- case ErrorCode::kOmahaRequestError:
- case ErrorCode::kOmahaResponseHandlerError:
- case ErrorCode::kPostinstallRunnerError:
- case ErrorCode::kFilesystemCopierError:
- case ErrorCode::kInstallDeviceOpenError:
- case ErrorCode::kKernelDeviceOpenError:
- case ErrorCode::kDownloadNewPartitionInfoError:
- case ErrorCode::kNewRootfsVerificationError:
- case ErrorCode::kNewKernelVerificationError:
- case ErrorCode::kPostinstallBootedFromFirmwareB:
- case ErrorCode::kPostinstallFirmwareRONotUpdatable:
- case ErrorCode::kOmahaRequestEmptyResponseError:
- case ErrorCode::kOmahaRequestXMLParseError:
- case ErrorCode::kOmahaResponseInvalid:
- case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
- case ErrorCode::kOmahaUpdateDeferredPerPolicy:
- case ErrorCode::kNonCriticalUpdateInOOBE:
- case ErrorCode::kOmahaUpdateDeferredForBackoff:
- case ErrorCode::kPostinstallPowerwashError:
- case ErrorCode::kUpdateCanceledByChannelChange:
- case ErrorCode::kOmahaRequestXMLHasEntityDecl:
- case ErrorCode::kFilesystemVerifierError:
- case ErrorCode::kUserCanceled:
- case ErrorCode::kOmahaUpdateIgnoredOverCellular:
- case ErrorCode::kUpdatedButNotActive:
- case ErrorCode::kNoUpdate:
- case ErrorCode::kRollbackNotPossible:
- case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
- case ErrorCode::kInternalLibCurlError:
- case ErrorCode::kUnresolvedHostError:
- 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;
-
- case ErrorCode::kSuccess: // success code
- case ErrorCode::kUmaReportedMax: // not an error code
- case ErrorCode::kOmahaRequestHTTPResponseBase: // aggregated already
- case ErrorCode::kDevModeFlag: // not an error code
- case ErrorCode::kResumedFlag: // not an error code
- case ErrorCode::kTestImageFlag: // not an error code
- case ErrorCode::kTestOmahaUrlFlag: // not an error code
- case ErrorCode::kSpecialFlags: // not an error code
- // These shouldn't happen. Enumerating these explicitly here so that we
- // can let the compiler warn about new error codes that are added to
- // action_processor.h but not added here.
- LOG(WARNING) << "Unexpected error code for UpdateFailed";
- break;
-
- // Note: Not adding a default here so as to let the compiler warn us of
- // any new enums that were added in the .h but not listed in this switch.
- }
-}
-
-bool PayloadState::ShouldBackoffDownload() {
- if (response_.disable_payload_backoff) {
- LOG(INFO) << "Payload backoff logic is disabled. "
- "Can proceed with the download";
- return false;
- }
- if (GetUsingP2PForDownloading() && !GetP2PUrl().empty()) {
- LOG(INFO) << "Payload backoff logic is disabled because download "
- << "will happen from local peer (via p2p).";
- return false;
- }
- if (SystemState::Get()->request_params()->interactive()) {
- LOG(INFO) << "Payload backoff disabled for interactive update checks.";
- return false;
- }
- for (const auto& package : response_.packages) {
- if (package.is_delta) {
- // If delta payloads fail, we want to fallback quickly to full payloads as
- // they are more likely to succeed. Exponential backoffs would greatly
- // slow down the fallback to full payloads. So we don't backoff for delta
- // payloads.
- LOG(INFO) << "No backoffs for delta payloads. "
- << "Can proceed with the download";
- return false;
- }
- }
-
- if (!SystemState::Get()->hardware()->IsOfficialBuild() &&
- !prefs_->Exists(kPrefsNoIgnoreBackoff)) {
- // Backoffs are needed only for official builds. We do not want any delays
- // or update failures due to backoffs during testing or development. Unless
- // the |kPrefsNoIgnoreBackoff| is manually set.
- LOG(INFO) << "No backoffs for test/dev images. "
- << "Can proceed with the download";
- return false;
- }
-
- if (backoff_expiry_time_.is_null()) {
- LOG(INFO) << "No backoff expiry time has been set. "
- << "Can proceed with the download";
- return false;
- }
-
- if (backoff_expiry_time_ < Time::Now()) {
- LOG(INFO) << "The backoff expiry time ("
- << utils::ToString(backoff_expiry_time_)
- << ") has elapsed. Can proceed with the download";
- return false;
- }
-
- LOG(INFO) << "Cannot proceed with downloads as we need to backoff until "
- << utils::ToString(backoff_expiry_time_);
- return true;
-}
-
-void PayloadState::Rollback() {
- SetRollbackVersion(SystemState::Get()->request_params()->app_version());
- AttemptStarted(AttemptType::kRollback);
-}
-
-void PayloadState::IncrementPayloadAttemptNumber() {
- // Update the payload attempt number for both payload types: full and delta.
- SetPayloadAttemptNumber(GetPayloadAttemptNumber() + 1);
-}
-
-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";
- return;
- }
-
- LOG(INFO) << "Incrementing the full payload attempt number";
- SetFullPayloadAttemptNumber(GetFullPayloadAttemptNumber() + 1);
- UpdateBackoffExpiryTime();
-}
-
-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) {
- LOG(INFO) << "Incrementing the URL index for next attempt";
- SetUrlIndex(next_url_index);
- } else {
- LOG(INFO) << "Resetting the current URL index (" << url_index_ << ") to "
- << "0 as we only have " << max_url_size << " candidate URL(s)";
- SetUrlIndex(0);
- IncrementPayloadAttemptNumber();
- IncrementFullPayloadAttemptNumber();
- }
-
- // If we have multiple URLs, record that we just switched to another one
- if (max_url_size > 1)
- SetUrlSwitchCount(url_switch_count_ + 1);
-
- // Whenever we update the URL index, we should also clear the URL failure
- // count so we can start over fresh for the new URL.
- SetUrlFailureCount(0);
-}
-
-void PayloadState::IncrementFailureCount() {
- uint32_t next_url_failure_count = GetUrlFailureCount() + 1;
- if (next_url_failure_count < response_.max_failure_count_per_url) {
- LOG(INFO) << "Incrementing the URL failure count";
- SetUrlFailureCount(next_url_failure_count);
- } else {
- LOG(INFO) << "Reached max number of failures for Url" << GetUrlIndex()
- << ". Trying next available URL";
- ExcludeCurrentPayload();
- IncrementUrlIndex();
- }
-}
-
-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="
- << package.hash;
- return;
- }
- auto exclusion_name = utils::GetExclusionName(GetCurrentUrl());
- if (!excluder_->Exclude(exclusion_name))
- LOG(WARNING) << "Failed to exclude "
- << " Package Hash=" << package.hash
- << " CurrentUrl=" << GetCurrentUrl();
- else
- LOG(INFO) << "Excluded "
- << " Package Hash=" << package.hash
- << " CurrentUrl=" << GetCurrentUrl();
-}
-
-void PayloadState::UpdateBackoffExpiryTime() {
- if (response_.disable_payload_backoff) {
- LOG(INFO) << "Resetting backoff expiry time as payload backoff is disabled";
- SetBackoffExpiryTime(Time());
- return;
- }
-
- if (GetFullPayloadAttemptNumber() == 0) {
- SetBackoffExpiryTime(Time());
- return;
- }
-
- // Since we're doing left-shift below, make sure we don't shift more
- // than this. E.g. if int is 4-bytes, don't left-shift more than 30 bits,
- // since we don't expect value of kMaxBackoffDays to be more than 100 anyway.
- int num_days = 1; // the value to be shifted.
- const int kMaxShifts = (sizeof(num_days) * 8) - 2;
-
- // Normal backoff days is 2 raised to (payload_attempt_number - 1).
- // E.g. if payload_attempt_number is over 30, limit power to 30.
- int power = min(GetFullPayloadAttemptNumber() - 1, kMaxShifts);
-
- // The number of days is the minimum of 2 raised to (payload_attempt_number
- // - 1) or kMaxBackoffDays.
- num_days = min(num_days << power, kMaxBackoffDays);
-
- // We don't want all retries to happen exactly at the same time when
- // retrying after backoff. So add some random minutes to fuzz.
- int fuzz_minutes = utils::FuzzInt(0, kMaxBackoffFuzzMinutes);
- TimeDelta next_backoff_interval =
- TimeDelta::FromDays(num_days) + TimeDelta::FromMinutes(fuzz_minutes);
- LOG(INFO) << "Incrementing the backoff expiry time by "
- << utils::FormatTimeDelta(next_backoff_interval);
- SetBackoffExpiryTime(Time::Now() + next_backoff_interval);
-}
-
-void PayloadState::UpdateCurrentDownloadSource() {
- current_download_source_ = kNumDownloadSources;
-
- if (using_p2p_for_downloading_) {
- current_download_source_ = kDownloadSourceHttpPeer;
- } else if (payload_index_ < candidate_urls_.size() &&
- candidate_urls_[payload_index_].size() != 0) {
- const string& current_url = candidate_urls_[payload_index_][GetUrlIndex()];
- if (base::StartsWith(
- current_url, "https://", base::CompareCase::INSENSITIVE_ASCII)) {
- current_download_source_ = kDownloadSourceHttpsServer;
- } else if (base::StartsWith(current_url,
- "http://",
- base::CompareCase::INSENSITIVE_ASCII)) {
- current_download_source_ = kDownloadSourceHttpServer;
- }
- }
-
- LOG(INFO) << "Current download source: "
- << utils::ToString(current_download_source_);
-}
-
-void PayloadState::UpdateBytesDownloaded(size_t count) {
- SetCurrentBytesDownloaded(
- current_download_source_,
- GetCurrentBytesDownloaded(current_download_source_) + count,
- false);
- SetTotalBytesDownloaded(
- current_download_source_,
- GetTotalBytesDownloaded(current_download_source_) + count,
- false);
-
- attempt_num_bytes_downloaded_ += count;
-}
-
-PayloadType PayloadState::CalculatePayloadType() {
- for (const auto& package : response_.packages) {
- if (package.is_delta) {
- return kPayloadTypeDelta;
- }
- }
- OmahaRequestParams* params = SystemState::Get()->request_params();
- if (params->delta_okay()) {
- return kPayloadTypeFull;
- }
- // Full payload, delta was not allowed by request.
- return kPayloadTypeForcedFull;
-}
-
-void PayloadState::CollectAndReportAttemptMetrics(ErrorCode code) {
- int attempt_number = GetPayloadAttemptNumber();
-
- PayloadType payload_type = CalculatePayloadType();
-
- int64_t payload_size = GetPayloadSize();
-
- int64_t payload_bytes_downloaded = attempt_num_bytes_downloaded_;
-
- const auto* clock = SystemState::Get()->clock();
- TimeDelta duration = clock->GetBootTime() - attempt_start_time_boot_;
- TimeDelta duration_uptime =
- clock->GetMonotonicTime() - attempt_start_time_monotonic_;
-
- int64_t payload_download_speed_bps = 0;
- int64_t usec = duration_uptime.InMicroseconds();
- if (usec > 0) {
- double sec = static_cast<double>(usec) / Time::kMicrosecondsPerSecond;
- double bps = static_cast<double>(payload_bytes_downloaded) / sec;
- payload_download_speed_bps = static_cast<int64_t>(bps);
- }
-
- DownloadSource download_source = current_download_source_;
-
- metrics::DownloadErrorCode payload_download_error_code =
- metrics::DownloadErrorCode::kUnset;
- ErrorCode internal_error_code = ErrorCode::kSuccess;
- metrics::AttemptResult attempt_result = metrics_utils::GetAttemptResult(code);
-
- // Add additional detail to AttemptResult
- switch (attempt_result) {
- case metrics::AttemptResult::kPayloadDownloadError:
- payload_download_error_code = metrics_utils::GetDownloadErrorCode(code);
- break;
-
- case metrics::AttemptResult::kInternalError:
- internal_error_code = code;
- break;
-
- // Explicit fall-through for cases where we do not have additional
- // detail. We avoid the default keyword to force people adding new
- // AttemptResult values to visit this code and examine whether
- // additional detail is needed.
- case metrics::AttemptResult::kUpdateSucceeded:
- case metrics::AttemptResult::kMetadataMalformed:
- case metrics::AttemptResult::kOperationMalformed:
- case metrics::AttemptResult::kOperationExecutionError:
- case metrics::AttemptResult::kMetadataVerificationFailed:
- case metrics::AttemptResult::kPayloadVerificationFailed:
- case metrics::AttemptResult::kVerificationFailed:
- case metrics::AttemptResult::kPostInstallFailed:
- 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;
- }
-
- SystemState::Get()->metrics_reporter()->ReportUpdateAttemptMetrics(
- attempt_number,
- payload_type,
- duration,
- duration_uptime,
- payload_size,
- attempt_result,
- internal_error_code);
-
- SystemState::Get()->metrics_reporter()->ReportUpdateAttemptDownloadMetrics(
- payload_bytes_downloaded,
- payload_download_speed_bps,
- download_source,
- payload_download_error_code,
- attempt_connection_type_);
-}
-
-void PayloadState::PersistAttemptMetrics() {
- // TODO(zeuthen): For now we only persist whether an attempt was in
- // progress and not values/metrics related to the attempt. This
- // means that when this happens, of all the UpdateEngine.Attempt.*
- // metrics, only UpdateEngine.Attempt.Result is reported (with the
- // value |kAbnormalTermination|). In the future we might want to
- // persist more data so we can report other metrics in the
- // UpdateEngine.Attempt.* namespace when this happens.
- prefs_->SetBoolean(kPrefsAttemptInProgress, true);
-}
-
-void PayloadState::ClearPersistedAttemptMetrics() {
- prefs_->Delete(kPrefsAttemptInProgress);
-}
-
-void PayloadState::ReportAndClearPersistedAttemptMetrics() {
- bool attempt_in_progress = false;
- if (!prefs_->GetBoolean(kPrefsAttemptInProgress, &attempt_in_progress))
- return;
- if (!attempt_in_progress)
- return;
-
- SystemState::Get()
- ->metrics_reporter()
- ->ReportAbnormallyTerminatedUpdateAttemptMetrics();
-
- ClearPersistedAttemptMetrics();
-}
-
-void PayloadState::CollectAndReportSuccessfulUpdateMetrics() {
- string metric;
-
- // Report metrics collected from all known download sources to UMA.
- int64_t total_bytes_by_source[kNumDownloadSources];
- int64_t successful_bytes = 0;
- int64_t total_bytes = 0;
- int64_t successful_mbs = 0;
- int64_t total_mbs = 0;
-
- for (int i = 0; i < kNumDownloadSources; i++) {
- DownloadSource source = static_cast<DownloadSource>(i);
- int64_t bytes;
-
- // Only consider this download source (and send byte counts) as
- // having been used if we downloaded a non-trivial amount of bytes
- // (e.g. at least 1 MiB) that contributed to the final success of
- // the update. Otherwise we're going to end up with a lot of
- // zero-byte events in the histogram.
-
- bytes = GetCurrentBytesDownloaded(source);
- successful_bytes += bytes;
- successful_mbs += bytes / kNumBytesInOneMiB;
- SetCurrentBytesDownloaded(source, 0, true);
-
- bytes = GetTotalBytesDownloaded(source);
- total_bytes_by_source[i] = bytes;
- total_bytes += bytes;
- total_mbs += bytes / kNumBytesInOneMiB;
- SetTotalBytesDownloaded(source, 0, true);
- }
-
- int download_overhead_percentage = 0;
- if (successful_bytes > 0) {
- download_overhead_percentage =
- (total_bytes - successful_bytes) * 100ULL / successful_bytes;
- }
-
- int url_switch_count = static_cast<int>(url_switch_count_);
-
- int reboot_count = GetNumReboots();
-
- SetNumReboots(0);
-
- TimeDelta duration = GetUpdateDuration();
- TimeDelta duration_uptime = GetUpdateDurationUptime();
-
- prefs_->Delete(kPrefsUpdateTimestampStart);
- prefs_->Delete(kPrefsUpdateDurationUptime);
-
- PayloadType payload_type = CalculatePayloadType();
-
- int64_t payload_size = GetPayloadSize();
-
- int attempt_count = GetPayloadAttemptNumber();
-
- int updates_abandoned_count = num_responses_seen_ - 1;
-
- SystemState::Get()->metrics_reporter()->ReportSuccessfulUpdateMetrics(
- attempt_count,
- updates_abandoned_count,
- payload_type,
- payload_size,
- total_bytes_by_source,
- download_overhead_percentage,
- duration,
- duration_uptime,
- reboot_count,
- url_switch_count);
-}
-
-void PayloadState::UpdateNumReboots() {
- // We only update the reboot count when the system has been detected to have
- // been rebooted.
- if (!SystemState::Get()->system_rebooted()) {
- return;
- }
-
- SetNumReboots(GetNumReboots() + 1);
-}
-
-void PayloadState::SetNumReboots(uint32_t num_reboots) {
- num_reboots_ = num_reboots;
- metrics_utils::SetNumReboots(num_reboots, prefs_);
-}
-
-void PayloadState::ResetPersistedState() {
- SetPayloadAttemptNumber(0);
- SetFullPayloadAttemptNumber(0);
- SetPayloadIndex(0);
- SetUrlIndex(0);
- SetUrlFailureCount(0);
- SetUrlSwitchCount(0);
- UpdateBackoffExpiryTime(); // This will reset the backoff expiry time.
- SetUpdateTimestampStart(SystemState::Get()->clock()->GetWallclockTime());
- SetUpdateTimestampEnd(Time()); // Set to null time
- SetUpdateDurationUptime(TimeDelta::FromSeconds(0));
- ResetDownloadSourcesOnNewUpdate();
- ResetRollbackVersion();
- SetP2PNumAttempts(0);
- SetP2PFirstAttemptTimestamp(Time()); // Set to null time
- SetScatteringWaitPeriod(TimeDelta());
- SetStagingWaitPeriod(TimeDelta());
-}
-
-void PayloadState::ResetRollbackVersion() {
- rollback_version_ = "";
- powerwash_safe_prefs_->Delete(kPrefsRollbackVersion);
-}
-
-void PayloadState::ResetDownloadSourcesOnNewUpdate() {
- for (int i = 0; i < kNumDownloadSources; i++) {
- DownloadSource source = static_cast<DownloadSource>(i);
- SetCurrentBytesDownloaded(source, 0, true);
- // Note: Not resetting the TotalBytesDownloaded as we want that metric
- // to count the bytes downloaded across various update attempts until
- // we have successfully applied the update.
- }
-}
-
-string PayloadState::CalculateResponseSignature() {
- string response_sign;
- for (size_t i = 0; i < response_.packages.size(); i++) {
- const auto& package = response_.packages[i];
- response_sign += base::StringPrintf(
- "Payload %zu:\n"
- " Size = %ju\n"
- " Sha256 Hash = %s\n"
- " Metadata Size = %ju\n"
- " Metadata Signature = %s\n"
- " Is Delta = %d\n"
- " NumURLs = %zu\n",
- i,
- static_cast<uintmax_t>(package.size),
- package.hash.c_str(),
- static_cast<uintmax_t>(package.metadata_size),
- package.metadata_signature.c_str(),
- package.is_delta,
- candidate_urls_[i].size());
-
- for (size_t j = 0; j < candidate_urls_[i].size(); j++)
- response_sign += base::StringPrintf(
- " Candidate Url%zu = %s\n", j, candidate_urls_[i][j].c_str());
- }
-
- response_sign += base::StringPrintf(
- "Max Failure Count Per Url = %d\n"
- "Disable Payload Backoff = %d\n",
- response_.max_failure_count_per_url,
- response_.disable_payload_backoff);
- return response_sign;
-}
-
-void PayloadState::LoadResponseSignature() {
- string stored_value;
- if (prefs_->Exists(kPrefsCurrentResponseSignature) &&
- prefs_->GetString(kPrefsCurrentResponseSignature, &stored_value)) {
- SetResponseSignature(stored_value);
- }
-}
-
-void PayloadState::SetResponseSignature(const string& response_signature) {
- response_signature_ = response_signature;
- LOG(INFO) << "Current Response Signature = \n" << response_signature_;
- prefs_->SetString(kPrefsCurrentResponseSignature, response_signature_);
-}
-
-void PayloadState::LoadPayloadAttemptNumber() {
- SetPayloadAttemptNumber(
- GetPersistedValue(kPrefsPayloadAttemptNumber, prefs_));
-}
-
-void PayloadState::LoadFullPayloadAttemptNumber() {
- SetFullPayloadAttemptNumber(
- GetPersistedValue(kPrefsFullPayloadAttemptNumber, prefs_));
-}
-
-void PayloadState::SetPayloadAttemptNumber(int payload_attempt_number) {
- payload_attempt_number_ = payload_attempt_number;
- metrics_utils::SetPayloadAttemptNumber(payload_attempt_number, prefs_);
-}
-
-void PayloadState::SetFullPayloadAttemptNumber(
- int full_payload_attempt_number) {
- full_payload_attempt_number_ = full_payload_attempt_number;
- LOG(INFO) << "Full Payload Attempt Number = " << full_payload_attempt_number_;
- prefs_->SetInt64(kPrefsFullPayloadAttemptNumber,
- full_payload_attempt_number_);
-}
-
-void PayloadState::SetPayloadIndex(size_t payload_index) {
- payload_index_ = payload_index;
- LOG(INFO) << "Payload Index = " << payload_index_;
- prefs_->SetInt64(kPrefsUpdateStatePayloadIndex, payload_index_);
-}
-
-bool PayloadState::NextPayload() {
- if (payload_index_ >= candidate_urls_.size())
- return false;
- SetPayloadIndex(payload_index_ + 1);
- if (payload_index_ >= candidate_urls_.size())
- return false;
- SetUrlIndex(0);
- return true;
-}
-
-void PayloadState::LoadUrlIndex() {
- SetUrlIndex(GetPersistedValue(kPrefsCurrentUrlIndex, prefs_));
-}
-
-void PayloadState::SetUrlIndex(uint32_t url_index) {
- url_index_ = url_index;
- LOG(INFO) << "Current URL Index = " << url_index_;
- prefs_->SetInt64(kPrefsCurrentUrlIndex, url_index_);
-
- // Also update the download source, which is purely dependent on the
- // current URL index alone.
- UpdateCurrentDownloadSource();
-}
-
-void PayloadState::LoadScatteringWaitPeriod() {
- SetScatteringWaitPeriod(TimeDelta::FromSeconds(
- GetPersistedValue(kPrefsWallClockScatteringWaitPeriod, prefs_)));
-}
-
-void PayloadState::SetScatteringWaitPeriod(TimeDelta wait_period) {
- scattering_wait_period_ = wait_period;
- LOG(INFO) << "Scattering Wait Period (seconds) = "
- << scattering_wait_period_.InSeconds();
- if (scattering_wait_period_.InSeconds() > 0) {
- prefs_->SetInt64(kPrefsWallClockScatteringWaitPeriod,
- scattering_wait_period_.InSeconds());
- } else {
- prefs_->Delete(kPrefsWallClockScatteringWaitPeriod);
- }
-}
-
-void PayloadState::LoadStagingWaitPeriod() {
- SetStagingWaitPeriod(TimeDelta::FromSeconds(
- GetPersistedValue(kPrefsWallClockStagingWaitPeriod, prefs_)));
-}
-
-void PayloadState::SetStagingWaitPeriod(TimeDelta wait_period) {
- staging_wait_period_ = wait_period;
- LOG(INFO) << "Staging Wait Period (days) =" << staging_wait_period_.InDays();
- if (staging_wait_period_.InSeconds() > 0) {
- prefs_->SetInt64(kPrefsWallClockStagingWaitPeriod,
- staging_wait_period_.InSeconds());
- } else {
- prefs_->Delete(kPrefsWallClockStagingWaitPeriod);
- }
-}
-
-void PayloadState::LoadUrlSwitchCount() {
- SetUrlSwitchCount(GetPersistedValue(kPrefsUrlSwitchCount, prefs_));
-}
-
-void PayloadState::SetUrlSwitchCount(uint32_t url_switch_count) {
- url_switch_count_ = url_switch_count;
- LOG(INFO) << "URL Switch Count = " << url_switch_count_;
- prefs_->SetInt64(kPrefsUrlSwitchCount, url_switch_count_);
-}
-
-void PayloadState::LoadUrlFailureCount() {
- SetUrlFailureCount(GetPersistedValue(kPrefsCurrentUrlFailureCount, prefs_));
-}
-
-void PayloadState::SetUrlFailureCount(uint32_t url_failure_count) {
- url_failure_count_ = url_failure_count;
- LOG(INFO) << "Current URL (Url" << GetUrlIndex()
- << ")'s Failure Count = " << url_failure_count_;
- prefs_->SetInt64(kPrefsCurrentUrlFailureCount, url_failure_count_);
-}
-
-void PayloadState::LoadBackoffExpiryTime() {
- int64_t stored_value;
- if (!prefs_->Exists(kPrefsBackoffExpiryTime))
- return;
-
- if (!prefs_->GetInt64(kPrefsBackoffExpiryTime, &stored_value))
- return;
-
- Time stored_time = Time::FromInternalValue(stored_value);
- if (stored_time > Time::Now() + TimeDelta::FromDays(kMaxBackoffDays)) {
- LOG(ERROR) << "Invalid backoff expiry time ("
- << utils::ToString(stored_time)
- << ") in persisted state. Resetting.";
- stored_time = Time();
- }
- SetBackoffExpiryTime(stored_time);
-}
-
-void PayloadState::SetBackoffExpiryTime(const Time& new_time) {
- backoff_expiry_time_ = new_time;
- LOG(INFO) << "Backoff Expiry Time = "
- << utils::ToString(backoff_expiry_time_);
- prefs_->SetInt64(kPrefsBackoffExpiryTime,
- backoff_expiry_time_.ToInternalValue());
-}
-
-TimeDelta PayloadState::GetUpdateDuration() {
- Time end_time = update_timestamp_end_.is_null()
- ? SystemState::Get()->clock()->GetWallclockTime()
- : update_timestamp_end_;
- return end_time - update_timestamp_start_;
-}
-
-void PayloadState::LoadUpdateTimestampStart() {
- int64_t stored_value;
- Time stored_time;
- Time now = SystemState::Get()->clock()->GetWallclockTime();
-
- if (!prefs_->Exists(kPrefsUpdateTimestampStart)) {
- // The preference missing is not unexpected - in that case, just
- // use the current time as start time
- stored_time = now;
- } else if (!prefs_->GetInt64(kPrefsUpdateTimestampStart, &stored_value)) {
- LOG(ERROR) << "Invalid UpdateTimestampStart value. Resetting.";
- stored_time = now;
- } else {
- stored_time = Time::FromInternalValue(stored_value);
- }
-
- // Validation check: If the time read from disk is in the future
- // (modulo some slack to account for possible NTP drift
- // adjustments), something is fishy and we should report and
- // reset.
- TimeDelta duration_according_to_stored_time = now - stored_time;
- if (duration_according_to_stored_time < -kDurationSlack) {
- LOG(ERROR) << "The UpdateTimestampStart value ("
- << utils::ToString(stored_time) << ") in persisted state is "
- << utils::FormatTimeDelta(duration_according_to_stored_time)
- << " in the future. Resetting.";
- stored_time = now;
- }
-
- SetUpdateTimestampStart(stored_time);
-}
-
-void PayloadState::SetUpdateTimestampStart(const Time& value) {
- update_timestamp_start_ = value;
- metrics_utils::SetUpdateTimestampStart(value, prefs_);
-}
-
-void PayloadState::SetUpdateTimestampEnd(const Time& value) {
- update_timestamp_end_ = value;
- LOG(INFO) << "Update Timestamp End = "
- << utils::ToString(update_timestamp_end_);
-}
-
-TimeDelta PayloadState::GetUpdateDurationUptime() {
- return update_duration_uptime_;
-}
-
-void PayloadState::LoadUpdateDurationUptime() {
- int64_t stored_value;
- TimeDelta stored_delta;
-
- if (!prefs_->Exists(kPrefsUpdateDurationUptime)) {
- // The preference missing is not unexpected - in that case, just
- // we'll use zero as the delta
- } else if (!prefs_->GetInt64(kPrefsUpdateDurationUptime, &stored_value)) {
- LOG(ERROR) << "Invalid UpdateDurationUptime value. Resetting.";
- stored_delta = TimeDelta::FromSeconds(0);
- } else {
- stored_delta = TimeDelta::FromInternalValue(stored_value);
- }
-
- // Validation check: Uptime can never be greater than the wall-clock
- // difference (modulo some slack). If it is, report and reset
- // to the wall-clock difference.
- TimeDelta diff = GetUpdateDuration() - stored_delta;
- if (diff < -kDurationSlack) {
- LOG(ERROR) << "The UpdateDurationUptime value ("
- << utils::FormatTimeDelta(stored_delta)
- << ") in persisted state is " << utils::FormatTimeDelta(diff)
- << " larger than the wall-clock delta. Resetting.";
- stored_delta = update_duration_current_;
- }
-
- SetUpdateDurationUptime(stored_delta);
-}
-
-void PayloadState::LoadNumReboots() {
- SetNumReboots(GetPersistedValue(kPrefsNumReboots, prefs_));
-}
-
-void PayloadState::LoadRollbackHappened() {
- bool rollback_happened = false;
- powerwash_safe_prefs_->GetBoolean(kPrefsRollbackHappened, &rollback_happened);
- SetRollbackHappened(rollback_happened);
-}
-
-void PayloadState::SetRollbackHappened(bool rollback_happened) {
- LOG(INFO) << "Setting rollback-happened to " << rollback_happened << ".";
- rollback_happened_ = rollback_happened;
- if (rollback_happened) {
- powerwash_safe_prefs_->SetBoolean(kPrefsRollbackHappened,
- rollback_happened);
- } else {
- powerwash_safe_prefs_->Delete(kPrefsRollbackHappened);
- }
-}
-
-void PayloadState::LoadRollbackVersion() {
- string rollback_version;
- if (powerwash_safe_prefs_->GetString(kPrefsRollbackVersion,
- &rollback_version)) {
- SetRollbackVersion(rollback_version);
- }
-}
-
-void PayloadState::SetRollbackVersion(const string& rollback_version) {
- LOG(INFO) << "Excluding version " << rollback_version;
- rollback_version_ = rollback_version;
- powerwash_safe_prefs_->SetString(kPrefsRollbackVersion, rollback_version);
-}
-
-void PayloadState::SetUpdateDurationUptimeExtended(const TimeDelta& value,
- const Time& timestamp,
- bool use_logging) {
- update_duration_uptime_ = value;
- update_duration_uptime_timestamp_ = timestamp;
- prefs_->SetInt64(kPrefsUpdateDurationUptime,
- update_duration_uptime_.ToInternalValue());
- if (use_logging) {
- LOG(INFO) << "Update Duration Uptime = "
- << utils::FormatTimeDelta(update_duration_uptime_);
- }
-}
-
-void PayloadState::SetUpdateDurationUptime(const TimeDelta& value) {
- Time now = SystemState::Get()->clock()->GetMonotonicTime();
- SetUpdateDurationUptimeExtended(value, now, true);
-}
-
-void PayloadState::CalculateUpdateDurationUptime() {
- Time now = SystemState::Get()->clock()->GetMonotonicTime();
- TimeDelta uptime_since_last_update = now - update_duration_uptime_timestamp_;
-
- if (uptime_since_last_update > TimeDelta::FromSeconds(kUptimeResolution)) {
- TimeDelta new_uptime = update_duration_uptime_ + uptime_since_last_update;
- // We're frequently called so avoid logging this write
- SetUpdateDurationUptimeExtended(new_uptime, now, false);
- }
-}
-
-string PayloadState::GetPrefsKey(const string& prefix, DownloadSource source) {
- return prefix + "-from-" + utils::ToString(source);
-}
-
-void PayloadState::LoadCurrentBytesDownloaded(DownloadSource source) {
- string key = GetPrefsKey(kPrefsCurrentBytesDownloaded, source);
- SetCurrentBytesDownloaded(source, GetPersistedValue(key, prefs_), true);
-}
-
-void PayloadState::SetCurrentBytesDownloaded(DownloadSource source,
- uint64_t current_bytes_downloaded,
- bool log) {
- if (source >= kNumDownloadSources)
- return;
-
- // Update the in-memory value.
- current_bytes_downloaded_[source] = current_bytes_downloaded;
-
- string prefs_key = GetPrefsKey(kPrefsCurrentBytesDownloaded, source);
- prefs_->SetInt64(prefs_key, current_bytes_downloaded);
- LOG_IF(INFO, log) << "Current bytes downloaded for "
- << utils::ToString(source) << " = "
- << GetCurrentBytesDownloaded(source);
-}
-
-void PayloadState::LoadTotalBytesDownloaded(DownloadSource source) {
- string key = GetPrefsKey(kPrefsTotalBytesDownloaded, source);
- SetTotalBytesDownloaded(source, GetPersistedValue(key, prefs_), true);
-}
-
-void PayloadState::SetTotalBytesDownloaded(DownloadSource source,
- uint64_t total_bytes_downloaded,
- bool log) {
- if (source >= kNumDownloadSources)
- return;
-
- // Update the in-memory value.
- total_bytes_downloaded_[source] = total_bytes_downloaded;
-
- // Persist.
- string prefs_key = GetPrefsKey(kPrefsTotalBytesDownloaded, source);
- prefs_->SetInt64(prefs_key, total_bytes_downloaded);
- LOG_IF(INFO, log) << "Total bytes downloaded for " << utils::ToString(source)
- << " = " << GetTotalBytesDownloaded(source);
-}
-
-void PayloadState::LoadNumResponsesSeen() {
- SetNumResponsesSeen(GetPersistedValue(kPrefsNumResponsesSeen, prefs_));
-}
-
-void PayloadState::SetNumResponsesSeen(int num_responses_seen) {
- num_responses_seen_ = num_responses_seen;
- LOG(INFO) << "Num Responses Seen = " << num_responses_seen_;
- prefs_->SetInt64(kPrefsNumResponsesSeen, num_responses_seen_);
-}
-
-void PayloadState::ComputeCandidateUrls() {
- bool http_url_ok = true;
-
- if (SystemState::Get()->hardware()->IsOfficialBuild()) {
- const policy::DevicePolicy* policy = SystemState::Get()->device_policy();
- if (policy && policy->GetHttpDownloadsEnabled(&http_url_ok) && !http_url_ok)
- LOG(INFO) << "Downloads via HTTP Url are not enabled by device policy";
- } else {
- LOG(INFO) << "Allowing HTTP downloads for unofficial builds";
- http_url_ok = true;
- }
-
- candidate_urls_.clear();
- for (const auto& package : response_.packages) {
- candidate_urls_.emplace_back();
- for (const string& candidate_url : package.payload_urls) {
- if (base::StartsWith(
- candidate_url, "http://", base::CompareCase::INSENSITIVE_ASCII) &&
- !http_url_ok) {
- continue;
- }
- candidate_urls_.back().push_back(candidate_url);
- LOG(INFO) << "Candidate Url" << (candidate_urls_.back().size() - 1)
- << ": " << candidate_url;
- }
- LOG(INFO) << "Found " << candidate_urls_.back().size() << " candidate URLs "
- << "out of " << package.payload_urls.size()
- << " URLs supplied in package " << candidate_urls_.size() - 1;
- }
-}
-
-void PayloadState::UpdateEngineStarted() {
- // Flush previous state from abnormal attempt failure, if any.
- ReportAndClearPersistedAttemptMetrics();
-
- // Avoid the UpdateEngineStarted actions if this is not the first time we
- // run the update engine since reboot.
- if (!SystemState::Get()->system_rebooted())
- return;
-
- // Report time_to_reboot if we booted into a new update.
- metrics_utils::LoadAndReportTimeToReboot(
- SystemState::Get()->metrics_reporter(),
- prefs_,
- SystemState::Get()->clock());
- prefs_->Delete(kPrefsSystemUpdatedMarker);
-
- // Check if it is needed to send metrics about a failed reboot into a new
- // version.
- ReportFailedBootIfNeeded();
-}
-
-void PayloadState::ReportFailedBootIfNeeded() {
- // If the kPrefsTargetVersionInstalledFrom is present, a successfully applied
- // payload was marked as ready immediately before the last reboot, and we
- // need to check if such payload successfully rebooted or not.
- if (prefs_->Exists(kPrefsTargetVersionInstalledFrom)) {
- int64_t installed_from = 0;
- if (!prefs_->GetInt64(kPrefsTargetVersionInstalledFrom, &installed_from)) {
- LOG(ERROR) << "Error reading TargetVersionInstalledFrom on reboot.";
- return;
- }
- // Old Chrome OS devices will write 2 or 4 in this setting, with the
- // partition number. We are now using slot numbers (0 or 1) instead, so
- // the following comparison will not match if we are comparing an old
- // partition number against a new slot number, which is the correct outcome
- // since we successfully booted the new update in that case. If the boot
- // failed, we will read this value from the same version, so it will always
- // be compatible.
- if (installed_from ==
- SystemState::Get()->boot_control()->GetCurrentSlot()) {
- // A reboot was pending, but the chromebook is again in the same
- // BootDevice where the update was installed from.
- int64_t target_attempt;
- if (!prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt)) {
- LOG(ERROR) << "Error reading TargetVersionAttempt when "
- "TargetVersionInstalledFrom was present.";
- target_attempt = 1;
- }
-
- // Report the UMA metric of the current boot failure.
- SystemState::Get()->metrics_reporter()->ReportFailedUpdateCount(
- target_attempt);
- } else {
- prefs_->Delete(kPrefsTargetVersionAttempt);
- prefs_->Delete(kPrefsTargetVersionUniqueId);
- }
- prefs_->Delete(kPrefsTargetVersionInstalledFrom);
- }
-}
-
-void PayloadState::ExpectRebootInNewVersion(const string& target_version_uid) {
- // Expect to boot into the new partition in the next reboot setting the
- // TargetVersion* flags in the Prefs.
- string stored_target_version_uid;
- string target_version_id;
- string target_partition;
- int64_t target_attempt;
-
- if (prefs_->Exists(kPrefsTargetVersionUniqueId) &&
- prefs_->GetString(kPrefsTargetVersionUniqueId,
- &stored_target_version_uid) &&
- stored_target_version_uid == target_version_uid) {
- if (!prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt))
- target_attempt = 0;
- } else {
- prefs_->SetString(kPrefsTargetVersionUniqueId, target_version_uid);
- target_attempt = 0;
- }
- prefs_->SetInt64(kPrefsTargetVersionAttempt, target_attempt + 1);
-
- prefs_->SetInt64(kPrefsTargetVersionInstalledFrom,
- SystemState::Get()->boot_control()->GetCurrentSlot());
-}
-
-void PayloadState::ResetUpdateStatus() {
- // Remove the TargetVersionInstalledFrom pref so that if the machine is
- // rebooted the next boot is not flagged as failed to rebooted into the
- // new applied payload.
- prefs_->Delete(kPrefsTargetVersionInstalledFrom);
-
- // Also decrement the attempt number if it exists.
- int64_t target_attempt;
- if (prefs_->GetInt64(kPrefsTargetVersionAttempt, &target_attempt))
- prefs_->SetInt64(kPrefsTargetVersionAttempt, target_attempt - 1);
-}
-
-int PayloadState::GetP2PNumAttempts() {
- return p2p_num_attempts_;
-}
-
-void PayloadState::SetP2PNumAttempts(int value) {
- p2p_num_attempts_ = value;
- LOG(INFO) << "p2p Num Attempts = " << p2p_num_attempts_;
- prefs_->SetInt64(kPrefsP2PNumAttempts, value);
-}
-
-void PayloadState::LoadP2PNumAttempts() {
- SetP2PNumAttempts(GetPersistedValue(kPrefsP2PNumAttempts, prefs_));
-}
-
-Time PayloadState::GetP2PFirstAttemptTimestamp() {
- return p2p_first_attempt_timestamp_;
-}
-
-void PayloadState::SetP2PFirstAttemptTimestamp(const Time& time) {
- p2p_first_attempt_timestamp_ = time;
- LOG(INFO) << "p2p First Attempt Timestamp = "
- << utils::ToString(p2p_first_attempt_timestamp_);
- int64_t stored_value = time.ToInternalValue();
- prefs_->SetInt64(kPrefsP2PFirstAttemptTimestamp, stored_value);
-}
-
-void PayloadState::LoadP2PFirstAttemptTimestamp() {
- int64_t stored_value =
- GetPersistedValue(kPrefsP2PFirstAttemptTimestamp, prefs_);
- Time stored_time = Time::FromInternalValue(stored_value);
- SetP2PFirstAttemptTimestamp(stored_time);
-}
-
-void PayloadState::P2PNewAttempt() {
- // Set timestamp, if it hasn't been set already
- if (p2p_first_attempt_timestamp_.is_null()) {
- SetP2PFirstAttemptTimestamp(
- SystemState::Get()->clock()->GetWallclockTime());
- }
- // Increase number of attempts
- SetP2PNumAttempts(GetP2PNumAttempts() + 1);
-}
-
-bool PayloadState::P2PAttemptAllowed() {
- if (p2p_num_attempts_ > kMaxP2PAttempts) {
- LOG(INFO) << "Number of p2p attempts is " << p2p_num_attempts_
- << " which is greater than " << kMaxP2PAttempts
- << " - disallowing p2p.";
- return false;
- }
-
- if (!p2p_first_attempt_timestamp_.is_null()) {
- Time now = SystemState::Get()->clock()->GetWallclockTime();
- TimeDelta time_spent_attempting_p2p = now - p2p_first_attempt_timestamp_;
- if (time_spent_attempting_p2p.InSeconds() < 0) {
- LOG(ERROR) << "Time spent attempting p2p is negative"
- << " - disallowing p2p.";
- return false;
- }
- if (time_spent_attempting_p2p.InSeconds() > kMaxP2PAttemptTimeSeconds) {
- LOG(INFO) << "Time spent attempting p2p is "
- << utils::FormatTimeDelta(time_spent_attempting_p2p)
- << " which is greater than "
- << utils::FormatTimeDelta(
- TimeDelta::FromSeconds(kMaxP2PAttemptTimeSeconds))
- << " - disallowing p2p.";
- return false;
- }
- }
-
- return true;
-}
-
-int64_t PayloadState::GetPayloadSize() {
- int64_t payload_size = 0;
- for (const auto& package : response_.packages)
- payload_size += package.size;
- return payload_size;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/payload_state.h b/cros/payload_state.h
deleted file mode 100644
index db548655..00000000
--- a/cros/payload_state.h
+++ /dev/null
@@ -1,598 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_PAYLOAD_STATE_H_
-#define UPDATE_ENGINE_CROS_PAYLOAD_STATE_H_
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include <base/time/time.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-#include "update_engine/common/excluder_interface.h"
-#include "update_engine/common/metrics_constants.h"
-#include "update_engine/common/prefs_interface.h"
-#include "update_engine/cros/payload_state_interface.h"
-
-namespace chromeos_update_engine {
-
-class SystemState;
-
-// Encapsulates all the payload state required for download. This includes the
-// state necessary for handling multiple URLs in Omaha response, the backoff
-// state, etc. All state is persisted so that we use the most recently saved
-// value when resuming the update_engine process. All state is also cached in
-// memory so that we ensure we always make progress based on last known good
-// state even when there's any issue in reading/writing from the file system.
-class PayloadState : public PayloadStateInterface {
- public:
- PayloadState();
- ~PayloadState() override {}
-
- // Initializes a payload state object using the given global system state.
- // It performs the initial loading of all persisted state into memory and
- // dumps the initial state for debugging purposes. Note: the other methods
- // should be called only after calling Initialize on this object.
- bool Initialize();
-
- // Implementation of PayloadStateInterface methods.
- void SetResponse(const OmahaResponse& response) override;
- void DownloadComplete() override;
- void DownloadProgress(size_t count) override;
- void UpdateResumed() override;
- void UpdateRestarted() override;
- void UpdateSucceeded() override;
- void UpdateFailed(ErrorCode error) override;
- void ResetUpdateStatus() override;
- bool ShouldBackoffDownload() override;
- void Rollback() override;
- void ExpectRebootInNewVersion(const std::string& target_version_uid) override;
- void SetUsingP2PForDownloading(bool value) override;
-
- void SetUsingP2PForSharing(bool value) override {
- using_p2p_for_sharing_ = value;
- }
-
- inline std::string GetResponseSignature() override {
- return response_signature_;
- }
-
- inline int GetFullPayloadAttemptNumber() override {
- return full_payload_attempt_number_;
- }
-
- inline int GetPayloadAttemptNumber() override {
- return payload_attempt_number_;
- }
-
- inline std::string GetCurrentUrl() override {
- return (payload_index_ < candidate_urls_.size() &&
- url_index_ < candidate_urls_[payload_index_].size())
- ? candidate_urls_[payload_index_][url_index_]
- : "";
- }
-
- inline uint32_t GetUrlFailureCount() override { return url_failure_count_; }
-
- inline uint32_t GetUrlSwitchCount() override { return url_switch_count_; }
-
- inline int GetNumResponsesSeen() override { return num_responses_seen_; }
-
- inline base::Time GetBackoffExpiryTime() override {
- return backoff_expiry_time_;
- }
-
- base::TimeDelta GetUpdateDuration() override;
-
- base::TimeDelta GetUpdateDurationUptime() override;
-
- inline uint64_t GetCurrentBytesDownloaded(DownloadSource source) override {
- return source < kNumDownloadSources ? current_bytes_downloaded_[source] : 0;
- }
-
- inline uint64_t GetTotalBytesDownloaded(DownloadSource source) override {
- return source < kNumDownloadSources ? total_bytes_downloaded_[source] : 0;
- }
-
- inline uint32_t GetNumReboots() override { return num_reboots_; }
-
- void UpdateEngineStarted() override;
-
- inline bool GetRollbackHappened() override { return rollback_happened_; }
-
- void SetRollbackHappened(bool rollback_happened) override;
-
- inline std::string GetRollbackVersion() override { return rollback_version_; }
-
- int GetP2PNumAttempts() override;
- base::Time GetP2PFirstAttemptTimestamp() override;
- void P2PNewAttempt() override;
- bool P2PAttemptAllowed() override;
-
- bool GetUsingP2PForDownloading() const override {
- return using_p2p_for_downloading_;
- }
-
- bool GetUsingP2PForSharing() const override { return using_p2p_for_sharing_; }
-
- base::TimeDelta GetScatteringWaitPeriod() override {
- return scattering_wait_period_;
- }
-
- void SetScatteringWaitPeriod(base::TimeDelta wait_period) override;
-
- void SetStagingWaitPeriod(base::TimeDelta wait_period) override;
-
- void SetP2PUrl(const std::string& url) override { p2p_url_ = url; }
-
- std::string GetP2PUrl() const override { return p2p_url_; }
-
- bool NextPayload() override;
-
- private:
- enum class AttemptType {
- kUpdate,
- kRollback,
- };
-
- friend class PayloadStateTest;
- FRIEND_TEST(PayloadStateTest, RebootAfterUpdateFailedMetric);
- FRIEND_TEST(PayloadStateTest, RebootAfterUpdateSucceed);
- FRIEND_TEST(PayloadStateTest, RebootAfterCanceledUpdate);
- FRIEND_TEST(PayloadStateTest, RollbackHappened);
- FRIEND_TEST(PayloadStateTest, RollbackVersion);
- FRIEND_TEST(PayloadStateTest, UpdateSuccessWithWipedPrefs);
- FRIEND_TEST(PayloadStateTest, NextPayloadResetsUrlIndex);
- 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().
- void AttemptStarted(AttemptType attempt_type);
-
- // Increments the payload attempt number used for metrics.
- void IncrementPayloadAttemptNumber();
-
- // Increments the payload attempt number which governs the backoff behavior
- // at the time of the next update check.
- void IncrementFullPayloadAttemptNumber();
-
- // Advances the current URL index to the next available one. If all URLs have
- // been exhausted during the current payload download attempt (as indicated
- // by the payload attempt number), then it will increment the payload attempt
- // number and wrap around again with the first URL in the list. This also
- // updates the URL switch count, if needed.
- void IncrementUrlIndex();
-
- // Increments the failure count of the current URL. If the configured max
- // failure count is reached for this URL, it advances the current URL index
- // to the next URL and resets the failure count for that URL.
- void IncrementFailureCount();
-
- // Excludes the current payload + current candidate URL from being part of
- // future updates/retries. Whenever |SetResponse()| or |NextPayload()| decide
- // on the initial current URL index and the next payload respectively, it will
- // advanced based on exclusions.
- void ExcludeCurrentPayload();
-
- // Updates the backoff expiry time exponentially based on the current
- // payload attempt number.
- void UpdateBackoffExpiryTime();
-
- // Updates the value of current download source based on the current URL
- // index. If the download source is not one of the known sources, it's set
- // to kNumDownloadSources.
- void UpdateCurrentDownloadSource();
-
- // Updates the various metrics corresponding with the given number of bytes
- // that were downloaded recently.
- void UpdateBytesDownloaded(size_t count);
-
- // Calculates the PayloadType we're using.
- PayloadType CalculatePayloadType();
-
- // Collects and reports the various metrics related to an update attempt.
- void CollectAndReportAttemptMetrics(ErrorCode code);
-
- // Persists values related to the UpdateEngine.Attempt.* metrics so
- // we can identify later if an update attempt ends abnormally.
- void PersistAttemptMetrics();
-
- // Clears persistent state previously set using AttemptMetricsPersist().
- void ClearPersistedAttemptMetrics();
-
- // Checks if persistent state previously set using AttemptMetricsPersist()
- // exists and, if so, emits it with |attempt_result| set to
- // metrics::AttemptResult::kAbnormalTermination.
- void ReportAndClearPersistedAttemptMetrics();
-
- // Collects and reports the various metrics related to a successful update.
- void CollectAndReportSuccessfulUpdateMetrics();
-
- // Checks if we were expecting to be running in the new version but the
- // boot into the new version failed for some reason. If that's the case, an
- // UMA metric is sent reporting the number of attempts the same applied
- // payload was attempted to reboot. This function is called by UpdateAttempter
- // every time the update engine starts and there's no reboot pending.
- void ReportFailedBootIfNeeded();
-
- // Resets all the persisted state values which are maintained relative to the
- // current response signature. The response signature itself is not reset.
- void ResetPersistedState();
-
- // Resets the appropriate state related to download sources that need to be
- // reset on a new update.
- void ResetDownloadSourcesOnNewUpdate();
-
- // Calculates the response "signature", which is basically a string composed
- // of the subset of the fields in the current response that affect the
- // behavior of the PayloadState.
- std::string CalculateResponseSignature();
-
- // Initializes the current response signature from the persisted state.
- void LoadResponseSignature();
-
- // Sets the response signature to the given value. Also persists the value
- // being set so that we resume from the save value in case of a process
- // restart.
- void SetResponseSignature(const std::string& response_signature);
-
- // Initializes the payload attempt number from the persisted state.
- void LoadPayloadAttemptNumber();
-
- // Initializes the payload attempt number for full payloads from the persisted
- // state.
- void LoadFullPayloadAttemptNumber();
-
- // Sets the payload attempt number to the given value. Also persists the
- // value being set so that we resume from the same value in case of a process
- // restart.
- void SetPayloadAttemptNumber(int payload_attempt_number);
-
- // Sets the payload attempt number for full updates to the given value. Also
- // persists the value being set so that we resume from the same value in case
- // of a process restart.
- void SetFullPayloadAttemptNumber(int payload_attempt_number);
-
- // Sets the current payload index to the given value. Also persists the value
- // being set so that we resume from the same value in case of a process
- // restart.
- void SetPayloadIndex(size_t payload_index);
-
- // Initializes the current URL index from the persisted state.
- void LoadUrlIndex();
-
- // Sets the current URL index to the given value. Also persists the value
- // being set so that we resume from the same value in case of a process
- // restart.
- void SetUrlIndex(uint32_t url_index);
-
- // Initializes the current URL's failure count from the persisted stae.
- void LoadUrlFailureCount();
-
- // Sets the current URL's failure count to the given value. Also persists the
- // value being set so that we resume from the same value in case of a process
- // restart.
- void SetUrlFailureCount(uint32_t url_failure_count);
-
- // Sets |url_switch_count_| to the given value and persists the value.
- void SetUrlSwitchCount(uint32_t url_switch_count);
-
- // Initializes |url_switch_count_| from the persisted stae.
- void LoadUrlSwitchCount();
-
- // Initializes the backoff expiry time from the persisted state.
- void LoadBackoffExpiryTime();
-
- // Sets the backoff expiry time to the given value. Also persists the value
- // being set so that we resume from the same value in case of a process
- // restart.
- void SetBackoffExpiryTime(const base::Time& new_time);
-
- // Initializes |update_timestamp_start_| from the persisted state.
- void LoadUpdateTimestampStart();
-
- // Sets |update_timestamp_start_| to the given value and persists the value.
- void SetUpdateTimestampStart(const base::Time& value);
-
- // Sets |update_timestamp_end_| to the given value. This is not persisted
- // as it happens at the end of the update process where state is deleted
- // anyway.
- void SetUpdateTimestampEnd(const base::Time& value);
-
- // Initializes |update_duration_uptime_| from the persisted state.
- void LoadUpdateDurationUptime();
-
- // Helper method used in SetUpdateDurationUptime() and
- // CalculateUpdateDurationUptime().
- void SetUpdateDurationUptimeExtended(const base::TimeDelta& value,
- const base::Time& timestamp,
- bool use_logging);
-
- // Sets |update_duration_uptime_| to the given value and persists
- // the value and sets |update_duration_uptime_timestamp_| to the
- // current monotonic time.
- void SetUpdateDurationUptime(const base::TimeDelta& value);
-
- // Adds the difference between current monotonic time and
- // |update_duration_uptime_timestamp_| to |update_duration_uptime_| and
- // sets |update_duration_uptime_timestamp_| to current monotonic time.
- void CalculateUpdateDurationUptime();
-
- // Returns the full key for a download source given the prefix.
- std::string GetPrefsKey(const std::string& prefix, DownloadSource source);
-
- // Loads the number of bytes that have been currently downloaded through the
- // previous attempts from the persisted state for the given source. It's
- // reset to 0 every time we begin a full update and is continued from previous
- // attempt if we're resuming the update.
- void LoadCurrentBytesDownloaded(DownloadSource source);
-
- // Sets the number of bytes that have been currently downloaded for the
- // given source. This value is also persisted.
- void SetCurrentBytesDownloaded(DownloadSource source,
- uint64_t current_bytes_downloaded,
- bool log);
-
- // Loads the total number of bytes that have been downloaded (since the last
- // successful update) from the persisted state for the given source. It's
- // reset to 0 every time we successfully apply an update and counts the bytes
- // downloaded for both successful and failed attempts since then.
- void LoadTotalBytesDownloaded(DownloadSource source);
-
- // Sets the total number of bytes that have been downloaded so far for the
- // given source. This value is also persisted.
- void SetTotalBytesDownloaded(DownloadSource source,
- uint64_t total_bytes_downloaded,
- bool log);
-
- // Loads whether rollback has happened on this device since the last update
- // check where policy was available. This info is preserved over powerwash.
- void LoadRollbackHappened();
-
- // Loads the excluded version from our prefs file.
- void LoadRollbackVersion();
-
- // Excludes this version from getting AU'd to until we receive a new update
- // response.
- void SetRollbackVersion(const std::string& rollback_version);
-
- // Clears any excluded version.
- void ResetRollbackVersion();
-
- inline uint32_t GetUrlIndex() {
- return (url_index_ != 0 && payload_index_ < candidate_urls_.size())
- ? std::min(candidate_urls_[payload_index_].size() - 1,
- url_index_)
- : 0;
- }
-
- // Computes the list of candidate URLs from the total list of payload URLs in
- // the Omaha response.
- void ComputeCandidateUrls();
-
- // Sets |num_responses_seen_| and persist it to disk.
- void SetNumResponsesSeen(int num_responses_seen);
-
- // Initializes |num_responses_seen_| from persisted state.
- void LoadNumResponsesSeen();
-
- // Initializes |num_reboots_| from the persisted state.
- void LoadNumReboots();
-
- // Sets |num_reboots| for the update attempt. Also persists the
- // value being set so that we resume from the same value in case of a process
- // restart.
- void SetNumReboots(uint32_t num_reboots);
-
- // Checks to see if the device rebooted since the last call and if so
- // increments num_reboots.
- void UpdateNumReboots();
-
- // Loads the |kPrefsP2PFirstAttemptTimestamp| state variable from disk
- // into |p2p_first_attempt_timestamp_|.
- void LoadP2PFirstAttemptTimestamp();
-
- // Loads the |kPrefsP2PNumAttempts| state variable into |p2p_num_attempts_|.
- void LoadP2PNumAttempts();
-
- // Sets the |kPrefsP2PNumAttempts| state variable to |value|.
- void SetP2PNumAttempts(int value);
-
- // Sets the |kPrefsP2PFirstAttemptTimestamp| state variable to |time|.
- void SetP2PFirstAttemptTimestamp(const base::Time& time);
-
- // Loads the persisted scattering wallclock-based wait period.
- void LoadScatteringWaitPeriod();
-
- // Loads the persisted staging wallclock-based wait period.
- void LoadStagingWaitPeriod();
-
- // Get the total size of all payloads.
- int64_t GetPayloadSize();
-
- // Interface object with which we read/write persisted state. This must
- // be set by calling the Initialize method before calling any other method.
- PrefsInterface* prefs_;
-
- // Interface object with which we read/write persisted state. This must
- // be set by calling the Initialize method before calling any other method.
- // This object persists across powerwashes.
- PrefsInterface* powerwash_safe_prefs_;
-
- // Interface object with which we determine exclusion decisions for
- // payloads/partitions during the update. This must be set by calling the
- // Initialize method before calling any other method.
- ExcluderInterface* excluder_;
-
- // This is the current response object from Omaha.
- OmahaResponse response_;
-
- // Whether P2P is being used for downloading and sharing.
- bool using_p2p_for_downloading_;
- bool using_p2p_for_sharing_;
-
- // Stores the P2P download URL, if one is used.
- std::string p2p_url_;
-
- // The cached value of |kPrefsP2PFirstAttemptTimestamp|.
- base::Time p2p_first_attempt_timestamp_;
-
- // The cached value of |kPrefsP2PNumAttempts|.
- int p2p_num_attempts_;
-
- // This stores a "signature" of the current response. The signature here
- // refers to a subset of the current response from Omaha. Each update to
- // this value is persisted so we resume from the same value in case of a
- // process restart.
- std::string response_signature_;
-
- // The number of times we've tried to download the payload. This is
- // incremented each time we download the payload successsfully or when we
- // exhaust all failure limits for all URLs and are about to wrap around back
- // to the first URL. Each update to this value is persisted so we resume from
- // the same value in case of a process restart.
- int payload_attempt_number_;
-
- // The number of times we've tried to download the payload in full. This is
- // incremented each time we download the payload in full successsfully or
- // when we exhaust all failure limits for all URLs and are about to wrap
- // around back to the first URL. Each update to this value is persisted so
- // we resume from the same value in case of a process restart.
- int full_payload_attempt_number_;
-
- // The index of the current payload.
- size_t payload_index_ = 0;
-
- // The index of the current URL. This type is different from the one in the
- // accessor methods because |PrefsInterface| supports only int64_t but we want
- // to provide a stronger abstraction of uint32_t. Each update to this value
- // is persisted so we resume from the same value in case of a process restart.
- size_t url_index_;
-
- // The count of failures encountered in the current attempt to download using
- // the current URL (specified by url_index_). Each update to this value is
- // persisted so we resume from the same value in case of a process restart.
- int64_t url_failure_count_;
-
- // The number of times we've switched URLs.
- int32_t url_switch_count_;
-
- // The current download source based on the current URL. This value is
- // not persisted as it can be recomputed every time we update the URL.
- // We're storing this so as not to recompute this on every few bytes of
- // data we read from the socket.
- DownloadSource current_download_source_;
-
- // The number of different Omaha responses seen. Increases every time
- // a new response is seen. Resets to 0 only when the system has been
- // successfully updated.
- int num_responses_seen_;
-
- // The number of system reboots during an update attempt. Technically since
- // we don't go out of our way to not update it when not attempting an update,
- // also records the number of reboots before the next update attempt starts.
- uint32_t num_reboots_;
-
- // The timestamp until which we've to wait before attempting to download the
- // payload again, so as to backoff repeated downloads.
- base::Time backoff_expiry_time_;
-
- // The most recently calculated value of the update duration.
- base::TimeDelta update_duration_current_;
-
- // The point in time (wall-clock) that the update was started.
- base::Time update_timestamp_start_;
-
- // The point in time (wall-clock) that the update ended. If the update
- // is still in progress, this is set to the Epoch (e.g. 0).
- base::Time update_timestamp_end_;
-
- // The update duration uptime
- base::TimeDelta update_duration_uptime_;
-
- // The monotonic time when |update_duration_uptime_| was last set
- base::Time update_duration_uptime_timestamp_;
-
- // The number of bytes that have been downloaded for each source for each new
- // update attempt. If we resume an update, we'll continue from the previous
- // value, but if we get a new response or if the previous attempt failed,
- // we'll reset this to 0 to start afresh. Each update to this value is
- // persisted so we resume from the same value in case of a process restart.
- // The extra index in the array is to no-op accidental access in case the
- // return value from GetCurrentDownloadSource is used without validation.
- uint64_t current_bytes_downloaded_[kNumDownloadSources + 1];
-
- // The number of bytes that have been downloaded for each source since the
- // the last successful update. This is used to compute the overhead we incur.
- // Each update to this value is persisted so we resume from the same value in
- // case of a process restart.
- // The extra index in the array is to no-op accidental access in case the
- // return value from GetCurrentDownloadSource is used without validation.
- uint64_t total_bytes_downloaded_[kNumDownloadSources + 1];
-
- // A small timespan used when comparing wall-clock times for coping
- // with the fact that clocks drift and consequently are adjusted
- // (either forwards or backwards) via NTP.
- static const base::TimeDelta kDurationSlack;
-
- // The ordered list of the subset of payload URL candidates which are
- // allowed as per device policy.
- std::vector<std::vector<std::string>> candidate_urls_;
-
- // This stores whether rollback has happened since the last time device policy
- // was available during update check. When this is set, we're preventing
- // forced updates to avoid update-rollback loops.
- bool rollback_happened_;
-
- // This stores an excluded version set as part of rollback. When we rollback
- // we store the version of the os from which we are rolling back from in order
- // to guarantee that we do not re-update to it on the next au attempt after
- // reboot.
- std::string rollback_version_;
-
- // The number of bytes downloaded per attempt.
- int64_t attempt_num_bytes_downloaded_;
-
- // The boot time when the attempt was started.
- base::Time attempt_start_time_boot_;
-
- // The monotonic time when the attempt was started.
- base::Time attempt_start_time_monotonic_;
-
- // The connection type when the attempt started.
- metrics::ConnectionType attempt_connection_type_;
-
- // Whether we're currently rolling back.
- AttemptType attempt_type_;
-
- // The current scattering wallclock-based wait period.
- base::TimeDelta scattering_wait_period_;
-
- // The current staging wallclock-based wait period.
- base::TimeDelta staging_wait_period_;
-
- DISALLOW_COPY_AND_ASSIGN(PayloadState);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_PAYLOAD_STATE_H_
diff --git a/cros/payload_state_interface.h b/cros/payload_state_interface.h
deleted file mode 100644
index 9ead6503..00000000
--- a/cros/payload_state_interface.h
+++ /dev/null
@@ -1,215 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_PAYLOAD_STATE_INTERFACE_H_
-#define UPDATE_ENGINE_CROS_PAYLOAD_STATE_INTERFACE_H_
-
-#include <string>
-
-#include "update_engine/common/action_processor.h"
-#include "update_engine/common/constants.h"
-#include "update_engine/cros/omaha_response.h"
-
-namespace chromeos_update_engine {
-
-// Describes the methods that need to be implemented by the PayloadState class.
-// This interface has been carved out to support mocking of the PayloadState
-// object.
-class PayloadStateInterface {
- public:
- virtual ~PayloadStateInterface() = default;
-
- // Sets the internal payload state based on the given Omaha response. This
- // response could be the same or different from the one for which we've stored
- // the internal state. If it's different, then this method resets all the
- // internal state corresponding to the old response. Since the Omaha response
- // has a lot of fields that are not related to payload state, it uses only
- // a subset of the fields in the Omaha response to compare equality.
- virtual void SetResponse(const OmahaResponse& response) = 0;
-
- // This method should be called whenever we have completed downloading all
- // the bytes of a payload and have verified that its size and hash match the
- // expected values. We use this notificaiton to increment the payload attempt
- // number so that the throttle the next attempt to download the same payload
- // (in case there's an error in subsequent steps such as post-install)
- // appropriately.
- virtual void DownloadComplete() = 0;
-
- // This method should be called whenever we receive new bytes from the
- // network for the current payload. We use this notification to reset the
- // failure count for a given URL since receipt of some bytes means we are
- // able to make forward progress with the current URL.
- virtual void DownloadProgress(size_t count) = 0;
-
- // This method should be called every time we resume an update attempt.
- virtual void UpdateResumed() = 0;
-
- // This method should be called every time we begin a new update. This method
- // should not be called when we resume an update from the previously
- // downloaded point. This is used to reset the metrics for each new update.
- virtual void UpdateRestarted() = 0;
-
- // This method should be called once after an update attempt succeeds. This
- // is when the relevant UMA metrics that are tracked on a per-update-basis
- // are uploaded to the UMA server.
- virtual void UpdateSucceeded() = 0;
-
- // This method should be called whenever an update attempt fails with the
- // given error code. We use this notification to update the payload state
- // depending on the type of the error that happened.
- virtual void UpdateFailed(ErrorCode error) = 0;
-
- // This method should be called whenever a succeeded update is canceled, and
- // thus can only be called after UpdateSucceeded(). This is currently used
- // only for manual testing using the update_engine_client.
- virtual void ResetUpdateStatus() = 0;
-
- // This method should be called every time we initiate a Rollback.
- virtual void Rollback() = 0;
-
- // Sets the expectations to boot into the new version in the next reboot.
- // This function is called every time a new update is marked as ready by
- // UpdateSuccess(). |target_version_uid| is an unique identifier of the
- // applied payload. It can be any string, as long as the same string is used
- // for the same payload.
- virtual void ExpectRebootInNewVersion(
- const std::string& target_version_uid) = 0;
-
- // Sets whether P2P is being used to download the update payload. This
- // is used to keep track of download sources being used and should be called
- // before the transfer begins.
- virtual void SetUsingP2PForDownloading(bool value) = 0;
-
- // Sets whether P2P is being used for sharing the update payloads.
- virtual void SetUsingP2PForSharing(bool value) = 0;
-
- // Returns true if we should backoff the current download attempt.
- // False otherwise.
- virtual bool ShouldBackoffDownload() = 0;
-
- // Returns the currently stored response "signature". The signature is a
- // subset of fields that are of interest to the PayloadState behavior.
- virtual std::string GetResponseSignature() = 0;
-
- // Returns the payload attempt number.
- virtual int GetPayloadAttemptNumber() = 0;
-
- // Returns the payload attempt number of the attempted full payload. Returns
- // 0 for delta payloads.
- virtual int GetFullPayloadAttemptNumber() = 0;
-
- // Returns the current URL. Returns an empty string if there's no valid URL.
- virtual std::string GetCurrentUrl() = 0;
-
- // Returns the current URL's failure count.
- virtual uint32_t GetUrlFailureCount() = 0;
-
- // Returns the total number of times a new URL has been switched to
- // for the current response.
- virtual uint32_t GetUrlSwitchCount() = 0;
-
- // Returns the total number of different responses seen since the
- // last successful update.
- virtual int GetNumResponsesSeen() = 0;
-
- // Returns the expiry time for the current backoff period.
- virtual base::Time GetBackoffExpiryTime() = 0;
-
- // Returns the elapsed time used for this update, including time
- // where the device is powered off and sleeping. If the
- // update has not completed, returns the time spent so far.
- virtual base::TimeDelta GetUpdateDuration() = 0;
-
- // Returns the time used for this update not including time when
- // the device is powered off or sleeping. If the update has not
- // completed, returns the time spent so far.
- virtual base::TimeDelta GetUpdateDurationUptime() = 0;
-
- // Returns the number of bytes that have been downloaded for each source for
- // each new update attempt. If we resume an update, we'll continue from the
- // previous value, but if we get a new response or if the previous attempt
- // failed, we'll reset this to 0 to start afresh.
- virtual uint64_t GetCurrentBytesDownloaded(DownloadSource source) = 0;
-
- // Returns the total number of bytes that have been downloaded for each
- // source since the the last successful update. This is used to compute the
- // overhead we incur.
- virtual uint64_t GetTotalBytesDownloaded(DownloadSource source) = 0;
-
- // Returns the reboot count for this update attempt.
- virtual uint32_t GetNumReboots() = 0;
-
- // Called at update_engine startup to do various house-keeping.
- virtual void UpdateEngineStarted() = 0;
-
- // Returns whether a rollback happened since the last update check with policy
- // present.
- virtual bool GetRollbackHappened() = 0;
-
- // Sets whether rollback has happened on this device since the last update
- // check where policy was available. This info is preserved over powerwash.
- // This prevents forced updates happening on a rolled back device before
- // device policy is available.
- virtual void SetRollbackHappened(bool rollback_happened) = 0;
-
- // Returns the version from before a rollback if our last update was a
- // rollback.
- virtual std::string GetRollbackVersion() = 0;
-
- // Returns the value of number of attempts we've attempted to
- // download the payload via p2p.
- virtual int GetP2PNumAttempts() = 0;
-
- // Returns the value of timestamp of the first time we've attempted
- // to download the payload via p2p.
- virtual base::Time GetP2PFirstAttemptTimestamp() = 0;
-
- // Should be called every time we decide to use p2p for an update
- // attempt. This is used to increase the p2p attempt counter and
- // set the timestamp for first attempt.
- virtual void P2PNewAttempt() = 0;
-
- // Returns |true| if we are allowed to continue using p2p for
- // downloading and |false| otherwise. This is done by recording
- // and examining how many attempts have been done already as well
- // as when the first attempt was.
- virtual bool P2PAttemptAllowed() = 0;
-
- // Gets the values previously set with SetUsingP2PForDownloading() and
- // SetUsingP2PForSharing().
- virtual bool GetUsingP2PForDownloading() const = 0;
- virtual bool GetUsingP2PForSharing() const = 0;
-
- // Returns the current (persisted) scattering wallclock-based wait period.
- virtual base::TimeDelta GetScatteringWaitPeriod() = 0;
-
- // Sets and persists the scattering wallclock-based wait period.
- virtual void SetScatteringWaitPeriod(base::TimeDelta wait_period) = 0;
-
- // Sets/gets the P2P download URL, if one is to be used.
- virtual void SetP2PUrl(const std::string& url) = 0;
- virtual std::string GetP2PUrl() const = 0;
-
- // Switch to next payload.
- virtual bool NextPayload() = 0;
-
- // Sets and persists the staging wallclock-based wait period.
- virtual void SetStagingWaitPeriod(base::TimeDelta wait_period) = 0;
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_PAYLOAD_STATE_INTERFACE_H_
diff --git a/cros/payload_state_unittest.cc b/cros/payload_state_unittest.cc
deleted file mode 100644
index 5478fcae..00000000
--- a/cros/payload_state_unittest.cc
+++ /dev/null
@@ -1,1758 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/payload_state.h"
-
-#include <base/files/file_path.h>
-#include <base/files/file_util.h>
-#include <base/strings/stringprintf.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/excluder_interface.h"
-#include "update_engine/common/fake_hardware.h"
-#include "update_engine/common/metrics_reporter_interface.h"
-#include "update_engine/common/mock_excluder.h"
-#include "update_engine/common/mock_prefs.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/cros/omaha_request_action.h"
-
-using base::Time;
-using base::TimeDelta;
-using std::string;
-using testing::_;
-using testing::AnyNumber;
-using testing::AtLeast;
-using testing::Mock;
-using testing::NiceMock;
-using testing::Return;
-using testing::SetArgPointee;
-using testing::StrictMock;
-
-namespace chromeos_update_engine {
-
-const char* kCurrentBytesDownloadedFromHttps =
- "current-bytes-downloaded-from-HttpsServer";
-const char* kTotalBytesDownloadedFromHttps =
- "total-bytes-downloaded-from-HttpsServer";
-const char* kCurrentBytesDownloadedFromHttp =
- "current-bytes-downloaded-from-HttpServer";
-const char* kTotalBytesDownloadedFromHttp =
- "total-bytes-downloaded-from-HttpServer";
-const char* kCurrentBytesDownloadedFromHttpPeer =
- "current-bytes-downloaded-from-HttpPeer";
-const char* kTotalBytesDownloadedFromHttpPeer =
- "total-bytes-downloaded-from-HttpPeer";
-
-static void SetupPayloadStateWith2Urls(string hash,
- bool http_enabled,
- bool is_delta_payload,
- PayloadState* payload_state,
- OmahaResponse* response) {
- response->packages.clear();
- response->packages.push_back({.payload_urls = {"http://test", "https://test"},
- .size = 523456789,
- .metadata_size = 558123,
- .metadata_signature = "metasign",
- .hash = hash,
- .is_delta = is_delta_payload});
- response->max_failure_count_per_url = 3;
- payload_state->SetResponse(*response);
- string stored_response_sign = payload_state->GetResponseSignature();
-
- string expected_url_https_only =
- " NumURLs = 1\n"
- " Candidate Url0 = https://test\n";
-
- string expected_urls_both =
- " NumURLs = 2\n"
- " Candidate Url0 = http://test\n"
- " Candidate Url1 = https://test\n";
-
- string expected_response_sign = base::StringPrintf(
- "Payload 0:\n"
- " Size = 523456789\n"
- " Sha256 Hash = %s\n"
- " Metadata Size = 558123\n"
- " Metadata Signature = metasign\n"
- " Is Delta = %d\n"
- "%s"
- "Max Failure Count Per Url = %d\n"
- "Disable Payload Backoff = %d\n",
- hash.c_str(),
- response->packages[0].is_delta,
- (http_enabled ? expected_urls_both : expected_url_https_only).c_str(),
- response->max_failure_count_per_url,
- response->disable_payload_backoff);
- EXPECT_EQ(expected_response_sign, stored_response_sign);
-}
-
-class PayloadStateTest : public ::testing::Test {
- public:
- void SetUp() { FakeSystemState::CreateInstance(); }
-
- // TODO(b/171829801): Replace all the |MockPrefs| in this file with
- // |FakePrefs| so we don't have to catch every single unimportant mock call.
-};
-
-TEST_F(PayloadStateTest, SetResponseWorksWithEmptyResponse) {
- OmahaResponse response;
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsUpdateTimestampStart, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsUpdateDurationUptime, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttps, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttpPeer, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0)).Times(AtLeast(1));
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- payload_state.SetResponse(response);
- string stored_response_sign = payload_state.GetResponseSignature();
- string expected_response_sign =
- "Max Failure Count Per Url = 0\n"
- "Disable Payload Backoff = 0\n";
- EXPECT_EQ(expected_response_sign, stored_response_sign);
- EXPECT_EQ("", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
- EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
-}
-
-TEST_F(PayloadStateTest, SetResponseWorksWithSingleUrl) {
- OmahaResponse response;
- response.packages.push_back({.payload_urls = {"https://single.url.test"},
- .size = 123456789,
- .metadata_size = 58123,
- .metadata_signature = "msign",
- .hash = "hash"});
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsUpdateTimestampStart, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsUpdateDurationUptime, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttps, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttpPeer, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0)).Times(AtLeast(1));
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- payload_state.SetResponse(response);
- string stored_response_sign = payload_state.GetResponseSignature();
- string expected_response_sign =
- "Payload 0:\n"
- " Size = 123456789\n"
- " Sha256 Hash = hash\n"
- " Metadata Size = 58123\n"
- " Metadata Signature = msign\n"
- " Is Delta = 0\n"
- " NumURLs = 1\n"
- " Candidate Url0 = https://single.url.test\n"
- "Max Failure Count Per Url = 0\n"
- "Disable Payload Backoff = 0\n";
- EXPECT_EQ(expected_response_sign, stored_response_sign);
- EXPECT_EQ("https://single.url.test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
- EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
-}
-
-TEST_F(PayloadStateTest, SetResponseWorksWithMultipleUrls) {
- OmahaResponse response;
- response.packages.push_back({.payload_urls = {"http://multiple.url.test",
- "https://multiple.url.test"},
- .size = 523456789,
- .metadata_size = 558123,
- .metadata_signature = "metasign",
- .hash = "rhash"});
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttps, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttpPeer, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0)).Times(AtLeast(1));
-
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- payload_state.SetResponse(response);
- string stored_response_sign = payload_state.GetResponseSignature();
- string expected_response_sign =
- "Payload 0:\n"
- " Size = 523456789\n"
- " Sha256 Hash = rhash\n"
- " Metadata Size = 558123\n"
- " Metadata Signature = metasign\n"
- " Is Delta = 0\n"
- " NumURLs = 2\n"
- " Candidate Url0 = http://multiple.url.test\n"
- " Candidate Url1 = https://multiple.url.test\n"
- "Max Failure Count Per Url = 0\n"
- "Disable Payload Backoff = 0\n";
- EXPECT_EQ(expected_response_sign, stored_response_sign);
- EXPECT_EQ("http://multiple.url.test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
- EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
-}
-
-TEST_F(PayloadStateTest, CanAdvanceUrlIndexCorrectly) {
- OmahaResponse response;
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
- PayloadState payload_state;
-
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AnyNumber());
- // Payload attempt should start with 0 and then advance to 1.
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 1))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 1))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, _)).Times(AtLeast(2));
-
- // Reboots will be set
- EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, _)).Times(AtLeast(1));
-
- // Url index should go from 0 to 1 twice.
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 1)).Times(AtLeast(1));
-
- // Failure count should be called each times url index is set, so that's
- // 4 times for this test.
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 0))
- .Times(AtLeast(4));
-
- EXPECT_TRUE(payload_state.Initialize());
-
- // This does a SetResponse which causes all the states to be set to 0 for
- // the first time.
- SetupPayloadStateWith2Urls(
- "Hash1235", true, false, &payload_state, &response);
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-
- // Verify that on the first error, the URL index advances to 1.
- ErrorCode error = ErrorCode::kDownloadMetadataSignatureMismatch;
- payload_state.UpdateFailed(error);
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-
- // Verify that on the next error, the URL index wraps around to 0.
- payload_state.UpdateFailed(error);
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-
- // Verify that on the next error, it again advances to 1.
- payload_state.UpdateFailed(error);
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-
- // Verify that we switched URLs three times
- EXPECT_EQ(3U, payload_state.GetUrlSwitchCount());
-}
-
-TEST_F(PayloadStateTest, NewResponseResetsPayloadState) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
-
- // Set the first response.
- SetupPayloadStateWith2Urls(
- "Hash5823", true, false, &payload_state, &response);
- EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
-
- // Advance the URL index to 1 by faking an error.
- ErrorCode error = ErrorCode::kDownloadMetadataSignatureMismatch;
- payload_state.UpdateFailed(error);
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
-
- // Now, slightly change the response and set it again.
- SetupPayloadStateWith2Urls(
- "Hash8225", true, false, &payload_state, &response);
- EXPECT_EQ(2, payload_state.GetNumResponsesSeen());
-
- // Fake an error again.
- payload_state.UpdateFailed(error);
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
-
- // Return a third different response.
- SetupPayloadStateWith2Urls(
- "Hash9999", true, false, &payload_state, &response);
- EXPECT_EQ(3, payload_state.GetNumResponsesSeen());
-
- // Make sure the url index was reset to 0 because of the new response.
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
- EXPECT_EQ(0U,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(0U,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(
- 0U, payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpsServer));
- EXPECT_EQ(0U,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
-}
-
-TEST_F(PayloadStateTest, AllCountersGetUpdatedProperlyOnErrorCodesAndEvents) {
- OmahaResponse response;
- PayloadState payload_state;
- int progress_bytes = 100;
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
-
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 0))
- .Times(AtLeast(2));
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 1))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 2))
- .Times(AtLeast(1));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 0))
- .Times(AtLeast(2));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 1))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 2))
- .Times(AtLeast(1));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, _)).Times(AtLeast(4));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(4));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 1)).Times(AtLeast(2));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 0))
- .Times(AtLeast(7));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 1))
- .Times(AtLeast(2));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 2))
- .Times(AtLeast(1));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsUpdateTimestampStart, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsUpdateDurationUptime, _))
- .Times(AtLeast(1));
-
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttps, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttpPeer, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kCurrentBytesDownloadedFromHttp, progress_bytes))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kTotalBytesDownloadedFromHttp, progress_bytes))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 0)).Times(AtLeast(1));
-
- EXPECT_TRUE(payload_state.Initialize());
-
- SetupPayloadStateWith2Urls(
- "Hash5873", true, false, &payload_state, &response);
- EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
-
- // This should advance the URL index.
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
-
- // This should advance the failure count only.
- payload_state.UpdateFailed(ErrorCode::kDownloadTransferError);
- EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
-
- // This should advance the failure count only.
- payload_state.UpdateFailed(ErrorCode::kDownloadTransferError);
- EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(2U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
-
- // This should advance the URL index as we've reached the
- // max failure count and reset the failure count for the new URL index.
- // This should also wrap around the URL index and thus cause the payload
- // attempt number to be incremented.
- payload_state.UpdateFailed(ErrorCode::kDownloadTransferError);
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(2U, payload_state.GetUrlSwitchCount());
- EXPECT_TRUE(payload_state.ShouldBackoffDownload());
-
- // This should advance the URL index.
- payload_state.UpdateFailed(ErrorCode::kPayloadHashMismatchError);
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(3U, payload_state.GetUrlSwitchCount());
- EXPECT_TRUE(payload_state.ShouldBackoffDownload());
-
- // This should advance the URL index and payload attempt number due to
- // wrap-around of URL index.
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMissingError);
- EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(2, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(4U, payload_state.GetUrlSwitchCount());
- EXPECT_TRUE(payload_state.ShouldBackoffDownload());
-
- // This HTTP error code should only increase the failure count.
- payload_state.UpdateFailed(static_cast<ErrorCode>(
- static_cast<int>(ErrorCode::kOmahaRequestHTTPResponseBase) + 404));
- EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(2, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(4U, payload_state.GetUrlSwitchCount());
- EXPECT_TRUE(payload_state.ShouldBackoffDownload());
-
- // And that failure count should be reset when we download some bytes
- // afterwards.
- payload_state.DownloadProgress(progress_bytes);
- EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(2, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(4U, payload_state.GetUrlSwitchCount());
- EXPECT_TRUE(payload_state.ShouldBackoffDownload());
-
- // Now, slightly change the response and set it again.
- SetupPayloadStateWith2Urls(
- "Hash8532", true, false, &payload_state, &response);
- EXPECT_EQ(2, payload_state.GetNumResponsesSeen());
-
- // Make sure the url index was reset to 0 because of the new response.
- EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
- EXPECT_FALSE(payload_state.ShouldBackoffDownload());
-}
-
-TEST_F(PayloadStateTest,
- PayloadAttemptNumberIncreasesOnSuccessfulFullDownload) {
- OmahaResponse response;
- PayloadState payload_state;
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
-
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 1))
- .Times(AtLeast(1));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 1))
- .Times(AtLeast(1));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, _)).Times(AtLeast(2));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 0))
- .Times(AtLeast(1));
-
- EXPECT_TRUE(payload_state.Initialize());
-
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
-
- // This should just advance the payload attempt number;
- EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- payload_state.DownloadComplete();
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
-}
-
-TEST_F(PayloadStateTest,
- PayloadAttemptNumberIncreasesOnSuccessfulDeltaDownload) {
- OmahaResponse response;
- PayloadState payload_state;
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
-
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AnyNumber());
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsPayloadAttemptNumber, 1))
- .Times(AtLeast(1));
-
- // kPrefsFullPayloadAttemptNumber is not incremented for delta payloads.
- EXPECT_CALL(*prefs, SetInt64(kPrefsFullPayloadAttemptNumber, 0))
- .Times(AtLeast(1));
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsBackoffExpiryTime, _)).Times(1);
-
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlIndex, 0)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, SetInt64(kPrefsCurrentUrlFailureCount, 0))
- .Times(AtLeast(1));
-
- EXPECT_TRUE(payload_state.Initialize());
-
- SetupPayloadStateWith2Urls("Hash8593", true, true, &payload_state, &response);
-
- // This should just advance the payload attempt number;
- EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- payload_state.DownloadComplete();
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
-}
-
-TEST_F(PayloadStateTest, SetResponseResetsInvalidUrlIndex) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash4427", true, false, &payload_state, &response);
-
- // Generate enough events to advance URL index, failure count and
- // payload attempt number all to 1.
- payload_state.DownloadComplete();
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- payload_state.UpdateFailed(ErrorCode::kDownloadTransferError);
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
-
- // Now, simulate a corrupted url index on persisted store which gets
- // loaded when update_engine restarts.
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
- EXPECT_CALL(*prefs, Exists(_)).WillRepeatedly(Return(true));
- EXPECT_CALL(*prefs, GetInt64(_, _)).Times(AtLeast(1));
- EXPECT_CALL(*prefs, GetInt64(kPrefsPayloadAttemptNumber, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, GetInt64(kPrefsFullPayloadAttemptNumber, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, GetInt64(kPrefsCurrentUrlIndex, _))
- .WillRepeatedly(DoAll(SetArgPointee<1>(2), Return(true)));
- EXPECT_CALL(*prefs, GetInt64(kPrefsCurrentUrlFailureCount, _))
- .Times(AtLeast(1));
- EXPECT_CALL(*prefs, GetInt64(kPrefsUrlSwitchCount, _)).Times(AtLeast(1));
-
- // Note: This will be a different payload object, but the response should
- // have the same hash as before so as to not trivially reset because the
- // response was different. We want to specifically test that even if the
- // response is same, we should reset the state if we find it corrupted.
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash4427", true, false, &payload_state, &response);
-
- // Make sure all counters get reset to 0 because of the corrupted URL index
- // we supplied above.
- EXPECT_EQ(0, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
-}
-
-TEST_F(PayloadStateTest, NoBackoffInteractiveChecks) {
- OmahaResponse response;
- PayloadState payload_state;
- OmahaRequestParams params;
- params.Init("", "", {.interactive = true});
- FakeSystemState::Get()->set_request_params(&params);
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash6437", true, false, &payload_state, &response);
-
- // Simulate two failures (enough to cause payload backoff) and check
- // again that we're ready to re-download without any backoff as this is
- // an interactive check.
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_FALSE(payload_state.ShouldBackoffDownload());
-}
-
-TEST_F(PayloadStateTest, NoBackoffForP2PUpdates) {
- OmahaResponse response;
- PayloadState payload_state;
- OmahaRequestParams params;
- params.Init("", "", {});
- FakeSystemState::Get()->set_request_params(&params);
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash6437", true, false, &payload_state, &response);
-
- // Simulate two failures (enough to cause payload backoff) and check
- // again that we're ready to re-download without any backoff as this is
- // an interactive check.
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
- // Set p2p url.
- payload_state.SetUsingP2PForDownloading(true);
- payload_state.SetP2PUrl("http://mypeer:52909/path/to/file");
- // Should not backoff for p2p updates.
- EXPECT_FALSE(payload_state.ShouldBackoffDownload());
-
- payload_state.SetP2PUrl("");
- // No actual p2p update if no url is provided.
- EXPECT_TRUE(payload_state.ShouldBackoffDownload());
-}
-
-TEST_F(PayloadStateTest, NoBackoffForDeltaPayloads) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls("Hash6437", true, true, &payload_state, &response);
-
- // Simulate a successful download and see that we're ready to download
- // again without any backoff as this is a delta payload.
- payload_state.DownloadComplete();
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_FALSE(payload_state.ShouldBackoffDownload());
-
- // Simulate two failures (enough to cause payload backoff) and check
- // again that we're ready to re-download without any backoff as this is
- // a delta payload.
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(0, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_FALSE(payload_state.ShouldBackoffDownload());
-}
-
-static void CheckPayloadBackoffState(PayloadState* payload_state,
- int expected_attempt_number,
- TimeDelta expected_days) {
- payload_state->DownloadComplete();
- EXPECT_EQ(expected_attempt_number,
- payload_state->GetFullPayloadAttemptNumber());
- EXPECT_TRUE(payload_state->ShouldBackoffDownload());
- Time backoff_expiry_time = payload_state->GetBackoffExpiryTime();
- // Add 1 hour extra to the 6 hour fuzz check to tolerate edge cases.
- TimeDelta max_fuzz_delta = TimeDelta::FromHours(7);
- Time expected_min_time = Time::Now() + expected_days - max_fuzz_delta;
- Time expected_max_time = Time::Now() + expected_days + max_fuzz_delta;
- EXPECT_LT(expected_min_time.ToInternalValue(),
- backoff_expiry_time.ToInternalValue());
- EXPECT_GT(expected_max_time.ToInternalValue(),
- backoff_expiry_time.ToInternalValue());
-}
-
-TEST_F(PayloadStateTest, BackoffPeriodsAreInCorrectRange) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash8939", true, false, &payload_state, &response);
-
- CheckPayloadBackoffState(&payload_state, 1, TimeDelta::FromDays(1));
- CheckPayloadBackoffState(&payload_state, 2, TimeDelta::FromDays(2));
- CheckPayloadBackoffState(&payload_state, 3, TimeDelta::FromDays(4));
- CheckPayloadBackoffState(&payload_state, 4, TimeDelta::FromDays(8));
- CheckPayloadBackoffState(&payload_state, 5, TimeDelta::FromDays(16));
- CheckPayloadBackoffState(&payload_state, 6, TimeDelta::FromDays(16));
- CheckPayloadBackoffState(&payload_state, 7, TimeDelta::FromDays(16));
- CheckPayloadBackoffState(&payload_state, 8, TimeDelta::FromDays(16));
- CheckPayloadBackoffState(&payload_state, 9, TimeDelta::FromDays(16));
- CheckPayloadBackoffState(&payload_state, 10, TimeDelta::FromDays(16));
-}
-
-TEST_F(PayloadStateTest, BackoffLogicCanBeDisabled) {
- OmahaResponse response;
- response.disable_payload_backoff = true;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash8939", true, false, &payload_state, &response);
-
- // Simulate a successful download and see that we are ready to download
- // again without any backoff.
- payload_state.DownloadComplete();
- EXPECT_EQ(1, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(1, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_FALSE(payload_state.ShouldBackoffDownload());
-
- // Test again, this time by simulating two errors that would cause
- // the payload attempt number to increment due to wrap around. And
- // check that we are still ready to re-download without any backoff.
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- payload_state.UpdateFailed(ErrorCode::kDownloadMetadataSignatureMismatch);
- EXPECT_EQ(2, payload_state.GetPayloadAttemptNumber());
- EXPECT_EQ(2, payload_state.GetFullPayloadAttemptNumber());
- EXPECT_FALSE(payload_state.ShouldBackoffDownload());
-}
-
-TEST_F(PayloadStateTest, BytesDownloadedMetricsGetAddedToCorrectSources) {
- OmahaResponse response;
- response.disable_payload_backoff = true;
- PayloadState payload_state;
- uint64_t https_total = 0;
- uint64_t http_total = 0;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash3286", true, false, &payload_state, &response);
- EXPECT_EQ(1, payload_state.GetNumResponsesSeen());
-
- // Simulate a previous attempt with in order to set an initial non-zero value
- // for the total bytes downloaded for HTTP.
- uint64_t prev_chunk = 323456789;
- http_total += prev_chunk;
- payload_state.DownloadProgress(prev_chunk);
-
- // Ensure that the initial values for HTTP reflect this attempt.
- EXPECT_EQ(prev_chunk,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(http_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
-
- // Change the response hash so as to simulate a new response which will
- // reset the current bytes downloaded, but not the total bytes downloaded.
- SetupPayloadStateWith2Urls(
- "Hash9904", true, false, &payload_state, &response);
- EXPECT_EQ(2, payload_state.GetNumResponsesSeen());
-
- // First, simulate successful download of a few bytes over HTTP.
- uint64_t first_chunk = 5000000;
- http_total += first_chunk;
- payload_state.DownloadProgress(first_chunk);
- // Test that first all progress is made on HTTP and none on HTTPS.
- EXPECT_EQ(first_chunk,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(http_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(
- 0U, payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpsServer));
- EXPECT_EQ(https_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
-
- // Simulate an error that'll cause the url index to point to https.
- ErrorCode error = ErrorCode::kDownloadMetadataSignatureMismatch;
- payload_state.UpdateFailed(error);
-
- // Test that no new progress is made on HTTP and new progress is on HTTPS.
- uint64_t second_chunk = 23456789;
- https_total += second_chunk;
- payload_state.DownloadProgress(second_chunk);
- EXPECT_EQ(first_chunk,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(http_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(
- second_chunk,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpsServer));
- EXPECT_EQ(https_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
-
- // Simulate error to go back to http.
- payload_state.UpdateFailed(error);
- uint64_t third_chunk = 32345678;
- uint64_t http_chunk = first_chunk + third_chunk;
- http_total += third_chunk;
- payload_state.DownloadProgress(third_chunk);
-
- // Test that third chunk is again back on HTTP. HTTPS remains on second chunk.
- EXPECT_EQ(http_chunk,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(http_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(
- second_chunk,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpsServer));
- EXPECT_EQ(https_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
-
- // Simulate error (will cause URL switch), set p2p is to be used and
- // then do 42MB worth of progress
- payload_state.UpdateFailed(error);
- payload_state.SetUsingP2PForDownloading(true);
- uint64_t p2p_total = 42 * 1000 * 1000;
- payload_state.DownloadProgress(p2p_total);
-
- EXPECT_EQ(p2p_total,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpPeer));
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportSuccessfulUpdateMetrics(
- 1, _, kPayloadTypeFull, _, _, 314, _, _, _, 3));
-
- payload_state.UpdateSucceeded();
-
- // Make sure the metrics are reset after a successful update.
- EXPECT_EQ(0U,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(0U,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(
- 0U, payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpsServer));
- EXPECT_EQ(0U,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
- EXPECT_EQ(0, payload_state.GetNumResponsesSeen());
-}
-
-TEST_F(PayloadStateTest, DownloadSourcesUsedIsCorrect) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash3286", true, false, &payload_state, &response);
-
- // Simulate progress in order to mark HTTP as one of the sources used.
- uint64_t num_bytes = 42 * 1000 * 1000;
- payload_state.DownloadProgress(num_bytes);
-
- // Check that this was done via HTTP.
- EXPECT_EQ(num_bytes,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(num_bytes,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
-
- // Check that only HTTP is reported as a download source.
- int64_t total_bytes[kNumDownloadSources] = {};
- total_bytes[kDownloadSourceHttpServer] = num_bytes;
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportSuccessfulUpdateMetrics(
- _,
- _,
- _,
- _,
- test_utils::DownloadSourceMatcher(total_bytes),
- _,
- _,
- _,
- _,
- _))
- .Times(1);
-
- payload_state.UpdateSucceeded();
-}
-
-TEST_F(PayloadStateTest, RestartingUpdateResetsMetrics) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
-
- // Set the first response.
- SetupPayloadStateWith2Urls(
- "Hash5823", true, false, &payload_state, &response);
-
- uint64_t num_bytes = 10000;
- payload_state.DownloadProgress(num_bytes);
- EXPECT_EQ(num_bytes,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(num_bytes,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(
- 0U, payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpsServer));
- EXPECT_EQ(0U,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpsServer));
-
- payload_state.UpdateRestarted();
- // Make sure the current bytes downloaded is reset, but not the total bytes.
- EXPECT_EQ(0U,
- payload_state.GetCurrentBytesDownloaded(kDownloadSourceHttpServer));
- EXPECT_EQ(num_bytes,
- payload_state.GetTotalBytesDownloaded(kDownloadSourceHttpServer));
-}
-
-TEST_F(PayloadStateTest, NumRebootsIncrementsCorrectly) {
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(AtLeast(0));
- EXPECT_CALL(*prefs, SetInt64(kPrefsNumReboots, 1)).Times(AtLeast(1));
-
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- payload_state.UpdateRestarted();
- EXPECT_EQ(0U, payload_state.GetNumReboots());
-
- FakeSystemState::Get()->set_system_rebooted(true);
- payload_state.UpdateResumed();
- // Num reboots should be incremented because system rebooted detected.
- EXPECT_EQ(1U, payload_state.GetNumReboots());
-
- FakeSystemState::Get()->set_system_rebooted(false);
- payload_state.UpdateResumed();
- // Num reboots should now be 1 as reboot was not detected.
- EXPECT_EQ(1U, payload_state.GetNumReboots());
-
- // Restart the update again to verify we set the num of reboots back to 0.
- payload_state.UpdateRestarted();
- EXPECT_EQ(0U, payload_state.GetNumReboots());
-}
-
-TEST_F(PayloadStateTest, RollbackHappened) {
- FakeSystemState::Get()->set_powerwash_safe_prefs(nullptr);
- auto* mock_powerwash_safe_prefs =
- FakeSystemState::Get()->mock_powerwash_safe_prefs();
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- // Verify pre-conditions are good.
- EXPECT_FALSE(payload_state.GetRollbackHappened());
-
- // Set to true.
- EXPECT_CALL(*mock_powerwash_safe_prefs,
- SetBoolean(kPrefsRollbackHappened, true));
- payload_state.SetRollbackHappened(true);
- EXPECT_TRUE(payload_state.GetRollbackHappened());
-
- // Set to false.
- EXPECT_CALL(*mock_powerwash_safe_prefs, Delete(kPrefsRollbackHappened));
- payload_state.SetRollbackHappened(false);
- EXPECT_FALSE(payload_state.GetRollbackHappened());
-
- // Let's verify we can reload it correctly.
- EXPECT_CALL(*mock_powerwash_safe_prefs, GetBoolean(kPrefsRollbackHappened, _))
- .WillOnce(DoAll(SetArgPointee<1>(true), Return(true)));
- EXPECT_CALL(*mock_powerwash_safe_prefs,
- SetBoolean(kPrefsRollbackHappened, true));
- payload_state.LoadRollbackHappened();
- EXPECT_TRUE(payload_state.GetRollbackHappened());
-}
-
-TEST_F(PayloadStateTest, RollbackVersion) {
- FakeSystemState::Get()->set_powerwash_safe_prefs(nullptr);
- auto* mock_powerwash_safe_prefs =
- FakeSystemState::Get()->mock_powerwash_safe_prefs();
-
- // Mock out the os version and make sure it's excluded correctly.
- string rollback_version = "2345.0.0";
- OmahaRequestParams params;
- params.Init(rollback_version, "", {});
- FakeSystemState::Get()->set_request_params(&params);
-
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- // Verify pre-conditions are good.
- EXPECT_TRUE(payload_state.GetRollbackVersion().empty());
-
- EXPECT_CALL(*mock_powerwash_safe_prefs,
- SetString(kPrefsRollbackVersion, rollback_version));
- payload_state.Rollback();
-
- EXPECT_EQ(rollback_version, payload_state.GetRollbackVersion());
-
- // Change it up a little and verify we load it correctly.
- rollback_version = "2345.0.1";
- // Let's verify we can reload it correctly.
- EXPECT_CALL(*mock_powerwash_safe_prefs, GetString(kPrefsRollbackVersion, _))
- .WillOnce(DoAll(SetArgPointee<1>(rollback_version), Return(true)));
- EXPECT_CALL(*mock_powerwash_safe_prefs,
- SetString(kPrefsRollbackVersion, rollback_version));
- payload_state.LoadRollbackVersion();
- EXPECT_EQ(rollback_version, payload_state.GetRollbackVersion());
-
- // Check that we report only UpdateEngine.Rollback.* metrics in
- // UpdateSucceeded().
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportRollbackMetrics(metrics::RollbackResult::kSuccess))
- .Times(1);
-
- payload_state.UpdateSucceeded();
-}
-
-TEST_F(PayloadStateTest, DurationsAreCorrect) {
- OmahaResponse response;
- response.packages.resize(1);
-
- // Set the clock to a well-known time - 1 second on the wall-clock
- // and 2 seconds on the monotonic clock
- auto* fake_clock = FakeSystemState::Get()->fake_clock();
- fake_clock->SetWallclockTime(Time::FromInternalValue(1000000));
- fake_clock->SetMonotonicTime(Time::FromInternalValue(2000000));
-
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- // Check that durations are correct for a successful update where
- // time has advanced 7 seconds on the wall clock and 4 seconds on
- // the monotonic clock.
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
- fake_clock->SetWallclockTime(Time::FromInternalValue(8000000));
- fake_clock->SetMonotonicTime(Time::FromInternalValue(6000000));
- payload_state.UpdateSucceeded();
- EXPECT_EQ(payload_state.GetUpdateDuration().InMicroseconds(), 7000000);
- EXPECT_EQ(payload_state.GetUpdateDurationUptime().InMicroseconds(), 4000000);
-
- // Check that durations are reset when a new response comes in.
- SetupPayloadStateWith2Urls(
- "Hash8594", true, false, &payload_state, &response);
- EXPECT_EQ(payload_state.GetUpdateDuration().InMicroseconds(), 0);
- EXPECT_EQ(payload_state.GetUpdateDurationUptime().InMicroseconds(), 0);
-
- // Advance time a bit (10 secs), simulate download progress and
- // check that durations are updated.
- fake_clock->SetWallclockTime(Time::FromInternalValue(18000000));
- fake_clock->SetMonotonicTime(Time::FromInternalValue(16000000));
- payload_state.DownloadProgress(10);
- EXPECT_EQ(payload_state.GetUpdateDuration().InMicroseconds(), 10000000);
- EXPECT_EQ(payload_state.GetUpdateDurationUptime().InMicroseconds(), 10000000);
-
- // Now simulate a reboot by resetting monotonic time (to 5000) and
- // creating a new PayloadState object and check that we load the
- // durations correctly (e.g. they are the same as before).
- fake_clock->SetMonotonicTime(Time::FromInternalValue(5000));
- PayloadState payload_state2;
- EXPECT_TRUE(payload_state2.Initialize());
- payload_state2.SetResponse(response);
- EXPECT_EQ(payload_state2.GetUpdateDuration().InMicroseconds(), 10000000);
- EXPECT_EQ(payload_state2.GetUpdateDurationUptime().InMicroseconds(),
- 10000000);
-
- // Advance wall-clock by 7 seconds and monotonic clock by 6 seconds
- // and check that the durations are increased accordingly.
- fake_clock->SetWallclockTime(Time::FromInternalValue(25000000));
- fake_clock->SetMonotonicTime(Time::FromInternalValue(6005000));
- payload_state2.UpdateSucceeded();
- EXPECT_EQ(payload_state2.GetUpdateDuration().InMicroseconds(), 17000000);
- EXPECT_EQ(payload_state2.GetUpdateDurationUptime().InMicroseconds(),
- 16000000);
-}
-
-TEST_F(PayloadStateTest, RebootAfterSuccessfulUpdateTest) {
- OmahaResponse response;
-
- // Set the clock to a well-known time (t = 30 seconds).
- auto* fake_clock = FakeSystemState::Get()->fake_clock();
- fake_clock->SetMonotonicTime(
- Time::FromInternalValue(30 * Time::kMicrosecondsPerSecond));
-
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- // Make the update succeed.
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
- payload_state.UpdateSucceeded();
-
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- // Check that the marker was written.
- EXPECT_TRUE(fake_prefs->Exists(kPrefsSystemUpdatedMarker));
-
- // Now simulate a reboot and set the wallclock time to a later point
- // (t = 500 seconds). We do this by using a new PayloadState object
- // and checking that it emits the right UMA metric with the right
- // value.
- fake_clock->SetMonotonicTime(
- Time::FromInternalValue(500 * Time::kMicrosecondsPerSecond));
- PayloadState payload_state2;
- EXPECT_TRUE(payload_state2.Initialize());
-
- // Expect 500 - 30 seconds = 470 seconds ~= 7 min 50 sec
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportTimeToReboot(7));
- FakeSystemState::Get()->set_system_rebooted(true);
-
- payload_state2.UpdateEngineStarted();
-
- // Check that the marker was nuked.
- EXPECT_FALSE(fake_prefs->Exists(kPrefsSystemUpdatedMarker));
-}
-
-TEST_F(PayloadStateTest, RestartAfterCrash) {
- PayloadState payload_state;
- testing::StrictMock<MockMetricsReporter> mock_metrics_reporter;
- FakeSystemState::Get()->set_metrics_reporter(&mock_metrics_reporter);
- FakeSystemState::Get()->set_prefs(nullptr);
- auto* prefs = FakeSystemState::Get()->mock_prefs();
-
- EXPECT_TRUE(payload_state.Initialize());
-
- // Only the |kPrefsAttemptInProgress| state variable should be read.
- EXPECT_CALL(*prefs, Exists(_)).Times(0);
- EXPECT_CALL(*prefs, SetString(_, _)).Times(0);
- EXPECT_CALL(*prefs, SetInt64(_, _)).Times(0);
- EXPECT_CALL(*prefs, SetBoolean(_, _)).Times(0);
- EXPECT_CALL(*prefs, GetString(_, _)).Times(0);
- EXPECT_CALL(*prefs, GetInt64(_, _)).Times(0);
- EXPECT_CALL(*prefs, GetBoolean(_, _)).Times(0);
- EXPECT_CALL(*prefs, GetBoolean(kPrefsAttemptInProgress, _));
-
- // Simulate an update_engine restart without a reboot.
- FakeSystemState::Get()->set_system_rebooted(false);
-
- payload_state.UpdateEngineStarted();
-}
-
-TEST_F(PayloadStateTest, AbnormalTerminationAttemptMetricsNoReporting) {
- PayloadState payload_state;
-
- // If there's no marker at startup, ensure we don't report a metric.
- EXPECT_TRUE(payload_state.Initialize());
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportAbnormallyTerminatedUpdateAttemptMetrics())
- .Times(0);
- payload_state.UpdateEngineStarted();
-}
-
-TEST_F(PayloadStateTest, AbnormalTerminationAttemptMetricsReported) {
- // If we have a marker at startup, ensure it's reported and the
- // marker is then cleared.
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- fake_prefs->SetBoolean(kPrefsAttemptInProgress, true);
-
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportAbnormallyTerminatedUpdateAttemptMetrics())
- .Times(1);
- payload_state.UpdateEngineStarted();
-
- EXPECT_FALSE(fake_prefs->Exists(kPrefsAttemptInProgress));
-}
-
-TEST_F(PayloadStateTest, AbnormalTerminationAttemptMetricsClearedOnSucceess) {
- // Make sure the marker is written and cleared during an attempt and
- // also that we DO NOT emit the metric (since the attempt didn't end
- // abnormally).
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- OmahaResponse response;
- response.packages.resize(1);
- payload_state.SetResponse(response);
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportAbnormallyTerminatedUpdateAttemptMetrics())
- .Times(0);
-
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- // Attempt not in progress, should be clear.
- EXPECT_FALSE(fake_prefs->Exists(kPrefsAttemptInProgress));
-
- payload_state.UpdateRestarted();
-
- // Attempt not in progress, should be set.
- EXPECT_TRUE(fake_prefs->Exists(kPrefsAttemptInProgress));
-
- payload_state.UpdateSucceeded();
-
- // Attempt not in progress, should be clear.
- EXPECT_FALSE(fake_prefs->Exists(kPrefsAttemptInProgress));
-}
-
-TEST_F(PayloadStateTest, CandidateUrlsComputedCorrectly) {
- OmahaResponse response;
- PayloadState payload_state;
-
- policy::MockDevicePolicy disable_http_policy;
- FakeSystemState::Get()->set_device_policy(&disable_http_policy);
- EXPECT_TRUE(payload_state.Initialize());
-
- // Test with no device policy. Should default to allowing http.
- EXPECT_CALL(disable_http_policy, GetHttpDownloadsEnabled(_))
- .WillRepeatedly(Return(false));
-
- // Set the first response.
- SetupPayloadStateWith2Urls(
- "Hash8433", true, false, &payload_state, &response);
-
- // Check that we use the HTTP URL since there is no value set for allowing
- // http.
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
-
- // Test with device policy not allowing http updates.
- EXPECT_CALL(disable_http_policy, GetHttpDownloadsEnabled(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(false), Return(true)));
-
- // Reset state and set again.
- SetupPayloadStateWith2Urls(
- "Hash8433", false, false, &payload_state, &response);
-
- // Check that we skip the HTTP URL and use only the HTTPS url.
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-
- // Advance the URL index to 1 by faking an error.
- ErrorCode error = ErrorCode::kDownloadMetadataSignatureMismatch;
- payload_state.UpdateFailed(error);
-
- // Check that we still skip the HTTP URL and use only the HTTPS url.
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlSwitchCount());
-
- // Now, slightly change the response and set it again.
- SetupPayloadStateWith2Urls(
- "Hash2399", false, false, &payload_state, &response);
-
- // Check that we still skip the HTTP URL and use only the HTTPS url.
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
-
- // Now, pretend that the HTTP policy is turned on. We want to make sure
- // the new policy is honored.
- policy::MockDevicePolicy enable_http_policy;
- FakeSystemState::Get()->set_device_policy(&enable_http_policy);
- EXPECT_CALL(enable_http_policy, GetHttpDownloadsEnabled(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(true), Return(true)));
-
- // Now, set the same response using the same hash
- // so that we can test that the state is reset not because of the
- // hash but because of the policy change which results in candidate url
- // list change.
- SetupPayloadStateWith2Urls(
- "Hash2399", true, false, &payload_state, &response);
-
- // Check that we use the HTTP URL now and the failure count is reset.
- EXPECT_EQ("http://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
-
- // Fake a failure and see if we're moving over to the HTTPS url and update
- // the URL switch count properly.
- payload_state.UpdateFailed(error);
- EXPECT_EQ("https://test", payload_state.GetCurrentUrl());
- EXPECT_EQ(1U, payload_state.GetUrlSwitchCount());
- EXPECT_EQ(0U, payload_state.GetUrlFailureCount());
-}
-
-TEST_F(PayloadStateTest, PayloadTypeMetricWhenTypeIsDelta) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls("Hash6437", true, true, &payload_state, &response);
-
- // Simulate a successful download and update.
- payload_state.DownloadComplete();
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportSuccessfulUpdateMetrics(
- _, _, kPayloadTypeDelta, _, _, _, _, _, _, _));
- payload_state.UpdateSucceeded();
-
- // Mock the request to a request where the delta was disabled but Omaha sends
- // a delta anyway and test again.
- OmahaRequestParams params;
- params.set_delta_okay(false);
- FakeSystemState::Get()->set_request_params(&params);
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls("Hash6437", true, true, &payload_state, &response);
-
- payload_state.DownloadComplete();
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportSuccessfulUpdateMetrics(
- _, _, kPayloadTypeDelta, _, _, _, _, _, _, _));
- payload_state.UpdateSucceeded();
-}
-
-TEST_F(PayloadStateTest, PayloadTypeMetricWhenTypeIsForcedFull) {
- OmahaResponse response;
- PayloadState payload_state;
-
- // Mock the request to a request where the delta was disabled.
- OmahaRequestParams params;
- params.set_delta_okay(false);
- FakeSystemState::Get()->set_request_params(&params);
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash6437", true, false, &payload_state, &response);
-
- // Simulate a successful download and update.
- payload_state.DownloadComplete();
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportSuccessfulUpdateMetrics(
- _, _, kPayloadTypeForcedFull, _, _, _, _, _, _, _));
- payload_state.UpdateSucceeded();
-}
-
-TEST_F(PayloadStateTest, PayloadTypeMetricWhenTypeIsFull) {
- OmahaResponse response;
- PayloadState payload_state;
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash6437", true, false, &payload_state, &response);
-
- // Mock the request to a request where the delta is enabled, although the
- // result is full.
- OmahaRequestParams params;
- params.set_delta_okay(true);
- FakeSystemState::Get()->set_request_params(&params);
-
- // Simulate a successful download and update.
- payload_state.DownloadComplete();
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportSuccessfulUpdateMetrics(
- _, _, kPayloadTypeFull, _, _, _, _, _, _, _));
- payload_state.UpdateSucceeded();
-}
-
-TEST_F(PayloadStateTest, RebootAfterUpdateFailedMetric) {
- OmahaResponse response;
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash3141", true, false, &payload_state, &response);
-
- // Simulate a successful download and update.
- payload_state.DownloadComplete();
- payload_state.UpdateSucceeded();
- payload_state.ExpectRebootInNewVersion("Version:12345678");
-
- // Reboot into the same environment to get an UMA metric with a value of 1.
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportFailedUpdateCount(1));
- payload_state.ReportFailedBootIfNeeded();
- Mock::VerifyAndClearExpectations(
- FakeSystemState::Get()->mock_metrics_reporter());
-
- // Simulate a second update and reboot into the same environment, this should
- // send a value of 2.
- payload_state.ExpectRebootInNewVersion("Version:12345678");
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportFailedUpdateCount(2));
- payload_state.ReportFailedBootIfNeeded();
- Mock::VerifyAndClearExpectations(
- FakeSystemState::Get()->mock_metrics_reporter());
-
- // Simulate a third failed reboot to new version, but this time for a
- // different payload. This should send a value of 1 this time.
- payload_state.ExpectRebootInNewVersion("Version:3141592");
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportFailedUpdateCount(1));
- payload_state.ReportFailedBootIfNeeded();
- Mock::VerifyAndClearExpectations(
- FakeSystemState::Get()->mock_metrics_reporter());
-}
-
-TEST_F(PayloadStateTest, RebootAfterUpdateSucceed) {
- OmahaResponse response;
- PayloadState payload_state;
- FakeBootControl* fake_boot_control =
- FakeSystemState::Get()->fake_boot_control();
- fake_boot_control->SetCurrentSlot(0);
-
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash3141", true, false, &payload_state, &response);
-
- // Simulate a successful download and update.
- payload_state.DownloadComplete();
- payload_state.UpdateSucceeded();
- payload_state.ExpectRebootInNewVersion("Version:12345678");
-
- // Change the BootDevice to a different one, no metric should be sent.
- fake_boot_control->SetCurrentSlot(1);
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportFailedUpdateCount(_))
- .Times(0);
- payload_state.ReportFailedBootIfNeeded();
-
- // A second reboot in either partition should not send a metric.
- payload_state.ReportFailedBootIfNeeded();
- fake_boot_control->SetCurrentSlot(0);
- payload_state.ReportFailedBootIfNeeded();
-}
-
-TEST_F(PayloadStateTest, RebootAfterCanceledUpdate) {
- OmahaResponse response;
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash3141", true, false, &payload_state, &response);
-
- // Simulate a successful download and update.
- payload_state.DownloadComplete();
- payload_state.UpdateSucceeded();
- payload_state.ExpectRebootInNewVersion("Version:12345678");
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportFailedUpdateCount(_))
- .Times(0);
-
- // Cancel the applied update.
- payload_state.ResetUpdateStatus();
-
- // Simulate a reboot.
- payload_state.ReportFailedBootIfNeeded();
-}
-
-TEST_F(PayloadStateTest, UpdateSuccessWithWipedPrefs) {
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportFailedUpdateCount(_))
- .Times(0);
-
- // Simulate a reboot in this environment.
- payload_state.ReportFailedBootIfNeeded();
-}
-
-TEST_F(PayloadStateTest, DisallowP2PAfterTooManyAttempts) {
- OmahaResponse response;
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
-
- // Should allow exactly kMaxP2PAttempts...
- for (int n = 0; n < kMaxP2PAttempts; n++) {
- payload_state.P2PNewAttempt();
- EXPECT_TRUE(payload_state.P2PAttemptAllowed());
- }
- // ... but not more than that.
- payload_state.P2PNewAttempt();
- EXPECT_FALSE(payload_state.P2PAttemptAllowed());
-}
-
-TEST_F(PayloadStateTest, DisallowP2PAfterDeadline) {
- OmahaResponse response;
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
-
- // Set the clock to 1 second.
- Time epoch = Time::FromInternalValue(1000000);
- auto* fake_clock = FakeSystemState::Get()->fake_clock();
- fake_clock->SetWallclockTime(epoch);
-
- // Do an attempt - this will set the timestamp.
- payload_state.P2PNewAttempt();
-
- // Check that the timestamp equals what we just set.
- EXPECT_EQ(epoch, payload_state.GetP2PFirstAttemptTimestamp());
-
- // Time hasn't advanced - this should work.
- EXPECT_TRUE(payload_state.P2PAttemptAllowed());
-
- // Set clock to half the deadline - this should work.
- fake_clock->SetWallclockTime(
- epoch + TimeDelta::FromSeconds(kMaxP2PAttemptTimeSeconds) / 2);
- EXPECT_TRUE(payload_state.P2PAttemptAllowed());
-
- // Check that the first attempt timestamp hasn't changed just
- // because the wall-clock time changed.
- EXPECT_EQ(epoch, payload_state.GetP2PFirstAttemptTimestamp());
-
- // Set clock to _just_ before the deadline - this should work.
- fake_clock->SetWallclockTime(
- epoch + TimeDelta::FromSeconds(kMaxP2PAttemptTimeSeconds - 1));
- EXPECT_TRUE(payload_state.P2PAttemptAllowed());
-
- // Set clock to _just_ after the deadline - this should not work.
- fake_clock->SetWallclockTime(
- epoch + TimeDelta::FromSeconds(kMaxP2PAttemptTimeSeconds + 1));
- EXPECT_FALSE(payload_state.P2PAttemptAllowed());
-}
-
-TEST_F(PayloadStateTest, P2PStateVarsInitialValue) {
- OmahaResponse response;
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
-
- Time null_time = Time();
- EXPECT_EQ(null_time, payload_state.GetP2PFirstAttemptTimestamp());
- EXPECT_EQ(0, payload_state.GetP2PNumAttempts());
-}
-
-TEST_F(PayloadStateTest, P2PStateVarsArePersisted) {
- OmahaResponse response;
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
-
- // Set the clock to something known.
- Time time = Time::FromInternalValue(12345);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(time);
-
- // New p2p attempt - as a side-effect this will update the p2p state vars.
- payload_state.P2PNewAttempt();
- EXPECT_EQ(1, payload_state.GetP2PNumAttempts());
- EXPECT_EQ(time, payload_state.GetP2PFirstAttemptTimestamp());
-
- // Now create a new PayloadState and check that it loads the state
- // vars correctly.
- PayloadState payload_state2;
- EXPECT_TRUE(payload_state2.Initialize());
- EXPECT_EQ(1, payload_state2.GetP2PNumAttempts());
- EXPECT_EQ(time, payload_state2.GetP2PFirstAttemptTimestamp());
-}
-
-TEST_F(PayloadStateTest, P2PStateVarsAreClearedOnNewResponse) {
- OmahaResponse response;
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
- SetupPayloadStateWith2Urls(
- "Hash8593", true, false, &payload_state, &response);
-
- // Set the clock to something known.
- Time time = Time::FromInternalValue(12345);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(time);
-
- // New p2p attempt - as a side-effect this will update the p2p state vars.
- payload_state.P2PNewAttempt();
- EXPECT_EQ(1, payload_state.GetP2PNumAttempts());
- EXPECT_EQ(time, payload_state.GetP2PFirstAttemptTimestamp());
-
- // Set a new response...
- SetupPayloadStateWith2Urls(
- "Hash9904", true, false, &payload_state, &response);
-
- // ... and check that it clears the P2P state vars.
- Time null_time = Time();
- EXPECT_EQ(0, payload_state.GetP2PNumAttempts());
- EXPECT_EQ(null_time, payload_state.GetP2PFirstAttemptTimestamp());
-}
-
-TEST_F(PayloadStateTest, NextPayloadResetsUrlIndex) {
- PayloadState payload_state;
- StrictMock<MockExcluder> mock_excluder;
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetExcluder())
- .WillOnce(Return(&mock_excluder));
- EXPECT_TRUE(payload_state.Initialize());
-
- OmahaResponse response;
- response.packages.push_back(
- {.payload_urls = {"http://test1a", "http://test2a"},
- .size = 123456789,
- .metadata_size = 58123,
- .metadata_signature = "msign",
- .hash = "hash"});
- response.packages.push_back({.payload_urls = {"http://test1b"},
- .size = 123456789,
- .metadata_size = 58123,
- .metadata_signature = "msign",
- .hash = "hash"});
- payload_state.SetResponse(response);
-
- EXPECT_EQ(payload_state.GetCurrentUrl(), "http://test1a");
- payload_state.IncrementUrlIndex();
- EXPECT_EQ(payload_state.GetCurrentUrl(), "http://test2a");
-
- EXPECT_TRUE(payload_state.NextPayload());
- EXPECT_EQ(payload_state.GetCurrentUrl(), "http://test1b");
-}
-
-TEST_F(PayloadStateTest, ExcludeNoopForNonExcludables) {
- PayloadState payload_state;
- StrictMock<MockExcluder> mock_excluder;
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetExcluder())
- .WillOnce(Return(&mock_excluder));
- EXPECT_TRUE(payload_state.Initialize());
-
- OmahaResponse response;
- response.packages.push_back(
- {.payload_urls = {"http://test1a", "http://test2a"},
- .size = 123456789,
- .metadata_size = 58123,
- .metadata_signature = "msign",
- .hash = "hash",
- .can_exclude = false});
- payload_state.SetResponse(response);
-
- EXPECT_CALL(mock_excluder, Exclude(_)).Times(0);
- payload_state.ExcludeCurrentPayload();
-}
-
-TEST_F(PayloadStateTest, ExcludeOnlyCanExcludables) {
- PayloadState payload_state;
- StrictMock<MockExcluder> mock_excluder;
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetExcluder())
- .WillOnce(Return(&mock_excluder));
- EXPECT_TRUE(payload_state.Initialize());
-
- OmahaResponse response;
- 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);
-
- EXPECT_CALL(mock_excluder, Exclude(utils::GetExclusionName("http://test1a")))
- .WillOnce(Return(true));
- payload_state.ExcludeCurrentPayload();
-}
-
-TEST_F(PayloadStateTest, IncrementFailureExclusionTest) {
- PayloadState payload_state;
- StrictMock<MockExcluder> mock_excluder;
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetExcluder())
- .WillOnce(Return(&mock_excluder));
- EXPECT_TRUE(payload_state.Initialize());
-
- OmahaResponse response;
- // Critical package.
- response.packages.push_back(
- {.payload_urls = {"http://crit-test1a", "http://crit-test2a"},
- .size = 123456789,
- .metadata_size = 58123,
- .metadata_signature = "msign",
- .hash = "hash",
- .can_exclude = false});
- // 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});
- response.max_failure_count_per_url = 2;
- payload_state.SetResponse(response);
-
- // Critical package won't be excluded.
- // Increment twice as failure count allowed per URL is set to 2.
- payload_state.IncrementFailureCount();
- payload_state.IncrementFailureCount();
-
- EXPECT_TRUE(payload_state.NextPayload());
-
- // First increment failure should not exclude.
- payload_state.IncrementFailureCount();
-
- // Second increment failure should exclude.
- EXPECT_CALL(mock_excluder, Exclude(utils::GetExclusionName("http://test1a")))
- .WillOnce(Return(true));
- payload_state.IncrementFailureCount();
-}
-
-TEST_F(PayloadStateTest, HaltExclusionPostPayloadExhaustion) {
- PayloadState payload_state;
- StrictMock<MockExcluder> mock_excluder;
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetExcluder())
- .WillOnce(Return(&mock_excluder));
- EXPECT_TRUE(payload_state.Initialize());
-
- 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_F(PayloadStateTest, NonInfinitePayloadIndexIncrement) {
- PayloadState payload_state;
- EXPECT_TRUE(payload_state.Initialize());
-
- 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/cros/platform_constants_chromeos.cc b/cros/platform_constants_chromeos.cc
deleted file mode 100644
index 5a5a5214..00000000
--- a/cros/platform_constants_chromeos.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// Copyright (C) 2015 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/common/platform_constants.h"
-
-namespace chromeos_update_engine {
-namespace constants {
-
-const char kOmahaDefaultProductionURL[] =
- "https://tools.google.com/service/update2";
-const char kOmahaDefaultAUTestURL[] =
- "https://omaha-qa.sandbox.google.com/service/update2";
-const char kOmahaUpdaterID[] = "ChromeOSUpdateEngine";
-const char kOmahaPlatformName[] = "Chrome OS";
-const char kUpdatePayloadPublicKeyPath[] =
- "/usr/share/update_engine/update-payload-key.pub.pem";
-const char kUpdateCertificatesPath[] = "";
-const char kCACertificatesPath[] = "/usr/share/chromeos-ca-certificates";
-const char kOmahaResponseDeadlineFile[] = "/tmp/update-check-response-deadline";
-// This directory is wiped during powerwash.
-const char kNonVolatileDirectory[] = "/var/lib/update_engine";
-
-} // namespace constants
-} // namespace chromeos_update_engine
diff --git a/cros/power_manager_chromeos.cc b/cros/power_manager_chromeos.cc
deleted file mode 100644
index c1a28591..00000000
--- a/cros/power_manager_chromeos.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// Copyright (C) 2016 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/cros/power_manager_chromeos.h"
-
-#include <memory>
-
-#include <power_manager/dbus-constants.h>
-#include <power_manager/dbus-proxies.h>
-
-#include "update_engine/cros/dbus_connection.h"
-
-namespace chromeos_update_engine {
-
-namespace power_manager {
-std::unique_ptr<PowerManagerInterface> CreatePowerManager() {
- return std::unique_ptr<PowerManagerInterface>(new PowerManagerChromeOS());
-}
-} // namespace power_manager
-
-PowerManagerChromeOS::PowerManagerChromeOS()
- : power_manager_proxy_(DBusConnection::Get()->GetDBus()) {}
-
-bool PowerManagerChromeOS::RequestReboot() {
- LOG(INFO) << "Calling " << ::power_manager::kPowerManagerInterface << "."
- << ::power_manager::kRequestRestartMethod;
- brillo::ErrorPtr error;
- return power_manager_proxy_.RequestRestart(
- ::power_manager::REQUEST_RESTART_FOR_UPDATE,
- "update_engine applying update",
- &error);
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/power_manager_chromeos.h b/cros/power_manager_chromeos.h
deleted file mode 100644
index 89305083..00000000
--- a/cros/power_manager_chromeos.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (C) 2016 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_CROS_POWER_MANAGER_CHROMEOS_H_
-#define UPDATE_ENGINE_CROS_POWER_MANAGER_CHROMEOS_H_
-
-#include <base/macros.h>
-#include <power_manager/dbus-proxies.h>
-
-#include "update_engine/cros/power_manager_interface.h"
-
-namespace chromeos_update_engine {
-
-class PowerManagerChromeOS : public PowerManagerInterface {
- public:
- PowerManagerChromeOS();
- ~PowerManagerChromeOS() override = default;
-
- // PowerManagerInterface overrides.
- bool RequestReboot() override;
-
- private:
- // Real DBus proxy using the DBus connection.
- org::chromium::PowerManagerProxy power_manager_proxy_;
-
- DISALLOW_COPY_AND_ASSIGN(PowerManagerChromeOS);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_POWER_MANAGER_CHROMEOS_H_
diff --git a/cros/power_manager_interface.h b/cros/power_manager_interface.h
deleted file mode 100644
index 1f712d26..00000000
--- a/cros/power_manager_interface.h
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// Copyright (C) 2016 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_CROS_POWER_MANAGER_INTERFACE_H_
-#define UPDATE_ENGINE_CROS_POWER_MANAGER_INTERFACE_H_
-
-#include <memory>
-
-#include <base/macros.h>
-
-namespace chromeos_update_engine {
-
-class PowerManagerInterface {
- public:
- virtual ~PowerManagerInterface() = default;
-
- // Request the power manager to restart the device. Returns true on success.
- virtual bool RequestReboot() = 0;
-
- protected:
- PowerManagerInterface() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PowerManagerInterface);
-};
-
-namespace power_manager {
-// Factory function which create a PowerManager.
-std::unique_ptr<PowerManagerInterface> CreatePowerManager();
-} // namespace power_manager
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_POWER_MANAGER_INTERFACE_H_
diff --git a/cros/real_system_state.cc b/cros/real_system_state.cc
deleted file mode 100644
index 5f89b278..00000000
--- a/cros/real_system_state.cc
+++ /dev/null
@@ -1,182 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/real_system_state.h"
-
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <base/bind.h>
-#include <base/files/file_util.h>
-#include <base/location.h>
-#include <base/time/time.h>
-#include <brillo/message_loops/message_loop.h>
-#include <chromeos/dbus/service_constants.h>
-
-#include "update_engine/common/boot_control.h"
-#include "update_engine/common/boot_control_stub.h"
-#include "update_engine/common/constants.h"
-#include "update_engine/common/dlcservice_interface.h"
-#include "update_engine/common/hardware.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/metrics_reporter_omaha.h"
-#if USE_DBUS
-#include "update_engine/cros/dbus_connection.h"
-#endif // USE_DBUS
-#include "update_engine/update_manager/state_factory.h"
-
-namespace chromeos_update_engine {
-
-bool RealSystemState::Initialize() {
- boot_control_ = boot_control::CreateBootControl();
- if (!boot_control_) {
- LOG(WARNING) << "Unable to create BootControl instance, using stub "
- << "instead. All update attempts will fail.";
- boot_control_ = std::make_unique<BootControlStub>();
- }
-
- hardware_ = hardware::CreateHardware();
- if (!hardware_) {
- LOG(ERROR) << "Error initializing the HardwareInterface.";
- return false;
- }
-
- kiosk_app_proxy_.reset(new org::chromium::KioskAppServiceInterfaceProxy(
- DBusConnection::Get()->GetDBus(), chromeos::kKioskAppServiceName));
-
- LOG_IF(INFO, !hardware_->IsNormalBootMode()) << "Booted in dev mode.";
- LOG_IF(INFO, !hardware_->IsOfficialBuild()) << "Booted non-official build.";
-
- connection_manager_ = connection_manager::CreateConnectionManager();
- if (!connection_manager_) {
- LOG(ERROR) << "Error initializing the ConnectionManagerInterface.";
- return false;
- }
-
- power_manager_ = power_manager::CreatePowerManager();
- if (!power_manager_) {
- LOG(ERROR) << "Error initializing the PowerManagerInterface.";
- return false;
- }
-
- dlcservice_ = CreateDlcService();
- if (!dlcservice_) {
- LOG(ERROR) << "Error initializing the DlcServiceInterface.";
- return false;
- }
-
- // Initialize standard and powerwash-safe prefs.
- base::FilePath non_volatile_path;
- // TODO(deymo): Fall back to in-memory prefs if there's no physical directory
- // available.
- if (!hardware_->GetNonVolatileDirectory(&non_volatile_path)) {
- LOG(ERROR) << "Failed to get a non-volatile directory.";
- return false;
- }
- Prefs* prefs;
- prefs_.reset(prefs = new Prefs());
- if (!prefs->Init(non_volatile_path.Append(kPrefsSubDirectory))) {
- LOG(ERROR) << "Failed to initialize preferences.";
- return false;
- }
-
- base::FilePath powerwash_safe_path;
- if (!hardware_->GetPowerwashSafeDirectory(&powerwash_safe_path)) {
- // TODO(deymo): Fall-back to in-memory prefs if there's no powerwash-safe
- // directory, or disable powerwash feature.
- powerwash_safe_path = non_volatile_path.Append("powerwash-safe");
- LOG(WARNING) << "No powerwash-safe directory, using non-volatile one.";
- }
- powerwash_safe_prefs_.reset(prefs = new Prefs());
- if (!prefs->Init(
- powerwash_safe_path.Append(kPowerwashSafePrefsSubDirectory))) {
- LOG(ERROR) << "Failed to initialize powerwash preferences.";
- return false;
- }
-
- // Check the system rebooted marker file.
- std::string boot_id;
- if (utils::GetBootId(&boot_id)) {
- std::string prev_boot_id;
- system_rebooted_ = (!prefs_->GetString(kPrefsBootId, &prev_boot_id) ||
- prev_boot_id != boot_id);
- prefs_->SetString(kPrefsBootId, boot_id);
- } else {
- LOG(WARNING) << "Couldn't detect the bootid, assuming system was rebooted.";
- system_rebooted_ = true;
- }
-
- // Initialize the OmahaRequestParams with the default settings. These settings
- // will be re-initialized before every request using the actual request
- // options. This initialization here pre-loads current channel and version, so
- // the DBus service can access it.
- if (!request_params_.Init("", "", {})) {
- LOG(WARNING) << "Ignoring OmahaRequestParams initialization error. Some "
- "features might not work properly.";
- }
-
- certificate_checker_.reset(
- new CertificateChecker(prefs_.get(), &openssl_wrapper_));
- certificate_checker_->Init();
-
- update_attempter_.reset(new UpdateAttempter(certificate_checker_.get()));
-
- // Initialize the UpdateAttempter before the UpdateManager.
- update_attempter_->Init();
-
- // Initialize the Update Manager using the default state factory.
- chromeos_update_manager::State* um_state =
- chromeos_update_manager::DefaultStateFactory(&policy_provider_,
- kiosk_app_proxy_.get());
-
- if (!um_state) {
- LOG(ERROR) << "Failed to initialize the Update Manager.";
- return false;
- }
- update_manager_.reset(new chromeos_update_manager::UpdateManager(
- base::TimeDelta::FromSeconds(5),
- base::TimeDelta::FromHours(12),
- um_state));
-
- // The P2P Manager depends on the Update Manager for its initialization.
- p2p_manager_.reset(
- P2PManager::Construct(nullptr,
- update_manager_.get(),
- "cros_au",
- kMaxP2PFilesToKeep,
- base::TimeDelta::FromDays(kMaxP2PFileAgeDays)));
-
- if (!payload_state_.Initialize()) {
- LOG(ERROR) << "Failed to initialize the payload state object.";
- return false;
- }
-
- // For images that are build for debugging purposes like test images
- // initialize max kernel key version to 0xfffffffe, which is logical infinity.
- if (!hardware_->IsOfficialBuild()) {
- if (!hardware()->SetMaxKernelKeyRollforward(
- chromeos_update_manager::kRollforwardInfinity)) {
- LOG(ERROR) << "Failed to set kernel_max_rollforward to infinity for"
- << " device with test/dev image.";
- }
- }
-
- // All is well. Initialization successful.
- return true;
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/real_system_state.h b/cros/real_system_state.h
deleted file mode 100644
index 81a5e0e3..00000000
--- a/cros/real_system_state.h
+++ /dev/null
@@ -1,181 +0,0 @@
-//
-// Copyright (C) 2013 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_CROS_REAL_SYSTEM_STATE_H_
-#define UPDATE_ENGINE_CROS_REAL_SYSTEM_STATE_H_
-
-#include "update_engine/common/system_state.h"
-
-#include <memory>
-#include <set>
-
-#include <policy/device_policy.h>
-#include <kiosk-app/dbus-proxies.h>
-
-#include "update_engine/certificate_checker.h"
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/clock.h"
-#include "update_engine/common/daemon_state_interface.h"
-#include "update_engine/common/dlcservice_interface.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/metrics_reporter_interface.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/cros/connection_manager_interface.h"
-#include "update_engine/cros/metrics_reporter_omaha.h"
-#include "update_engine/cros/p2p_manager.h"
-#include "update_engine/cros/payload_state.h"
-#include "update_engine/cros/power_manager_interface.h"
-#include "update_engine/cros/update_attempter.h"
-#include "update_engine/update_manager/update_manager.h"
-
-namespace chromeos_update_engine {
-
-// A real implementation of the SystemStateInterface which is
-// used by the actual product code.
-class RealSystemState : public SystemState {
- public:
- // Constructs all system objects that do not require separate initialization;
- // see Initialize() below for the remaining ones.
- RealSystemState() = default;
- ~RealSystemState() = default;
-
- static void SetInstance(RealSystemState* system_state) {
- CHECK(g_pointer_ == nullptr) << "SystemState has been previously set.";
- g_pointer_ = system_state;
- LOG_IF(FATAL, !system_state->Initialize())
- << "Failed to initialize system state.";
- }
-
- // SystemState overrides.
- void set_device_policy(const policy::DevicePolicy* device_policy) override {
- device_policy_ = device_policy;
- }
-
- const policy::DevicePolicy* device_policy() override {
- return device_policy_;
- }
-
- BootControlInterface* boot_control() override { return boot_control_.get(); }
-
- ClockInterface* clock() override { return &clock_; }
-
- ConnectionManagerInterface* connection_manager() override {
- return connection_manager_.get();
- }
-
- HardwareInterface* hardware() override { return hardware_.get(); }
-
- MetricsReporterInterface* metrics_reporter() override {
- return &metrics_reporter_;
- }
-
- PrefsInterface* prefs() override { return prefs_.get(); }
-
- PrefsInterface* powerwash_safe_prefs() override {
- return powerwash_safe_prefs_.get();
- }
-
- PayloadStateInterface* payload_state() override { return &payload_state_; }
-
- UpdateAttempter* update_attempter() override {
- return update_attempter_.get();
- }
-
- OmahaRequestParams* request_params() override { return &request_params_; }
-
- P2PManager* p2p_manager() override { return p2p_manager_.get(); }
-
- chromeos_update_manager::UpdateManager* update_manager() override {
- return update_manager_.get();
- }
-
- PowerManagerInterface* power_manager() override {
- return power_manager_.get();
- }
-
- bool system_rebooted() override { return system_rebooted_; }
-
- DlcServiceInterface* dlcservice() override { return dlcservice_.get(); }
-
- private:
- // Initializes and sets systems objects that require an initialization
- // separately from construction. Returns |true| on success.
- bool Initialize();
-
- // Real DBus proxies using the DBus connection.
- std::unique_ptr<org::chromium::KioskAppServiceInterfaceProxy>
- kiosk_app_proxy_;
-
- // Interface for the power manager.
- std::unique_ptr<PowerManagerInterface> power_manager_;
-
- // Interface for dlcservice.
- std::unique_ptr<DlcServiceInterface> dlcservice_;
-
- // Interface for the bootloader control.
- std::unique_ptr<BootControlInterface> boot_control_;
-
- // Interface for the clock.
- Clock clock_;
-
- // The latest device policy object from the policy provider.
- const policy::DevicePolicy* device_policy_{nullptr};
-
- // The connection manager object that makes download decisions depending on
- // the current type of connection.
- std::unique_ptr<ConnectionManagerInterface> connection_manager_;
-
- // Interface for the hardware functions.
- std::unique_ptr<HardwareInterface> hardware_;
-
- // The Metrics reporter for reporting UMA stats.
- MetricsReporterOmaha metrics_reporter_;
-
- // Interface for persisted store.
- std::unique_ptr<PrefsInterface> prefs_;
-
- // Interface for persisted store that persists across powerwashes.
- std::unique_ptr<PrefsInterface> powerwash_safe_prefs_;
-
- // All state pertaining to payload state such as response, URL, backoff
- // states.
- PayloadState payload_state_;
-
- // OpenSSLWrapper and CertificateChecker used for checking SSL certificates.
- OpenSSLWrapper openssl_wrapper_;
- std::unique_ptr<CertificateChecker> certificate_checker_;
-
- // Pointer to the update attempter object.
- std::unique_ptr<UpdateAttempter> update_attempter_;
-
- // Common parameters for all Omaha requests.
- OmahaRequestParams request_params_;
-
- std::unique_ptr<P2PManager> p2p_manager_;
-
- std::unique_ptr<chromeos_update_manager::UpdateManager> update_manager_;
-
- policy::PolicyProvider policy_provider_;
-
- // If true, this is the first instance of the update engine since the system
- // rebooted. Important for tracking whether you are running instance of the
- // update engine on first boot or due to a crash/restart.
- bool system_rebooted_{false};
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_REAL_SYSTEM_STATE_H_
diff --git a/cros/requisition_util.cc b/cros/requisition_util.cc
deleted file mode 100644
index 6296d0bb..00000000
--- a/cros/requisition_util.cc
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// 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/cros/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/cros/requisition_util.h b/cros/requisition_util.h
deleted file mode 100644
index 6ec47833..00000000
--- a/cros/requisition_util.h
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// 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_CROS_REQUISITION_UTIL_H_
-#define UPDATE_ENGINE_CROS_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_CROS_REQUISITION_UTIL_H_
diff --git a/cros/requisition_util_unittest.cc b/cros/requisition_util_unittest.cc
deleted file mode 100644
index 269585eb..00000000
--- a/cros/requisition_util_unittest.cc
+++ /dev/null
@@ -1,94 +0,0 @@
-//
-// 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/cros/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/cros/shill_proxy.cc b/cros/shill_proxy.cc
deleted file mode 100644
index a3c8543a..00000000
--- a/cros/shill_proxy.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Copyright (C) 2015 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/cros/shill_proxy.h"
-
-#include "update_engine/cros/dbus_connection.h"
-
-using org::chromium::flimflam::ManagerProxy;
-using org::chromium::flimflam::ManagerProxyInterface;
-using org::chromium::flimflam::ServiceProxy;
-using org::chromium::flimflam::ServiceProxyInterface;
-
-namespace chromeos_update_engine {
-
-ShillProxy::ShillProxy()
- : bus_(DBusConnection::Get()->GetDBus()),
- manager_proxy_(new ManagerProxy(bus_)) {}
-
-ManagerProxyInterface* ShillProxy::GetManagerProxy() {
- return manager_proxy_.get();
-}
-
-std::unique_ptr<ServiceProxyInterface> ShillProxy::GetServiceForPath(
- const dbus::ObjectPath& path) {
- DCHECK(bus_.get());
- return std::unique_ptr<ServiceProxyInterface>(new ServiceProxy(bus_, path));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/shill_proxy.h b/cros/shill_proxy.h
deleted file mode 100644
index aff428a7..00000000
--- a/cros/shill_proxy.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright (C) 2015 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_CROS_SHILL_PROXY_H_
-#define UPDATE_ENGINE_CROS_SHILL_PROXY_H_
-
-#include <memory>
-#include <string>
-
-#include <base/macros.h>
-#include <dbus/bus.h>
-#include <dbus/object_path.h>
-#include <shill/dbus-proxies.h>
-
-#include "update_engine/cros/shill_proxy_interface.h"
-
-namespace chromeos_update_engine {
-
-// This class implements the connection to shill using real DBus calls.
-class ShillProxy : public ShillProxyInterface {
- public:
- ShillProxy();
- ~ShillProxy() override = default;
-
- // ShillProxyInterface overrides.
- org::chromium::flimflam::ManagerProxyInterface* GetManagerProxy() override;
- std::unique_ptr<org::chromium::flimflam::ServiceProxyInterface>
- GetServiceForPath(const dbus::ObjectPath& path) override;
-
- private:
- // A reference to the main bus for creating new ServiceProxy instances.
- scoped_refptr<dbus::Bus> bus_;
- std::unique_ptr<org::chromium::flimflam::ManagerProxyInterface>
- manager_proxy_;
-
- DISALLOW_COPY_AND_ASSIGN(ShillProxy);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_SHILL_PROXY_H_
diff --git a/cros/shill_proxy_interface.h b/cros/shill_proxy_interface.h
deleted file mode 100644
index 19e81f30..00000000
--- a/cros/shill_proxy_interface.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// Copyright (C) 2015 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_CROS_SHILL_PROXY_INTERFACE_H_
-#define UPDATE_ENGINE_CROS_SHILL_PROXY_INTERFACE_H_
-
-#include <memory>
-#include <string>
-
-#include <base/macros.h>
-#include <dbus/object_path.h>
-#include <shill/dbus-proxies.h>
-
-namespace chromeos_update_engine {
-
-// This class handles the DBus connection with shill daemon. The DBus interface
-// with shill requires to monitor or request the current service by interacting
-// with the org::chromium::flimflam::ManagerProxy and then request or monitor
-// properties on the selected org::chromium::flimflam::ServiceProxy. This class
-// provides a mockable way to access that.
-class ShillProxyInterface {
- public:
- virtual ~ShillProxyInterface() = default;
-
- // Return the ManagerProxy instance of the shill daemon. The instance is owned
- // by this ShillProxyInterface instance.
- virtual org::chromium::flimflam::ManagerProxyInterface* GetManagerProxy() = 0;
-
- // Return a ServiceProxy for the given path. The ownership of the returned
- // instance is transferred to the caller.
- virtual std::unique_ptr<org::chromium::flimflam::ServiceProxyInterface>
- GetServiceForPath(const dbus::ObjectPath& path) = 0;
-
- protected:
- ShillProxyInterface() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ShillProxyInterface);
-};
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_SHILL_PROXY_INTERFACE_H_
diff --git a/cros/update_attempter.cc b/cros/update_attempter.cc
deleted file mode 100644
index e0394807..00000000
--- a/cros/update_attempter.cc
+++ /dev/null
@@ -1,1858 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/update_attempter.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <map>
-#include <memory>
-#include <string>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/compiler_specific.h>
-#include <base/files/file_util.h>
-#include <base/logging.h>
-#include <base/rand_util.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
-#include <base/time/time.h>
-#include <brillo/data_encoding.h>
-#include <brillo/errors/error_codes.h>
-#include <brillo/message_loops/message_loop.h>
-#include <policy/device_policy.h>
-#include <policy/libpolicy.h>
-#include <update_engine/dbus-constants.h>
-
-#include "update_engine/certificate_checker.h"
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/constants.h"
-#include "update_engine/common/dlcservice_interface.h"
-#include "update_engine/common/download_action.h"
-#include "update_engine/common/excluder_interface.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/metrics_reporter_interface.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/prefs_interface.h"
-#include "update_engine/common/subprocess.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/download_action_chromeos.h"
-#include "update_engine/cros/omaha_request_action.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/omaha_response_handler_action.h"
-#include "update_engine/cros/omaha_utils.h"
-#include "update_engine/cros/p2p_manager.h"
-#include "update_engine/cros/payload_state_interface.h"
-#include "update_engine/cros/power_manager_interface.h"
-#include "update_engine/libcurl_http_fetcher.h"
-#include "update_engine/payload_consumer/filesystem_verifier_action.h"
-#include "update_engine/payload_consumer/postinstall_runner_action.h"
-#include "update_engine/update_boot_flags_action.h"
-#include "update_engine/update_manager/policy.h"
-#include "update_engine/update_manager/policy_utils.h"
-#include "update_engine/update_manager/update_manager.h"
-#include "update_engine/update_status_utils.h"
-
-using base::Bind;
-using base::Callback;
-using base::FilePath;
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-using brillo::MessageLoop;
-using chromeos_update_manager::CalculateStagingCase;
-using chromeos_update_manager::EvalStatus;
-using chromeos_update_manager::Policy;
-using chromeos_update_manager::StagingCase;
-using chromeos_update_manager::UpdateCheckParams;
-using std::map;
-using std::string;
-using std::vector;
-using update_engine::UpdateAttemptFlags;
-using update_engine::UpdateEngineStatus;
-
-namespace chromeos_update_engine {
-
-const int UpdateAttempter::kMaxDeltaUpdateFailures = 3;
-
-namespace {
-const int kMaxConsecutiveObeyProxyRequests = 20;
-
-// Minimum threshold to broadcast an status update in progress and time.
-const double kBroadcastThresholdProgress = 0.01; // 1%
-const int kBroadcastThresholdSeconds = 10;
-
-// By default autest bypasses scattering. If we want to test scattering,
-// use kScheduledAUTestURLRequest. The URL used is same in both cases, but
-// different params are passed to CheckForUpdate().
-const char kAUTestURLRequest[] = "autest";
-const char kScheduledAUTestURLRequest[] = "autest-scheduled";
-} // namespace
-
-ErrorCode GetErrorCodeForAction(AbstractAction* action, ErrorCode code) {
- if (code != ErrorCode::kError)
- return code;
-
- const string type = action->Type();
- if (type == OmahaRequestAction::StaticType())
- return ErrorCode::kOmahaRequestError;
- if (type == OmahaResponseHandlerAction::StaticType())
- return ErrorCode::kOmahaResponseHandlerError;
- if (type == FilesystemVerifierAction::StaticType())
- return ErrorCode::kFilesystemVerifierError;
- if (type == PostinstallRunnerAction::StaticType())
- return ErrorCode::kPostinstallRunnerError;
-
- return code;
-}
-
-UpdateAttempter::UpdateAttempter(CertificateChecker* cert_checker)
- : processor_(new ActionProcessor()),
- cert_checker_(cert_checker),
- is_install_(false) {}
-
-UpdateAttempter::~UpdateAttempter() {
- // Prevent any DBus communication from UpdateAttempter when shutting down the
- // daemon.
- ClearObservers();
-
- // CertificateChecker might not be initialized in unittests.
- if (cert_checker_)
- cert_checker_->SetObserver(nullptr);
- // Release ourselves as the ActionProcessor's delegate to prevent
- // re-scheduling the updates due to the processing stopped.
- processor_->set_delegate(nullptr);
-}
-
-void UpdateAttempter::Init() {
- // Pulling from the SystemState can only be done after construction, since
- // this is an aggregate of various objects (such as the UpdateAttempter),
- // which requires them all to be constructed prior to it being used.
- prefs_ = SystemState::Get()->prefs();
- omaha_request_params_ = SystemState::Get()->request_params();
-
- if (cert_checker_)
- cert_checker_->SetObserver(this);
-
- // In case of update_engine restart without a reboot we need to restore the
- // reboot needed state.
- if (GetBootTimeAtUpdate(nullptr)) {
- status_ = UpdateStatus::UPDATED_NEED_REBOOT;
- } else {
- status_ = UpdateStatus::IDLE;
- prefs_->Delete(kPrefsLastFp, {kDlcPrefsSubDir});
- }
-}
-
-bool UpdateAttempter::ScheduleUpdates() {
- if (IsBusyOrUpdateScheduled())
- return false;
-
- chromeos_update_manager::UpdateManager* const update_manager =
- SystemState::Get()->update_manager();
- CHECK(update_manager);
- Callback<void(EvalStatus, const UpdateCheckParams&)> callback =
- Bind(&UpdateAttempter::OnUpdateScheduled, base::Unretained(this));
- // We limit the async policy request to a reasonably short time, to avoid a
- // starvation due to a transient bug.
- update_manager->AsyncPolicyRequestUpdateCheckAllowed(
- callback, &Policy::UpdateCheckAllowed);
- waiting_for_scheduled_check_ = true;
- return true;
-}
-
-bool UpdateAttempter::StartUpdater() {
- // Initiate update checks.
- ScheduleUpdates();
-
- auto update_boot_flags_action = std::make_unique<UpdateBootFlagsAction>(
- SystemState::Get()->boot_control());
- aux_processor_.EnqueueAction(std::move(update_boot_flags_action));
- // Update boot flags after 45 seconds.
- MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ActionProcessor::StartProcessing,
- base::Unretained(&aux_processor_)),
- base::TimeDelta::FromSeconds(45));
-
- // Broadcast the update engine status on startup to ensure consistent system
- // state on crashes.
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&UpdateAttempter::BroadcastStatus, base::Unretained(this)));
-
- MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&UpdateAttempter::UpdateEngineStarted,
- base::Unretained(this)));
- return true;
-}
-
-void UpdateAttempter::CertificateChecked(ServerToCheck server_to_check,
- CertificateCheckResult result) {
- SystemState::Get()->metrics_reporter()->ReportCertificateCheckMetrics(
- server_to_check, result);
-}
-
-bool UpdateAttempter::CheckAndReportDailyMetrics() {
- int64_t stored_value;
- Time now = SystemState::Get()->clock()->GetWallclockTime();
- if (SystemState::Get()->prefs()->Exists(kPrefsDailyMetricsLastReportedAt) &&
- SystemState::Get()->prefs()->GetInt64(kPrefsDailyMetricsLastReportedAt,
- &stored_value)) {
- Time last_reported_at = Time::FromInternalValue(stored_value);
- TimeDelta time_reported_since = now - last_reported_at;
- if (time_reported_since.InSeconds() < 0) {
- LOG(WARNING) << "Last reported daily metrics "
- << utils::FormatTimeDelta(time_reported_since) << " ago "
- << "which is negative. Either the system clock is wrong or "
- << "the kPrefsDailyMetricsLastReportedAt state variable "
- << "is wrong.";
- // In this case, report daily metrics to reset.
- } else {
- if (time_reported_since.InSeconds() < 24 * 60 * 60) {
- LOG(INFO) << "Last reported daily metrics "
- << utils::FormatTimeDelta(time_reported_since) << " ago.";
- return false;
- }
- LOG(INFO) << "Last reported daily metrics "
- << utils::FormatTimeDelta(time_reported_since) << " ago, "
- << "which is more than 24 hours ago.";
- }
- }
-
- LOG(INFO) << "Reporting daily metrics.";
- SystemState::Get()->prefs()->SetInt64(kPrefsDailyMetricsLastReportedAt,
- now.ToInternalValue());
-
- ReportOSAge();
-
- return true;
-}
-
-void UpdateAttempter::ReportOSAge() {
- struct stat sb;
- if (stat("/etc/lsb-release", &sb) != 0) {
- PLOG(ERROR) << "Error getting file status for /etc/lsb-release "
- << "(Note: this may happen in some unit tests)";
- return;
- }
-
- Time lsb_release_timestamp = Time::FromTimeSpec(sb.st_ctim);
- Time now = SystemState::Get()->clock()->GetWallclockTime();
- TimeDelta age = now - lsb_release_timestamp;
- if (age.InSeconds() < 0) {
- LOG(ERROR) << "The OS age (" << utils::FormatTimeDelta(age)
- << ") is negative. Maybe the clock is wrong? "
- << "(Note: this may happen in some unit tests.)";
- return;
- }
-
- SystemState::Get()->metrics_reporter()->ReportDailyMetrics(age);
-}
-
-void UpdateAttempter::Update(const UpdateCheckParams& params) {
- // This is normally called frequently enough so it's appropriate to use as a
- // hook for reporting daily metrics.
- // TODO(garnold) This should be hooked to a separate (reliable and consistent)
- // timeout event.
- CheckAndReportDailyMetrics();
-
- fake_update_success_ = false;
- if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) {
- // Although we have applied an update, we still want to ping Omaha
- // to ensure the number of active statistics is accurate.
- //
- // Also convey to the UpdateEngine.Check.Result metric that we're
- // not performing an update check because of this.
- LOG(INFO) << "Not updating b/c we already updated and we're waiting for "
- << "reboot, we'll ping Omaha instead";
- SystemState::Get()->metrics_reporter()->ReportUpdateCheckMetrics(
- metrics::CheckResult::kRebootPending,
- metrics::CheckReaction::kUnset,
- metrics::DownloadErrorCode::kUnset);
- PingOmaha();
- return;
- }
- if (status_ != UpdateStatus::IDLE) {
- // Update in progress. Do nothing
- return;
- }
-
- if (!CalculateUpdateParams(params)) {
- return;
- }
-
- BuildUpdateActions(params.interactive);
-
- SetStatusAndNotify(UpdateStatus::CHECKING_FOR_UPDATE);
-
- // Update the last check time here; it may be re-updated when an Omaha
- // response is received, but this will prevent us from repeatedly scheduling
- // checks in the case where a response is not received.
- UpdateLastCheckedTime();
-
- ScheduleProcessingStart();
-}
-
-void UpdateAttempter::RefreshDevicePolicy() {
- // Lazy initialize the policy provider, or reload the latest policy data.
- if (!policy_provider_.get())
- policy_provider_.reset(new policy::PolicyProvider());
- policy_provider_->Reload();
-
- const policy::DevicePolicy* device_policy = nullptr;
- if (policy_provider_->device_policy_is_loaded())
- device_policy = &policy_provider_->GetDevicePolicy();
-
- if (device_policy)
- LOG(INFO) << "Device policies/settings present";
- else
- LOG(INFO) << "No device policies/settings present.";
-
- SystemState::Get()->set_device_policy(device_policy);
- SystemState::Get()->p2p_manager()->SetDevicePolicy(device_policy);
-}
-
-void UpdateAttempter::CalculateP2PParams(bool interactive) {
- bool use_p2p_for_downloading = false;
- bool use_p2p_for_sharing = false;
-
- // Never use p2p for downloading in interactive checks unless the developer
- // has opted in for it via a marker file.
- //
- // (Why would a developer want to opt in? If they are working on the
- // update_engine or p2p codebases so they can actually test their code.)
-
- if (!SystemState::Get()->p2p_manager()->IsP2PEnabled()) {
- LOG(INFO) << "p2p is not enabled - disallowing p2p for both"
- << " downloading and sharing.";
- } else {
- // Allow p2p for sharing, even in interactive checks.
- use_p2p_for_sharing = true;
- if (!interactive) {
- LOG(INFO) << "Non-interactive check - allowing p2p for downloading";
- use_p2p_for_downloading = true;
- } else {
- LOG(INFO) << "Forcibly disabling use of p2p for downloading "
- << "since this update attempt is interactive.";
- }
- }
-
- PayloadStateInterface* const payload_state =
- SystemState::Get()->payload_state();
- payload_state->SetUsingP2PForDownloading(use_p2p_for_downloading);
- payload_state->SetUsingP2PForSharing(use_p2p_for_sharing);
-}
-
-bool UpdateAttempter::CalculateUpdateParams(const UpdateCheckParams& params) {
- http_response_code_ = 0;
- PayloadStateInterface* const payload_state =
- SystemState::Get()->payload_state();
-
- // Refresh the policy before computing all the update parameters.
- RefreshDevicePolicy();
-
- // Check whether we need to clear the rollback-happened preference after
- // policy is available again.
- UpdateRollbackHappened();
-
- CalculateStagingParams(params.interactive);
- // If staging_wait_time_ wasn't set, staging is off, use scattering instead.
- if (staging_wait_time_.InSeconds() == 0) {
- CalculateScatteringParams(params.interactive);
- }
-
- CalculateP2PParams(params.interactive);
- if (payload_state->GetUsingP2PForDownloading() ||
- payload_state->GetUsingP2PForSharing()) {
- // OK, p2p is to be used - start it and perform housekeeping.
- if (!StartP2PAndPerformHousekeeping()) {
- // If this fails, disable p2p for this attempt
- LOG(INFO) << "Forcibly disabling use of p2p since starting p2p or "
- << "performing housekeeping failed.";
- payload_state->SetUsingP2PForDownloading(false);
- payload_state->SetUsingP2PForSharing(false);
- }
- }
-
- if (!omaha_request_params_->Init(
- forced_app_version_, forced_omaha_url_, params)) {
- LOG(ERROR) << "Unable to initialize Omaha request params.";
- return false;
- }
-
- // The function |CalculateDlcParams| makes use of the function |GetAppId| from
- // |OmahaRequestParams|, so to ensure that the return from |GetAppId|
- // doesn't change, no changes to the values |download_channel_|,
- // |image_props_.product_id| and |image_props_.canary_product_id| from
- // |omaha_request_params_| shall be made below this line.
- CalculateDlcParams();
-
- LOG(INFO) << "target_version_prefix = "
- << omaha_request_params_->target_version_prefix()
- << ", rollback_allowed = "
- << omaha_request_params_->rollback_allowed()
- << ", scatter_factor_in_seconds = "
- << utils::FormatSecs(scatter_factor_.InSeconds());
-
- LOG(INFO) << "Wall Clock Based Wait Enabled = "
- << omaha_request_params_->wall_clock_based_wait_enabled()
- << ", Update Check Count Wait Enabled = "
- << omaha_request_params_->update_check_count_wait_enabled()
- << ", Waiting Period = "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
-
- LOG(INFO) << "Use p2p For Downloading = "
- << payload_state->GetUsingP2PForDownloading()
- << ", Use p2p For Sharing = "
- << payload_state->GetUsingP2PForSharing();
-
- obeying_proxies_ = true;
- if (proxy_manual_checks_ == 0) {
- LOG(INFO) << "forced to obey proxies";
- // If forced to obey proxies, every 20th request will not use proxies
- proxy_manual_checks_++;
- LOG(INFO) << "proxy manual checks: " << proxy_manual_checks_;
- if (proxy_manual_checks_ >= kMaxConsecutiveObeyProxyRequests) {
- proxy_manual_checks_ = 0;
- obeying_proxies_ = false;
- }
- } else if (base::RandInt(0, 4) == 0) {
- obeying_proxies_ = false;
- }
- LOG_IF(INFO, !obeying_proxies_)
- << "To help ensure updates work, this update check we are ignoring the "
- << "proxy settings and using direct connections.";
-
- DisableDeltaUpdateIfNeeded();
- return true;
-}
-
-void UpdateAttempter::CalculateScatteringParams(bool interactive) {
- // Take a copy of the old scatter value before we update it, as
- // we need to update the waiting period if this value changes.
- TimeDelta old_scatter_factor = scatter_factor_;
- const policy::DevicePolicy* device_policy =
- SystemState::Get()->device_policy();
- if (device_policy) {
- int64_t new_scatter_factor_in_secs = 0;
- device_policy->GetScatterFactorInSeconds(&new_scatter_factor_in_secs);
- if (new_scatter_factor_in_secs < 0) // sanitize input, just in case.
- new_scatter_factor_in_secs = 0;
- scatter_factor_ = TimeDelta::FromSeconds(new_scatter_factor_in_secs);
- }
-
- bool is_scatter_enabled = false;
- if (scatter_factor_.InSeconds() == 0) {
- LOG(INFO) << "Scattering disabled since scatter factor is set to 0";
- } else if (interactive) {
- LOG(INFO) << "Scattering disabled as this is an interactive update check";
- } else if (SystemState::Get()->hardware()->IsOOBEEnabled() &&
- !SystemState::Get()->hardware()->IsOOBEComplete(nullptr)) {
- LOG(INFO) << "Scattering disabled since OOBE is enabled but not complete "
- "yet";
- } else {
- is_scatter_enabled = true;
- LOG(INFO) << "Scattering is enabled";
- }
-
- if (is_scatter_enabled) {
- // This means the scattering policy is turned on.
- // Now check if we need to update the waiting period. The two cases
- // in which we'd need to update the waiting period are:
- // 1. First time in process or a scheduled check after a user-initiated one.
- // (omaha_request_params_->waiting_period will be zero in this case).
- // 2. Admin has changed the scattering policy value.
- // (new scattering value will be different from old one in this case).
- int64_t wait_period_in_secs = 0;
- if (omaha_request_params_->waiting_period().InSeconds() == 0) {
- // First case. Check if we have a suitable value to set for
- // the waiting period.
- if (prefs_->GetInt64(kPrefsWallClockScatteringWaitPeriod,
- &wait_period_in_secs) &&
- wait_period_in_secs > 0 &&
- wait_period_in_secs <= scatter_factor_.InSeconds()) {
- // This means:
- // 1. There's a persisted value for the waiting period available.
- // 2. And that persisted value is still valid.
- // So, in this case, we should reuse the persisted value instead of
- // generating a new random value to improve the chances of a good
- // distribution for scattering.
- omaha_request_params_->set_waiting_period(
- TimeDelta::FromSeconds(wait_period_in_secs));
- LOG(INFO) << "Using persisted wall-clock waiting period: "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
- } else {
- // This means there's no persisted value for the waiting period
- // available or its value is invalid given the new scatter_factor value.
- // So, we should go ahead and regenerate a new value for the
- // waiting period.
- LOG(INFO) << "Persisted value not present or not valid ("
- << utils::FormatSecs(wait_period_in_secs)
- << ") for wall-clock waiting period.";
- GenerateNewWaitingPeriod();
- }
- } else if (scatter_factor_ != old_scatter_factor) {
- // This means there's already a waiting period value, but we detected
- // a change in the scattering policy value. So, we should regenerate the
- // waiting period to make sure it's within the bounds of the new scatter
- // factor value.
- GenerateNewWaitingPeriod();
- } else {
- // Neither the first time scattering is enabled nor the scattering value
- // changed. Nothing to do.
- LOG(INFO) << "Keeping current wall-clock waiting period: "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
- }
-
- // The invariant at this point is that omaha_request_params_->waiting_period
- // is non-zero no matter which path we took above.
- LOG_IF(ERROR, omaha_request_params_->waiting_period().InSeconds() == 0)
- << "Waiting Period should NOT be zero at this point!!!";
-
- // Since scattering is enabled, wall clock based wait will always be
- // enabled.
- omaha_request_params_->set_wall_clock_based_wait_enabled(true);
-
- // If we don't have any issues in accessing the file system to update
- // the update check count value, we'll turn that on as well.
- bool decrement_succeeded = DecrementUpdateCheckCount();
- omaha_request_params_->set_update_check_count_wait_enabled(
- decrement_succeeded);
- } else {
- // This means the scattering feature is turned off or disabled for
- // this particular update check. Make sure to disable
- // all the knobs and artifacts so that we don't invoke any scattering
- // related code.
- omaha_request_params_->set_wall_clock_based_wait_enabled(false);
- omaha_request_params_->set_update_check_count_wait_enabled(false);
- omaha_request_params_->set_waiting_period(TimeDelta::FromSeconds(0));
- prefs_->Delete(kPrefsWallClockScatteringWaitPeriod);
- prefs_->Delete(kPrefsUpdateCheckCount);
- // Don't delete the UpdateFirstSeenAt file as we don't want manual checks
- // that result in no-updates (e.g. due to server side throttling) to
- // cause update starvation by having the client generate a new
- // UpdateFirstSeenAt for each scheduled check that follows a manual check.
- }
-}
-
-void UpdateAttempter::GenerateNewWaitingPeriod() {
- omaha_request_params_->set_waiting_period(
- TimeDelta::FromSeconds(base::RandInt(1, scatter_factor_.InSeconds())));
-
- LOG(INFO) << "Generated new wall-clock waiting period: "
- << utils::FormatSecs(
- omaha_request_params_->waiting_period().InSeconds());
-
- // Do a best-effort to persist this in all cases. Even if the persistence
- // fails, we'll still be able to scatter based on our in-memory value.
- // The persistence only helps in ensuring a good overall distribution
- // across multiple devices if they tend to reboot too often.
- SystemState::Get()->payload_state()->SetScatteringWaitPeriod(
- omaha_request_params_->waiting_period());
-}
-
-void UpdateAttempter::CalculateStagingParams(bool interactive) {
- bool oobe_complete = SystemState::Get()->hardware()->IsOOBEEnabled() &&
- SystemState::Get()->hardware()->IsOOBEComplete(nullptr);
- auto device_policy = SystemState::Get()->device_policy();
- StagingCase staging_case = StagingCase::kOff;
- if (device_policy && !interactive && oobe_complete) {
- staging_wait_time_ = omaha_request_params_->waiting_period();
- staging_case = CalculateStagingCase(
- device_policy, &staging_wait_time_, &staging_schedule_);
- }
- switch (staging_case) {
- case StagingCase::kOff:
- // Staging is off, get rid of persisted value.
- prefs_->Delete(kPrefsWallClockStagingWaitPeriod);
- // Set |staging_wait_time_| to its default value so scattering can still
- // be turned on
- staging_wait_time_ = TimeDelta();
- break;
- // Let the cases fall through since they just add, and never remove, steps
- // to turning staging on.
- case StagingCase::kNoSavedValue:
- prefs_->SetInt64(kPrefsWallClockStagingWaitPeriod,
- staging_wait_time_.InDays());
- FALLTHROUGH;
- case StagingCase::kSetStagingFromPref:
- omaha_request_params_->set_waiting_period(staging_wait_time_);
- FALLTHROUGH;
- case StagingCase::kNoAction:
- // Staging is on, enable wallclock based wait so that its values get used.
- omaha_request_params_->set_wall_clock_based_wait_enabled(true);
- // Use UpdateCheckCount if possible to prevent devices updating all at
- // once.
- omaha_request_params_->set_update_check_count_wait_enabled(
- DecrementUpdateCheckCount());
- // Scattering should not be turned on if staging is on, delete the
- // existing scattering configuration.
- prefs_->Delete(kPrefsWallClockScatteringWaitPeriod);
- scatter_factor_ = TimeDelta();
- }
-}
-
-bool UpdateAttempter::ResetDlcPrefs(const string& dlc_id) {
- vector<string> failures;
- for (auto& sub_key :
- {kPrefsPingActive, kPrefsPingLastActive, kPrefsPingLastRollcall}) {
- auto key = prefs_->CreateSubKey({kDlcPrefsSubDir, dlc_id, sub_key});
- if (!prefs_->Delete(key))
- failures.emplace_back(sub_key);
- }
- if (failures.size() != 0)
- PLOG(ERROR) << "Failed to delete prefs (" << base::JoinString(failures, ",")
- << " for DLC (" << dlc_id << ").";
-
- return failures.size() == 0;
-}
-
-void UpdateAttempter::SetPref(const string& pref_key,
- const string& pref_value,
- const string& payload_id) {
- string dlc_id;
- if (!omaha_request_params_->GetDlcId(payload_id, &dlc_id)) {
- // Not a DLC ID, set fingerprint in perf for platform ID.
- prefs_->SetString(pref_key, pref_value);
- } else {
- // Set fingerprint in pref for DLC ID.
- auto key = prefs_->CreateSubKey({kDlcPrefsSubDir, dlc_id, pref_key});
- prefs_->SetString(key, pref_value);
- }
-}
-
-bool UpdateAttempter::SetDlcActiveValue(bool is_active, const string& dlc_id) {
- if (dlc_id.empty()) {
- LOG(ERROR) << "Empty DLC ID passed.";
- return false;
- }
- LOG(INFO) << "Set DLC (" << dlc_id << ") to "
- << (is_active ? "Active" : "Inactive");
- if (is_active) {
- auto ping_active_key =
- prefs_->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
- if (!prefs_->SetInt64(ping_active_key, kPingActiveValue)) {
- LOG(ERROR) << "Failed to set the value of ping metadata '"
- << kPrefsPingActive << "'.";
- return false;
- }
- } else {
- return ResetDlcPrefs(dlc_id);
- }
- return true;
-}
-
-int64_t UpdateAttempter::GetPingMetadata(const string& metadata_key) const {
- // The first time a ping is sent, the metadata files containing the values
- // sent back by the server still don't exist. A value of -1 is used to
- // indicate this.
- if (!SystemState::Get()->prefs()->Exists(metadata_key))
- return kPingNeverPinged;
-
- int64_t value;
- if (SystemState::Get()->prefs()->GetInt64(metadata_key, &value))
- return value;
-
- // Return -2 when the file exists and there is a problem reading from it, or
- // the value cannot be converted to an integer.
- return kPingUnknownValue;
-}
-
-void UpdateAttempter::CalculateDlcParams() {
- // Set the |dlc_ids_| only for an update. This is required to get the
- // currently installed DLC(s).
- if (!is_install_ &&
- !SystemState::Get()->dlcservice()->GetDlcsToUpdate(&dlc_ids_)) {
- LOG(INFO) << "Failed to retrieve DLC module IDs from dlcservice. Check the "
- "state of dlcservice, will not update DLC modules.";
- }
- map<string, OmahaRequestParams::AppParams> dlc_apps_params;
- for (const auto& dlc_id : dlc_ids_) {
- OmahaRequestParams::AppParams dlc_params{
- .active_counting_type = OmahaRequestParams::kDateBased,
- .name = dlc_id,
- .send_ping = false};
- if (is_install_) {
- // In some cases, |SetDlcActiveValue| might fail to reset the DLC prefs
- // when a DLC is uninstalled. To avoid having stale values from that
- // scenario, we reset the metadata values on a new install request.
- // Ignore failure to delete stale prefs.
- ResetDlcPrefs(dlc_id);
- SetDlcActiveValue(true, dlc_id);
- } else {
- // Only send the ping when the request is to update DLCs. When installing
- // DLCs, we don't want to send the ping yet, since the DLCs might fail to
- // install or might not really be active yet.
- dlc_params.ping_active = kPingActiveValue;
- auto ping_active_key =
- prefs_->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
- if (!prefs_->GetInt64(ping_active_key, &dlc_params.ping_active) ||
- dlc_params.ping_active != kPingActiveValue) {
- dlc_params.ping_active = kPingInactiveValue;
- }
- auto ping_last_active_key =
- prefs_->CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingLastActive});
- dlc_params.ping_date_last_active = GetPingMetadata(ping_last_active_key);
-
- auto ping_last_rollcall_key = prefs_->CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastRollcall});
- dlc_params.ping_date_last_rollcall =
- GetPingMetadata(ping_last_rollcall_key);
-
- dlc_params.send_ping = true;
- }
- dlc_apps_params[omaha_request_params_->GetDlcAppId(dlc_id)] = dlc_params;
- }
- omaha_request_params_->set_dlc_apps_params(dlc_apps_params);
- omaha_request_params_->set_is_install(is_install_);
-}
-
-void UpdateAttempter::BuildUpdateActions(bool interactive) {
- CHECK(!processor_->IsRunning());
- processor_->set_delegate(this);
-
- // The session ID needs to be kept throughout the update flow. The value
- // of the session ID will reset/update only when it is a new update flow.
- session_id_ = base::GenerateGUID();
-
- // Actions:
- auto update_check_fetcher = std::make_unique<LibcurlHttpFetcher>(
- GetProxyResolver(), SystemState::Get()->hardware());
- update_check_fetcher->set_server_to_check(ServerToCheck::kUpdate);
- // Try harder to connect to the network, esp when not interactive.
- // See comment in libcurl_http_fetcher.cc.
- update_check_fetcher->set_no_network_max_retries(interactive ? 1 : 3);
- update_check_fetcher->set_is_update_check(true);
- auto update_check_action = std::make_unique<OmahaRequestAction>(
- nullptr, std::move(update_check_fetcher), false, session_id_);
- auto response_handler_action = std::make_unique<OmahaResponseHandlerAction>();
- auto update_boot_flags_action = std::make_unique<UpdateBootFlagsAction>(
- SystemState::Get()->boot_control());
- auto download_started_action = std::make_unique<OmahaRequestAction>(
- new OmahaEvent(OmahaEvent::kTypeUpdateDownloadStarted),
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- SystemState::Get()->hardware()),
- false,
- session_id_);
-
- LibcurlHttpFetcher* download_fetcher = new LibcurlHttpFetcher(
- GetProxyResolver(), SystemState::Get()->hardware());
- download_fetcher->set_server_to_check(ServerToCheck::kDownload);
- if (interactive)
- download_fetcher->set_max_retry_count(kDownloadMaxRetryCountInteractive);
- download_fetcher->SetHeader(kXGoogleUpdateSessionId, session_id_);
- auto download_action = std::make_unique<DownloadActionChromeos>(
- prefs_,
- SystemState::Get()->boot_control(),
- SystemState::Get()->hardware(),
- download_fetcher, // passes ownership
- interactive);
- download_action->set_delegate(this);
-
- auto download_finished_action = std::make_unique<OmahaRequestAction>(
- new OmahaEvent(OmahaEvent::kTypeUpdateDownloadFinished),
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- SystemState::Get()->hardware()),
- false,
- session_id_);
- auto filesystem_verifier_action = std::make_unique<FilesystemVerifierAction>(
- SystemState::Get()->boot_control()->GetDynamicPartitionControl());
- auto update_complete_action = std::make_unique<OmahaRequestAction>(
- new OmahaEvent(OmahaEvent::kTypeUpdateComplete),
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- SystemState::Get()->hardware()),
- false,
- session_id_);
-
- auto postinstall_runner_action = std::make_unique<PostinstallRunnerAction>(
- SystemState::Get()->boot_control(), SystemState::Get()->hardware());
- postinstall_runner_action->set_delegate(this);
-
- // Bond them together. We have to use the leaf-types when calling
- // BondActions().
- BondActions(update_check_action.get(), response_handler_action.get());
- BondActions(response_handler_action.get(), download_action.get());
- BondActions(download_action.get(), filesystem_verifier_action.get());
- BondActions(filesystem_verifier_action.get(),
- postinstall_runner_action.get());
-
- processor_->EnqueueAction(std::move(update_check_action));
- processor_->EnqueueAction(std::move(response_handler_action));
- processor_->EnqueueAction(std::move(update_boot_flags_action));
- processor_->EnqueueAction(std::move(download_started_action));
- processor_->EnqueueAction(std::move(download_action));
- processor_->EnqueueAction(std::move(download_finished_action));
- processor_->EnqueueAction(std::move(filesystem_verifier_action));
- processor_->EnqueueAction(std::move(postinstall_runner_action));
- processor_->EnqueueAction(std::move(update_complete_action));
-}
-
-bool UpdateAttempter::Rollback(bool powerwash) {
- is_install_ = false;
- if (!CanRollback()) {
- return false;
- }
-
- // Extra check for enterprise-enrolled devices since they don't support
- // powerwash.
- if (powerwash) {
- // Enterprise-enrolled devices have an empty owner in their device policy.
- string owner;
- RefreshDevicePolicy();
- const policy::DevicePolicy* device_policy =
- SystemState::Get()->device_policy();
- if (device_policy && (!device_policy->GetOwner(&owner) || owner.empty())) {
- LOG(ERROR) << "Enterprise device detected. "
- << "Cannot perform a powerwash for enterprise devices.";
- return false;
- }
- }
-
- processor_->set_delegate(this);
-
- // Initialize the default request params.
- if (!omaha_request_params_->Init("", "", {.interactive = true})) {
- LOG(ERROR) << "Unable to initialize Omaha request params.";
- return false;
- }
-
- LOG(INFO) << "Setting rollback options.";
- install_plan_.reset(new InstallPlan());
- install_plan_->target_slot = GetRollbackSlot();
- install_plan_->source_slot =
- SystemState::Get()->boot_control()->GetCurrentSlot();
-
- TEST_AND_RETURN_FALSE(install_plan_->LoadPartitionsFromSlots(
- SystemState::Get()->boot_control()));
- install_plan_->powerwash_required = powerwash;
-
- install_plan_->Dump();
-
- auto install_plan_action =
- std::make_unique<InstallPlanAction>(*install_plan_);
- auto postinstall_runner_action = std::make_unique<PostinstallRunnerAction>(
- SystemState::Get()->boot_control(), SystemState::Get()->hardware());
- postinstall_runner_action->set_delegate(this);
- BondActions(install_plan_action.get(), postinstall_runner_action.get());
- processor_->EnqueueAction(std::move(install_plan_action));
- processor_->EnqueueAction(std::move(postinstall_runner_action));
-
- // Update the payload state for Rollback.
- SystemState::Get()->payload_state()->Rollback();
-
- SetStatusAndNotify(UpdateStatus::ATTEMPTING_ROLLBACK);
-
- ScheduleProcessingStart();
- return true;
-}
-
-bool UpdateAttempter::CanRollback() const {
- // We can only rollback if the update_engine isn't busy and we have a valid
- // rollback partition.
- return (status_ == UpdateStatus::IDLE &&
- GetRollbackSlot() != BootControlInterface::kInvalidSlot);
-}
-
-BootControlInterface::Slot UpdateAttempter::GetRollbackSlot() const {
- LOG(INFO) << "UpdateAttempter::GetRollbackSlot";
- const unsigned int num_slots =
- SystemState::Get()->boot_control()->GetNumSlots();
- const BootControlInterface::Slot current_slot =
- SystemState::Get()->boot_control()->GetCurrentSlot();
-
- LOG(INFO) << " Installed slots: " << num_slots;
- LOG(INFO) << " Booted from slot: "
- << BootControlInterface::SlotName(current_slot);
-
- if (current_slot == BootControlInterface::kInvalidSlot || num_slots < 2) {
- LOG(INFO) << "Device is not updateable.";
- return BootControlInterface::kInvalidSlot;
- }
-
- vector<BootControlInterface::Slot> bootable_slots;
- for (BootControlInterface::Slot slot = 0; slot < num_slots; slot++) {
- if (slot != current_slot &&
- SystemState::Get()->boot_control()->IsSlotBootable(slot)) {
- LOG(INFO) << "Found bootable slot "
- << BootControlInterface::SlotName(slot);
- return slot;
- }
- }
- LOG(INFO) << "No other bootable slot found.";
- return BootControlInterface::kInvalidSlot;
-}
-
-bool UpdateAttempter::CheckForUpdate(const string& app_version,
- const string& omaha_url,
- UpdateAttemptFlags flags) {
- if (status_ != UpdateStatus::IDLE) {
- LOG(INFO) << "Refusing to do an update as there is an "
- << (is_install_ ? "install" : "update")
- << " already in progress.";
- return false;
- }
-
- bool interactive = !(flags & UpdateAttemptFlags::kFlagNonInteractive);
- is_install_ = false;
-
- LOG(INFO) << "Forced update check requested.";
- forced_app_version_.clear();
- forced_omaha_url_.clear();
-
- // Certain conditions must be met to allow setting custom version and update
- // server URLs. However, kScheduledAUTestURLRequest and kAUTestURLRequest are
- // always allowed regardless of device state.
- if (IsAnyUpdateSourceAllowed()) {
- forced_app_version_ = app_version;
- forced_omaha_url_ = omaha_url;
- }
- if (omaha_url == kScheduledAUTestURLRequest) {
- forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
- // Pretend that it's not user-initiated even though it is,
- // so as to test scattering logic, etc. which get kicked off
- // only in scheduled update checks.
- interactive = false;
- } else if (omaha_url == kAUTestURLRequest) {
- forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
- }
-
- if (interactive) {
- // Use the passed-in update attempt flags for this update attempt instead
- // of the previously set ones.
- current_update_attempt_flags_ = flags;
- // Note: The caching for non-interactive update checks happens in
- // |OnUpdateScheduled()|.
- }
-
- // |forced_update_pending_callback_| should always be set, but even in the
- // case that it is not, we still return true indicating success because the
- // scheduled periodic check will pick up these changes.
- if (forced_update_pending_callback_.get()) {
- // Always call |ScheduleUpdates()| before forcing an update. This is because
- // we need an update to be scheduled for the
- // |forced_update_pending_callback_| to have an effect. Here we don't need
- // to care about the return value from |ScheduleUpdate()|.
- ScheduleUpdates();
- forced_update_pending_callback_->Run(true, interactive);
- }
- return true;
-}
-
-bool UpdateAttempter::CheckForInstall(const vector<string>& dlc_ids,
- const string& omaha_url) {
- if (status_ != UpdateStatus::IDLE) {
- LOG(INFO) << "Refusing to do an install as there is an "
- << (is_install_ ? "install" : "update")
- << " already in progress.";
- return false;
- }
-
- dlc_ids_ = dlc_ids;
- is_install_ = true;
- forced_omaha_url_.clear();
-
- // Certain conditions must be met to allow setting custom version and update
- // server URLs. However, kScheduledAUTestURLRequest and kAUTestURLRequest are
- // always allowed regardless of device state.
- if (IsAnyUpdateSourceAllowed()) {
- forced_omaha_url_ = omaha_url;
- }
-
- if (omaha_url == kScheduledAUTestURLRequest ||
- omaha_url == kAUTestURLRequest) {
- forced_omaha_url_ = constants::kOmahaDefaultAUTestURL;
- }
-
- // |forced_update_pending_callback_| should always be set, but even in the
- // case that it is not, we still return true indicating success because the
- // scheduled periodic check will pick up these changes.
- if (forced_update_pending_callback_.get()) {
- // Always call |ScheduleUpdates()| before forcing an update. This is because
- // we need an update to be scheduled for the
- // |forced_update_pending_callback_| to have an effect. Here we don't need
- // to care about the return value from |ScheduleUpdate()|.
- ScheduleUpdates();
- forced_update_pending_callback_->Run(true, true);
- }
- return true;
-}
-
-bool UpdateAttempter::RebootIfNeeded() {
- if (SystemState::Get()->power_manager()->RequestReboot())
- return true;
-
- return RebootDirectly();
-}
-
-void UpdateAttempter::WriteUpdateCompletedMarker() {
- string boot_id;
- if (!utils::GetBootId(&boot_id))
- return;
- prefs_->SetString(kPrefsUpdateCompletedOnBootId, boot_id);
-
- int64_t value = SystemState::Get()->clock()->GetBootTime().ToInternalValue();
- prefs_->SetInt64(kPrefsUpdateCompletedBootTime, value);
-}
-
-bool UpdateAttempter::RebootDirectly() {
- vector<string> command = {"/sbin/shutdown", "-r", "now"};
- int rc = 0;
- Subprocess::SynchronousExec(command, &rc, nullptr, nullptr);
- return rc == 0;
-}
-
-void UpdateAttempter::OnUpdateScheduled(EvalStatus status,
- const UpdateCheckParams& params) {
- waiting_for_scheduled_check_ = false;
-
- if (status == EvalStatus::kSucceeded) {
- if (!params.updates_enabled) {
- LOG(WARNING) << "Updates permanently disabled.";
- // Signal disabled status, then switch right back to idle. This is
- // necessary for ensuring that observers waiting for a signal change will
- // actually notice one on subsequent calls. Note that we don't need to
- // re-schedule a check in this case as updates are permanently disabled;
- // further (forced) checks may still initiate a scheduling call.
- SetStatusAndNotify(UpdateStatus::DISABLED);
- SetStatusAndNotify(UpdateStatus::IDLE);
- return;
- }
-
- LOG(INFO) << "Running " << (params.interactive ? "interactive" : "periodic")
- << " update.";
-
- if (!params.interactive) {
- // Cache the update attempt flags that will be used by this update attempt
- // so that they can't be changed mid-way through.
- current_update_attempt_flags_ = update_attempt_flags_;
- }
-
- LOG(INFO) << "Update attempt flags in use = 0x" << std::hex
- << current_update_attempt_flags_;
-
- Update(params);
- // Always clear the forced app_version and omaha_url after an update attempt
- // so the next update uses the defaults.
- forced_app_version_.clear();
- forced_omaha_url_.clear();
- } else {
- LOG(WARNING)
- << "Update check scheduling failed (possibly timed out); retrying.";
- ScheduleUpdates();
- }
-
- // This check ensures that future update checks will be or are already
- // scheduled. The check should never fail. A check failure means that there's
- // a bug that will most likely prevent further automatic update checks. It
- // seems better to crash in such cases and restart the update_engine daemon
- // into, hopefully, a known good state.
- CHECK(IsBusyOrUpdateScheduled());
-}
-
-void UpdateAttempter::UpdateLastCheckedTime() {
- last_checked_time_ =
- SystemState::Get()->clock()->GetWallclockTime().ToTimeT();
-}
-
-void UpdateAttempter::UpdateRollbackHappened() {
- DCHECK(SystemState::Get()->payload_state());
- DCHECK(policy_provider_);
- if (SystemState::Get()->payload_state()->GetRollbackHappened() &&
- (policy_provider_->device_policy_is_loaded() ||
- policy_provider_->IsConsumerDevice())) {
- // Rollback happened, but we already went through OOBE and policy is
- // present or it's a consumer device.
- SystemState::Get()->payload_state()->SetRollbackHappened(false);
- }
-}
-
-void UpdateAttempter::ProcessingDoneInternal(const ActionProcessor* processor,
- ErrorCode code) {
- // Reset cpu shares back to normal.
- cpu_limiter_.StopLimiter();
-
- ResetInteractivityFlags();
-
- if (status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
- LOG(INFO) << "Error event sent.";
-
- // Inform scheduler of new status.
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
-
- if (!fake_update_success_) {
- return;
- }
- LOG(INFO) << "Booted from FW B and tried to install new firmware, "
- "so requesting reboot from user.";
- }
-
- attempt_error_code_ = utils::GetBaseErrorCode(code);
-
- if (code != ErrorCode::kSuccess) {
- if (ScheduleErrorEventAction()) {
- return;
- }
- LOG(INFO) << "No update.";
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
- return;
- }
-
- ReportTimeToUpdateAppliedMetric();
- prefs_->SetInt64(kPrefsDeltaUpdateFailures, 0);
- prefs_->SetString(kPrefsPreviousVersion,
- omaha_request_params_->app_version());
- DeltaPerformer::ResetUpdateProgress(prefs_, false);
-
- SystemState::Get()->payload_state()->UpdateSucceeded();
-
- // Since we're done with scattering fully at this point, this is the
- // safest point delete the state files, as we're sure that the status is
- // set to reboot (which means no more updates will be applied until reboot)
- // This deletion is required for correctness as we want the next update
- // check to re-create a new random number for the update check count.
- // Similarly, we also delete the wall-clock-wait period that was persisted
- // so that we start with a new random value for the next update check
- // after reboot so that the same device is not favored or punished in any
- // way.
- prefs_->Delete(kPrefsUpdateCheckCount);
- SystemState::Get()->payload_state()->SetScatteringWaitPeriod(TimeDelta());
- SystemState::Get()->payload_state()->SetStagingWaitPeriod(TimeDelta());
- prefs_->Delete(kPrefsUpdateFirstSeenAt);
-
- // Note: below this comment should only be on |ErrorCode::kSuccess|.
- if (is_install_) {
- ProcessingDoneInstall(processor, code);
- } else {
- ProcessingDoneUpdate(processor, code);
- }
-}
-
-vector<string> UpdateAttempter::GetSuccessfulDlcIds() {
- vector<string> dlc_ids;
- for (const auto& pr : omaha_request_params_->dlc_apps_params())
- if (pr.second.updated)
- dlc_ids.push_back(pr.second.name);
- return dlc_ids;
-}
-
-void UpdateAttempter::ProcessingDoneInstall(const ActionProcessor* processor,
- ErrorCode code) {
- if (!SystemState::Get()->dlcservice()->InstallCompleted(
- GetSuccessfulDlcIds()))
- LOG(WARNING) << "dlcservice didn't successfully handle install completion.";
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
- LOG(INFO) << "DLC successfully installed, no reboot needed.";
-}
-
-void UpdateAttempter::ProcessingDoneUpdate(const ActionProcessor* processor,
- ErrorCode code) {
- WriteUpdateCompletedMarker();
-
- if (!SystemState::Get()->dlcservice()->UpdateCompleted(GetSuccessfulDlcIds()))
- LOG(WARNING) << "dlcservice didn't successfully handle update completion.";
- SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
- ScheduleUpdates();
- LOG(INFO) << "Update successfully applied, waiting to reboot.";
-
- // |install_plan_| is null during rollback operations, and the stats don't
- // make much sense then anyway.
- if (install_plan_) {
- // Generate an unique payload identifier.
- string target_version_uid;
- for (const auto& payload : install_plan_->payloads) {
- target_version_uid += brillo::data_encoding::Base64Encode(payload.hash) +
- ":" + payload.metadata_signature + ":";
- // Set fingerprint value for updates only.
- if (!is_install_)
- SetPref(kPrefsLastFp, payload.fp, payload.app_id);
- }
-
- // If we just downloaded a rollback image, we should preserve this fact
- // over the following powerwash.
- if (install_plan_->is_rollback) {
- SystemState::Get()->payload_state()->SetRollbackHappened(true);
- SystemState::Get()->metrics_reporter()->ReportEnterpriseRollbackMetrics(
- /*success=*/true, install_plan_->version);
- }
-
- // Expect to reboot into the new version to send the proper metric during
- // next boot.
- SystemState::Get()->payload_state()->ExpectRebootInNewVersion(
- target_version_uid);
- } else {
- // If we just finished a rollback, then we expect to have no Omaha
- // response. Otherwise, it's an error.
- if (SystemState::Get()->payload_state()->GetRollbackVersion().empty()) {
- LOG(ERROR) << "Can't send metrics because there was no Omaha response";
- }
- }
-}
-
-// Delegate methods:
-void UpdateAttempter::ProcessingDone(const ActionProcessor* processor,
- ErrorCode code) {
- LOG(INFO) << "Processing Done.";
- ProcessingDoneInternal(processor, code);
-
- // Note: do cleanups here for any variables that need to be reset after a
- // failure, error, update, or install.
- is_install_ = false;
-}
-
-void UpdateAttempter::ProcessingStopped(const ActionProcessor* processor) {
- // Reset cpu shares back to normal.
- cpu_limiter_.StopLimiter();
- download_progress_ = 0.0;
-
- ResetInteractivityFlags();
-
- SetStatusAndNotify(UpdateStatus::IDLE);
- ScheduleUpdates();
- error_event_.reset(nullptr);
-}
-
-// Called whenever an action has finished processing, either successfully
-// or otherwise.
-void UpdateAttempter::ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) {
- // Reset download progress regardless of whether or not the download
- // action succeeded. Also, get the response code from HTTP request
- // actions (update download as well as the initial update check
- // actions).
- const string type = action->Type();
- if (type == DownloadActionChromeos::StaticType()) {
- download_progress_ = 0.0;
- DownloadActionChromeos* download_action =
- static_cast<DownloadActionChromeos*>(action);
- http_response_code_ = download_action->GetHTTPResponseCode();
- } else if (type == OmahaRequestAction::StaticType()) {
- OmahaRequestAction* omaha_request_action =
- static_cast<OmahaRequestAction*>(action);
- // If the request is not an event, then it's the update-check.
- if (!omaha_request_action->IsEvent()) {
- http_response_code_ = omaha_request_action->GetHTTPResponseCode();
-
- // Record the number of consecutive failed update checks.
- if (http_response_code_ == kHttpResponseInternalServerError ||
- http_response_code_ == kHttpResponseServiceUnavailable) {
- consecutive_failed_update_checks_++;
- } else {
- consecutive_failed_update_checks_ = 0;
- }
-
- const OmahaResponse& omaha_response =
- omaha_request_action->GetOutputObject();
- // Store the server-dictated poll interval, if any.
- server_dictated_poll_interval_ =
- std::max(0, omaha_response.poll_interval);
-
- // This update is ignored by omaha request action because update over
- // cellular connection is not allowed. Needs to ask for user's permissions
- // to update.
- if (code == ErrorCode::kOmahaUpdateIgnoredOverCellular) {
- new_version_ = omaha_response.version;
- new_payload_size_ = 0;
- for (const auto& package : omaha_response.packages) {
- new_payload_size_ += package.size;
- }
- SetStatusAndNotify(UpdateStatus::NEED_PERMISSION_TO_UPDATE);
- }
- }
- } else if (type == OmahaResponseHandlerAction::StaticType()) {
- // Depending on the returned error code, note that an update is available.
- if (code == ErrorCode::kOmahaUpdateDeferredPerPolicy ||
- code == ErrorCode::kSuccess) {
- // Note that the status will be updated to DOWNLOADING when some bytes
- // get actually downloaded from the server and the BytesReceived
- // callback is invoked. This avoids notifying the user that a download
- // has started in cases when the server and the client are unable to
- // initiate the download.
- auto omaha_response_handler_action =
- static_cast<OmahaResponseHandlerAction*>(action);
- install_plan_.reset(
- new InstallPlan(omaha_response_handler_action->install_plan()));
- UpdateLastCheckedTime();
- new_version_ = install_plan_->version;
- new_payload_size_ = 0;
- for (const auto& payload : install_plan_->payloads)
- new_payload_size_ += payload.size;
- cpu_limiter_.StartLimiter();
- SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE);
- }
- }
- // General failure cases.
- if (code != ErrorCode::kSuccess) {
- // If the current state is at or past the download phase, count the failure
- // in case a switch to full update becomes necessary. Ignore network
- // transfer timeouts and failures.
- if (code != ErrorCode::kDownloadTransferError) {
- switch (status_) {
- case UpdateStatus::IDLE:
- case UpdateStatus::CHECKING_FOR_UPDATE:
- case UpdateStatus::UPDATE_AVAILABLE:
- case UpdateStatus::NEED_PERMISSION_TO_UPDATE:
- break;
- case UpdateStatus::DOWNLOADING:
- case UpdateStatus::VERIFYING:
- case UpdateStatus::FINALIZING:
- case UpdateStatus::UPDATED_NEED_REBOOT:
- case UpdateStatus::REPORTING_ERROR_EVENT:
- case UpdateStatus::ATTEMPTING_ROLLBACK:
- case UpdateStatus::DISABLED:
- case UpdateStatus::CLEANUP_PREVIOUS_UPDATE:
- MarkDeltaUpdateFailure();
- break;
- }
- }
- if (code != ErrorCode::kNoUpdate) {
- // On failure, schedule an error event to be sent to Omaha.
- CreatePendingErrorEvent(action, code);
- }
- return;
- }
- // Find out which action completed (successfully).
- if (type == DownloadAction::StaticType()) {
- SetStatusAndNotify(UpdateStatus::FINALIZING);
- } else if (type == FilesystemVerifierAction::StaticType()) {
- // Log the system properties before the postinst and after the file system
- // is verified. It used to be done in the postinst itself. But postinst
- // cannot do this anymore. On the other hand, these logs are frequently
- // looked at and it is preferable not to scatter them in random location in
- // the log and rather log it right before the postinst. The reason not do
- // this in the |PostinstallRunnerAction| is to prevent dependency from
- // libpayload_consumer to libupdate_engine.
- LogImageProperties();
- }
-}
-
-void UpdateAttempter::BytesReceived(uint64_t bytes_progressed,
- uint64_t bytes_received,
- uint64_t total) {
- // The PayloadState keeps track of how many bytes were actually downloaded
- // from a given URL for the URL skipping logic.
- SystemState::Get()->payload_state()->DownloadProgress(bytes_progressed);
-
- double progress = 0;
- if (total)
- progress = static_cast<double>(bytes_received) / static_cast<double>(total);
- if (status_ != UpdateStatus::DOWNLOADING || bytes_received == total) {
- download_progress_ = progress;
- SetStatusAndNotify(UpdateStatus::DOWNLOADING);
- } else {
- ProgressUpdate(progress);
- }
-}
-
-void UpdateAttempter::DownloadComplete() {
- SystemState::Get()->payload_state()->DownloadComplete();
-}
-
-void UpdateAttempter::ProgressUpdate(double progress) {
- // Self throttle based on progress. Also send notifications if progress is
- // too slow.
- if (progress == 1.0 ||
- progress - download_progress_ >= kBroadcastThresholdProgress ||
- TimeTicks::Now() - last_notify_time_ >=
- TimeDelta::FromSeconds(kBroadcastThresholdSeconds)) {
- download_progress_ = progress;
- BroadcastStatus();
- }
-}
-
-void UpdateAttempter::ResetInteractivityFlags() {
- // Reset the state that's only valid for a single update pass.
- current_update_attempt_flags_ = UpdateAttemptFlags::kNone;
-
- if (forced_update_pending_callback_.get())
- // Clear prior interactive requests once the processor is done.
- forced_update_pending_callback_->Run(false, false);
-}
-
-bool UpdateAttempter::ResetStatus() {
- LOG(INFO) << "Attempting to reset state from "
- << UpdateStatusToString(status_) << " to UpdateStatus::IDLE";
-
- switch (status_) {
- case UpdateStatus::IDLE:
- // no-op.
- return true;
-
- case UpdateStatus::UPDATED_NEED_REBOOT: {
- bool ret_value = true;
- status_ = UpdateStatus::IDLE;
-
- // Remove the reboot marker so that if the machine is rebooted
- // after resetting to idle state, it doesn't go back to
- // UpdateStatus::UPDATED_NEED_REBOOT state.
- ret_value = prefs_->Delete(kPrefsUpdateCompletedOnBootId) && ret_value;
- ret_value = prefs_->Delete(kPrefsUpdateCompletedBootTime) && ret_value;
- ret_value = prefs_->Delete(kPrefsLastFp, {kDlcPrefsSubDir}) && ret_value;
-
- // Update the boot flags so the current slot has higher priority.
- BootControlInterface* boot_control = SystemState::Get()->boot_control();
- if (!boot_control->SetActiveBootSlot(boot_control->GetCurrentSlot()))
- ret_value = false;
-
- // Mark the current slot as successful again, since marking it as active
- // may reset the successful bit. We ignore the result of whether marking
- // the current slot as successful worked.
- if (!boot_control->MarkBootSuccessfulAsync(Bind([](bool successful) {})))
- ret_value = false;
-
- // Notify the PayloadState that the successful payload was canceled.
- SystemState::Get()->payload_state()->ResetUpdateStatus();
-
- // The previous version is used to report back to omaha after reboot that
- // we actually rebooted into the new version from this "prev-version". We
- // need to clear out this value now to prevent it being sent on the next
- // updatecheck request.
- ret_value = prefs_->SetString(kPrefsPreviousVersion, "") && ret_value;
-
- LOG(INFO) << "Reset status " << (ret_value ? "successful" : "failed");
- return ret_value;
- }
-
- default:
- LOG(ERROR) << "Reset not allowed in this state.";
- return false;
- }
-}
-
-bool UpdateAttempter::GetStatus(UpdateEngineStatus* out_status) {
- out_status->last_checked_time = last_checked_time_;
- out_status->status = status_;
- out_status->current_version = omaha_request_params_->app_version();
- out_status->progress = download_progress_;
- out_status->new_size_bytes = new_payload_size_;
- out_status->new_version = new_version_;
- out_status->is_enterprise_rollback =
- install_plan_ && install_plan_->is_rollback;
- out_status->is_install = is_install_;
-
- string str_eol_date;
- if (SystemState::Get()->prefs()->Exists(kPrefsOmahaEolDate) &&
- !SystemState::Get()->prefs()->GetString(kPrefsOmahaEolDate,
- &str_eol_date))
- LOG(ERROR) << "Failed to retrieve kPrefsOmahaEolDate pref.";
- out_status->eol_date = StringToEolDate(str_eol_date);
-
- // A powerwash will take place either if the install plan says it is required
- // or if an enterprise rollback is happening.
- out_status->will_powerwash_after_reboot =
- install_plan_ &&
- (install_plan_->powerwash_required || install_plan_->is_rollback);
-
- return true;
-}
-
-void UpdateAttempter::BroadcastStatus() {
- UpdateEngineStatus broadcast_status;
- // Use common method for generating the current status.
- GetStatus(&broadcast_status);
-
- for (const auto& observer : service_observers_) {
- observer->SendStatusUpdate(broadcast_status);
- }
- last_notify_time_ = TimeTicks::Now();
-}
-
-uint32_t UpdateAttempter::GetErrorCodeFlags() {
- uint32_t flags = 0;
-
- if (!SystemState::Get()->hardware()->IsNormalBootMode())
- flags |= static_cast<uint32_t>(ErrorCode::kDevModeFlag);
-
- if (install_plan_ && install_plan_->is_resume)
- flags |= static_cast<uint32_t>(ErrorCode::kResumedFlag);
-
- if (!SystemState::Get()->hardware()->IsOfficialBuild())
- flags |= static_cast<uint32_t>(ErrorCode::kTestImageFlag);
-
- if (!omaha_request_params_->IsUpdateUrlOfficial()) {
- flags |= static_cast<uint32_t>(ErrorCode::kTestOmahaUrlFlag);
- }
-
- return flags;
-}
-
-bool UpdateAttempter::ShouldCancel(ErrorCode* cancel_reason) {
- // Check if the channel we're attempting to update to is the same as the
- // target channel currently chosen by the user.
- OmahaRequestParams* params = SystemState::Get()->request_params();
- if (params->download_channel() != params->target_channel()) {
- LOG(ERROR) << "Aborting download as target channel: "
- << params->target_channel()
- << " is different from the download channel: "
- << params->download_channel();
- *cancel_reason = ErrorCode::kUpdateCanceledByChannelChange;
- return true;
- }
-
- return false;
-}
-
-void UpdateAttempter::SetStatusAndNotify(UpdateStatus status) {
- status_ = status;
- BroadcastStatus();
-}
-
-void UpdateAttempter::CreatePendingErrorEvent(AbstractAction* action,
- ErrorCode code) {
- if (error_event_.get() || status_ == UpdateStatus::REPORTING_ERROR_EVENT) {
- // This shouldn't really happen.
- LOG(WARNING) << "There's already an existing pending error event.";
- return;
- }
-
- // Classify the code to generate the appropriate result so that
- // the Borgmon charts show up the results correctly.
- // Do this before calling GetErrorCodeForAction which could potentially
- // augment the bit representation of code and thus cause no matches for
- // the switch cases below.
- OmahaEvent::Result event_result;
- switch (code) {
- case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
- case ErrorCode::kOmahaUpdateDeferredPerPolicy:
- case ErrorCode::kOmahaUpdateDeferredForBackoff:
- event_result = OmahaEvent::kResultUpdateDeferred;
- break;
- default:
- event_result = OmahaEvent::kResultError;
- break;
- }
-
- code = GetErrorCodeForAction(action, code);
- fake_update_success_ = code == ErrorCode::kPostinstallBootedFromFirmwareB;
-
- // Compute the final error code with all the bit flags to be sent to Omaha.
- code =
- static_cast<ErrorCode>(static_cast<uint32_t>(code) | GetErrorCodeFlags());
- error_event_.reset(
- new OmahaEvent(OmahaEvent::kTypeUpdateComplete, event_result, code));
-}
-
-bool UpdateAttempter::ScheduleErrorEventAction() {
- if (error_event_.get() == nullptr)
- return false;
-
- LOG(ERROR) << "Update failed.";
- SystemState::Get()->payload_state()->UpdateFailed(error_event_->error_code);
-
- // Send metrics if it was a rollback.
- if (install_plan_ && install_plan_->is_rollback) {
- SystemState::Get()->metrics_reporter()->ReportEnterpriseRollbackMetrics(
- /*success=*/false, install_plan_->version);
- }
-
- // Send it to Omaha.
- LOG(INFO) << "Reporting the error event";
- auto error_event_action = std::make_unique<OmahaRequestAction>(
- error_event_.release(), // Pass ownership.
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- SystemState::Get()->hardware()),
- false,
- session_id_);
- processor_->EnqueueAction(std::move(error_event_action));
- SetStatusAndNotify(UpdateStatus::REPORTING_ERROR_EVENT);
- processor_->StartProcessing();
- return true;
-}
-
-void UpdateAttempter::ScheduleProcessingStart() {
- LOG(INFO) << "Scheduling an action processor start.";
- MessageLoop::current()->PostTask(
- FROM_HERE,
- Bind([](ActionProcessor* processor) { processor->StartProcessing(); },
- base::Unretained(processor_.get())));
-}
-
-void UpdateAttempter::DisableDeltaUpdateIfNeeded() {
- int64_t delta_failures;
- if (omaha_request_params_->delta_okay() &&
- prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) &&
- delta_failures >= kMaxDeltaUpdateFailures) {
- LOG(WARNING) << "Too many delta update failures, forcing full update.";
- omaha_request_params_->set_delta_okay(false);
- }
-}
-
-void UpdateAttempter::MarkDeltaUpdateFailure() {
- // Don't try to resume a failed delta update.
- DeltaPerformer::ResetUpdateProgress(prefs_, false);
- int64_t delta_failures;
- if (!prefs_->GetInt64(kPrefsDeltaUpdateFailures, &delta_failures) ||
- delta_failures < 0) {
- delta_failures = 0;
- }
- prefs_->SetInt64(kPrefsDeltaUpdateFailures, ++delta_failures);
-}
-
-void UpdateAttempter::PingOmaha() {
- if (!processor_->IsRunning()) {
- ResetInteractivityFlags();
-
- auto ping_action = std::make_unique<OmahaRequestAction>(
- nullptr,
- std::make_unique<LibcurlHttpFetcher>(GetProxyResolver(),
- SystemState::Get()->hardware()),
- true,
- "" /* session_id */);
- processor_->set_delegate(nullptr);
- processor_->EnqueueAction(std::move(ping_action));
- // Call StartProcessing() synchronously here to avoid any race conditions
- // caused by multiple outstanding ping Omaha requests. If we call
- // StartProcessing() asynchronously, the device can be suspended before we
- // get a chance to callback to StartProcessing(). When the device resumes
- // (assuming the device sleeps longer than the next update check period),
- // StartProcessing() is called back and at the same time, the next update
- // check is fired which eventually invokes StartProcessing(). A crash
- // can occur because StartProcessing() checks to make sure that the
- // processor is idle which it isn't due to the two concurrent ping Omaha
- // requests.
- processor_->StartProcessing();
- } else {
- LOG(WARNING) << "Action processor running, Omaha ping suppressed.";
- }
-
- // Update the last check time here; it may be re-updated when an Omaha
- // response is received, but this will prevent us from repeatedly scheduling
- // checks in the case where a response is not received.
- UpdateLastCheckedTime();
-
- // Update the status which will schedule the next update check
- SetStatusAndNotify(UpdateStatus::UPDATED_NEED_REBOOT);
- ScheduleUpdates();
-}
-
-bool UpdateAttempter::DecrementUpdateCheckCount() {
- int64_t update_check_count_value;
-
- if (!prefs_->Exists(kPrefsUpdateCheckCount)) {
- // This file does not exist. This means we haven't started our update
- // check count down yet, so nothing more to do. This file will be created
- // later when we first satisfy the wall-clock-based-wait period.
- LOG(INFO) << "No existing update check count. That's normal.";
- return true;
- }
-
- if (prefs_->GetInt64(kPrefsUpdateCheckCount, &update_check_count_value)) {
- // Only if we're able to read a proper integer value, then go ahead
- // and decrement and write back the result in the same file, if needed.
- LOG(INFO) << "Update check count = " << update_check_count_value;
-
- if (update_check_count_value == 0) {
- // It could be 0, if, for some reason, the file didn't get deleted
- // when we set our status to waiting for reboot. so we just leave it
- // as is so that we can prevent another update_check wait for this client.
- LOG(INFO) << "Not decrementing update check count as it's already 0.";
- return true;
- }
-
- if (update_check_count_value > 0)
- update_check_count_value--;
- else
- update_check_count_value = 0;
-
- // Write out the new value of update_check_count_value.
- if (prefs_->SetInt64(kPrefsUpdateCheckCount, update_check_count_value)) {
- // We successfully wrote out the new value, so enable the
- // update check based wait.
- LOG(INFO) << "New update check count = " << update_check_count_value;
- return true;
- }
- }
-
- LOG(INFO) << "Deleting update check count state due to read/write errors.";
-
- // We cannot read/write to the file, so disable the update check based wait
- // so that we don't get stuck in this OS version by any chance (which could
- // happen if there's some bug that causes to read/write incorrectly).
- // Also attempt to delete the file to do our best effort to cleanup.
- prefs_->Delete(kPrefsUpdateCheckCount);
- return false;
-}
-
-void UpdateAttempter::UpdateEngineStarted() {
- // If we just booted into a new update, keep the previous OS version
- // in case we rebooted because of a crash of the old version, so we
- // can do a proper crash report with correct information.
- // This must be done before calling
- // SystemState::Get()->payload_state()->UpdateEngineStarted() since it will
- // delete SystemUpdated marker file.
- if (SystemState::Get()->system_rebooted() &&
- prefs_->Exists(kPrefsSystemUpdatedMarker)) {
- if (!prefs_->GetString(kPrefsPreviousVersion, &prev_version_)) {
- // If we fail to get the version string, make sure it stays empty.
- prev_version_.clear();
- }
- }
-
- MoveToPrefs({kPrefsLastRollCallPingDay, kPrefsLastActivePingDay});
-
- SystemState::Get()->payload_state()->UpdateEngineStarted();
- StartP2PAtStartup();
-
- excluder_ = CreateExcluder();
-}
-
-void UpdateAttempter::MoveToPrefs(const vector<string>& keys) {
- auto* powerwash_safe_prefs = SystemState::Get()->powerwash_safe_prefs();
- for (const auto& key : keys) {
- // Do not overwrite existing pref key with powerwash prefs.
- if (!prefs_->Exists(key) && powerwash_safe_prefs->Exists(key)) {
- string value;
- if (!powerwash_safe_prefs->GetString(key, &value) ||
- !prefs_->SetString(key, value)) {
- PLOG(ERROR) << "Unable to add powerwash safe key " << key
- << " to prefs. Powerwash safe key will be deleted.";
- }
- }
- // Delete keys regardless of operation success to preserve privacy.
- powerwash_safe_prefs->Delete(key);
- }
-}
-
-bool UpdateAttempter::StartP2PAtStartup() {
- if (!SystemState::Get()->p2p_manager()->IsP2PEnabled()) {
- LOG(INFO) << "Not starting p2p at startup since it's not enabled.";
- return false;
- }
-
- if (SystemState::Get()->p2p_manager()->CountSharedFiles() < 1) {
- LOG(INFO) << "Not starting p2p at startup since our application "
- << "is not sharing any files.";
- return false;
- }
-
- return StartP2PAndPerformHousekeeping();
-}
-
-bool UpdateAttempter::StartP2PAndPerformHousekeeping() {
- if (!SystemState::Get()->p2p_manager()->IsP2PEnabled()) {
- LOG(INFO) << "Not starting p2p since it's not enabled.";
- return false;
- }
-
- LOG(INFO) << "Ensuring that p2p is running.";
- if (!SystemState::Get()->p2p_manager()->EnsureP2PRunning()) {
- LOG(ERROR) << "Error starting p2p.";
- return false;
- }
-
- LOG(INFO) << "Performing p2p housekeeping.";
- if (!SystemState::Get()->p2p_manager()->PerformHousekeeping()) {
- LOG(ERROR) << "Error performing housekeeping for p2p.";
- return false;
- }
-
- LOG(INFO) << "Done performing p2p housekeeping.";
- return true;
-}
-
-bool UpdateAttempter::GetBootTimeAtUpdate(Time* out_boot_time) {
- // In case of an update_engine restart without a reboot, we stored the boot_id
- // when the update was completed by setting a pref, so we can check whether
- // the last update was on this boot or a previous one.
- string boot_id;
- TEST_AND_RETURN_FALSE(utils::GetBootId(&boot_id));
-
- string update_completed_on_boot_id;
- if (!prefs_->Exists(kPrefsUpdateCompletedOnBootId) ||
- !prefs_->GetString(kPrefsUpdateCompletedOnBootId,
- &update_completed_on_boot_id) ||
- update_completed_on_boot_id != boot_id)
- return false;
-
- // Short-circuit avoiding the read in case out_boot_time is nullptr.
- if (out_boot_time) {
- int64_t boot_time = 0;
- // Since the kPrefsUpdateCompletedOnBootId was correctly set, this pref
- // should not fail.
- TEST_AND_RETURN_FALSE(
- prefs_->GetInt64(kPrefsUpdateCompletedBootTime, &boot_time));
- *out_boot_time = Time::FromInternalValue(boot_time);
- }
- return true;
-}
-
-bool UpdateAttempter::IsBusyOrUpdateScheduled() {
- return ((status_ != UpdateStatus::IDLE &&
- status_ != UpdateStatus::UPDATED_NEED_REBOOT) ||
- waiting_for_scheduled_check_);
-}
-
-bool UpdateAttempter::IsAnyUpdateSourceAllowed() const {
- // We allow updates from any source if either of these are true:
- // * The device is running an unofficial (dev/test) image.
- // * The debugd dev features are accessible (i.e. in devmode with no owner).
- // This protects users running a base image, while still allowing a specific
- // window (gated by the debug dev features) where `cros flash` is usable.
- if (!SystemState::Get()->hardware()->IsOfficialBuild()) {
- LOG(INFO) << "Non-official build; allowing any update source.";
- return true;
- }
-
- if (SystemState::Get()->hardware()->AreDevFeaturesEnabled()) {
- LOG(INFO) << "Developer features enabled; allowing custom update sources.";
- return true;
- }
-
- LOG(INFO)
- << "Developer features disabled; disallowing custom update sources.";
- return false;
-}
-
-void UpdateAttempter::ReportTimeToUpdateAppliedMetric() {
- const policy::DevicePolicy* device_policy =
- SystemState::Get()->device_policy();
- if (device_policy && device_policy->IsEnterpriseEnrolled()) {
- vector<policy::DevicePolicy::WeeklyTimeInterval> parsed_intervals;
- bool has_time_restrictions =
- device_policy->GetDisallowedTimeIntervals(&parsed_intervals);
-
- int64_t update_first_seen_at_int;
- if (SystemState::Get()->prefs()->Exists(kPrefsUpdateFirstSeenAt)) {
- if (SystemState::Get()->prefs()->GetInt64(kPrefsUpdateFirstSeenAt,
- &update_first_seen_at_int)) {
- TimeDelta update_delay =
- SystemState::Get()->clock()->GetWallclockTime() -
- Time::FromInternalValue(update_first_seen_at_int);
- SystemState::Get()
- ->metrics_reporter()
- ->ReportEnterpriseUpdateSeenToDownloadDays(has_time_restrictions,
- update_delay.InDays());
- }
- }
- }
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/update_attempter.h b/cros/update_attempter.h
deleted file mode 100644
index 6010484a..00000000
--- a/cros/update_attempter.h
+++ /dev/null
@@ -1,581 +0,0 @@
-//
-// Copyright (C) 2012 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_CROS_UPDATE_ATTEMPTER_H_
-#define UPDATE_ENGINE_CROS_UPDATE_ATTEMPTER_H_
-
-#include <time.h>
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/guid.h>
-#include <base/time/time.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-#include "update_engine/certificate_checker.h"
-#include "update_engine/client_library/include/update_engine/update_status.h"
-#include "update_engine/common/action_processor.h"
-#include "update_engine/common/cpu_limiter.h"
-#include "update_engine/common/daemon_state_interface.h"
-#include "update_engine/common/download_action.h"
-#include "update_engine/common/excluder_interface.h"
-#include "update_engine/common/proxy_resolver.h"
-#include "update_engine/common/service_observer_interface.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/cros/chrome_browser_proxy_resolver.h"
-#include "update_engine/cros/omaha_request_builder_xml.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/omaha_response_handler_action.h"
-#include "update_engine/payload_consumer/postinstall_runner_action.h"
-#include "update_engine/update_manager/policy.h"
-#include "update_engine/update_manager/staging_utils.h"
-#include "update_engine/update_manager/update_manager.h"
-
-namespace policy {
-class PolicyProvider;
-}
-
-namespace chromeos_update_engine {
-
-class UpdateAttempter : public ActionProcessorDelegate,
- public DownloadActionDelegate,
- public CertificateChecker::Observer,
- public PostinstallRunnerAction::DelegateInterface,
- public DaemonStateInterface {
- public:
- using UpdateStatus = update_engine::UpdateStatus;
- using UpdateAttemptFlags = update_engine::UpdateAttemptFlags;
- static const int kMaxDeltaUpdateFailures;
-
- explicit UpdateAttempter(CertificateChecker* cert_checker);
- ~UpdateAttempter() override;
-
- // Further initialization to be done post construction.
- void Init();
-
- // Initiates scheduling of update checks.
- // Returns true if update check is scheduled.
- virtual bool ScheduleUpdates();
-
- // Checks for update and, if a newer version is available, attempts to update
- // the system.
- virtual void Update(const chromeos_update_manager::UpdateCheckParams& params);
-
- // ActionProcessorDelegate methods:
- void ProcessingDone(const ActionProcessor* processor,
- ErrorCode code) override;
- void ProcessingStopped(const ActionProcessor* processor) override;
- void ActionCompleted(ActionProcessor* processor,
- AbstractAction* action,
- ErrorCode code) override;
-
- // PostinstallRunnerAction::DelegateInterface
- void ProgressUpdate(double progress) override;
-
- // Resets the current state to UPDATE_STATUS_IDLE.
- // Used by update_engine_client for restarting a new update without
- // having to reboot once the previous update has reached
- // UPDATE_STATUS_UPDATED_NEED_REBOOT state. This is used only
- // for testing purposes.
- virtual bool ResetStatus();
-
- // Returns the current status in the out param. Returns true on success.
- virtual bool GetStatus(update_engine::UpdateEngineStatus* out_status);
-
- UpdateStatus status() const { return status_; }
-
- int http_response_code() const { return http_response_code_; }
- void set_http_response_code(int code) { http_response_code_ = code; }
-
- // Set flags that influence how updates and checks are performed. These
- // influence all future checks and updates until changed or the device
- // reboots.
- void SetUpdateAttemptFlags(UpdateAttemptFlags flags) {
- update_attempt_flags_ = flags;
- }
-
- // Returns the update attempt flags that are in place for the current update
- // attempt. These are cached at the start of an update attempt so that they
- // remain constant throughout the process.
- virtual UpdateAttemptFlags GetCurrentUpdateAttemptFlags() const {
- return current_update_attempt_flags_;
- }
-
- // This is the internal entry point for going through an
- // update. If the current status is idle invokes Update.
- // This is called by the DBus implementation.
- // This returns true if an update check was started, false if a check or an
- // update was already in progress.
- virtual bool CheckForUpdate(const std::string& app_version,
- const std::string& omaha_url,
- UpdateAttemptFlags flags);
-
- // This is the version of CheckForUpdate called by AttemptInstall API.
- virtual bool CheckForInstall(const std::vector<std::string>& dlc_ids,
- const std::string& omaha_url);
-
- // This is the internal entry point for going through a rollback. This will
- // attempt to run the postinstall on the non-active partition and set it as
- // the partition to boot from. If |powerwash| is True, perform a powerwash
- // as part of rollback. Returns True on success.
- bool Rollback(bool powerwash);
-
- // This is the internal entry point for checking if we can rollback.
- bool CanRollback() const;
-
- // This is the internal entry point for getting a rollback partition name,
- // if one exists. It returns the bootable rollback kernel device partition
- // name or empty string if none is available.
- BootControlInterface::Slot GetRollbackSlot() const;
-
- // Initiates a reboot if the current state is
- // UPDATED_NEED_REBOOT. Returns true on success, false otherwise.
- bool RebootIfNeeded();
-
- // Sets the DLC as active or inactive. See chromeos/common_service.h
- virtual bool SetDlcActiveValue(bool is_active, const std::string& dlc_id);
-
- // DownloadActionDelegate methods:
- void BytesReceived(uint64_t bytes_progressed,
- uint64_t bytes_received,
- uint64_t total) override;
-
- // Returns that the update should be canceled when the download channel was
- // changed.
- bool ShouldCancel(ErrorCode* cancel_reason) override;
-
- void DownloadComplete() override;
-
- // Broadcasts the current status to all observers.
- void BroadcastStatus();
-
- ErrorCode GetAttemptErrorCode() const { return attempt_error_code_; }
-
- // Called at update_engine startup to do various house-keeping.
- void UpdateEngineStarted();
-
- // Returns the |Excluder| that is currently held onto.
- virtual ExcluderInterface* GetExcluder() const { return excluder_.get(); }
-
- // Reloads the device policy from libbrillo. Note: This method doesn't
- // cause a real-time policy fetch from the policy server. It just reloads the
- // latest value that libbrillo has cached. libbrillo fetches the policies
- // from the server asynchronously at its own frequency.
- virtual void RefreshDevicePolicy();
-
- // Stores in |out_boot_time| the boottime (CLOCK_BOOTTIME) recorded at the
- // time of the last successful update in the current boot. Returns false if
- // there wasn't a successful update in the current boot.
- virtual bool GetBootTimeAtUpdate(base::Time* out_boot_time);
-
- // Returns a version OS version that was being used before the last reboot,
- // and if that reboot happened to be into an update (current version).
- // This will return an empty string otherwise.
- const std::string& GetPrevVersion() const { return prev_version_; }
-
- // Returns the number of consecutive failed update checks.
- virtual unsigned int consecutive_failed_update_checks() const {
- return consecutive_failed_update_checks_;
- }
-
- // Returns the poll interval dictated by Omaha, if provided; zero otherwise.
- virtual unsigned int server_dictated_poll_interval() const {
- return server_dictated_poll_interval_;
- }
-
- // Sets a callback to be used when either a forced update request is received
- // (first argument set to true) or cleared by an update attempt (first
- // argument set to false). The callback further encodes whether the forced
- // check is an interactive one (second argument set to true). Takes ownership
- // of the callback object. A null value disables callback on these events.
- // Note that only one callback can be set, so effectively at most one client
- // can be notified.
- virtual void set_forced_update_pending_callback(
- base::Callback<void(bool, bool)>* callback) {
- forced_update_pending_callback_.reset(callback);
- }
-
- // Returns true if we should allow updates from any source. In official builds
- // we want to restrict updates to known safe sources, but under certain
- // conditions it's useful to allow updating from anywhere (e.g. to allow
- // 'cros flash' to function properly).
- bool IsAnyUpdateSourceAllowed() const;
-
- // |DaemonStateInterface| overrides.
- bool StartUpdater() override;
- void AddObserver(ServiceObserverInterface* observer) override {
- service_observers_.insert(observer);
- }
- void RemoveObserver(ServiceObserverInterface* observer) override {
- service_observers_.erase(observer);
- }
- const std::set<ServiceObserverInterface*>& service_observers() override {
- return service_observers_;
- }
-
- // Remove all the observers.
- void ClearObservers() { service_observers_.clear(); }
-
- private:
- // Friend declarations for testing purposes.
- friend class UpdateAttempterUnderTest;
- friend class UpdateAttempterTest;
- FRIEND_TEST(UpdateAttempterTest, ActionCompletedDownloadTest);
- FRIEND_TEST(UpdateAttempterTest, ActionCompletedErrorTest);
- FRIEND_TEST(UpdateAttempterTest, ActionCompletedOmahaRequestTest);
- FRIEND_TEST(UpdateAttempterTest, BootTimeInUpdateMarkerFile);
- FRIEND_TEST(UpdateAttempterTest, BroadcastCompleteDownloadTest);
- FRIEND_TEST(UpdateAttempterTest, CalculateDlcParamsInstallTest);
- FRIEND_TEST(UpdateAttempterTest, CalculateDlcParamsNoPrefFilesTest);
- FRIEND_TEST(UpdateAttempterTest, CalculateDlcParamsNonParseableValuesTest);
- FRIEND_TEST(UpdateAttempterTest, CalculateDlcParamsValidValuesTest);
- FRIEND_TEST(UpdateAttempterTest, CalculateDlcParamsRemoveStaleMetadata);
- FRIEND_TEST(UpdateAttempterTest, ChangeToDownloadingOnReceivedBytesTest);
- FRIEND_TEST(UpdateAttempterTest, CheckForInstallNotIdleFails);
- FRIEND_TEST(UpdateAttempterTest, CheckForUpdateAUDlcTest);
- FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventTest);
- FRIEND_TEST(UpdateAttempterTest, CreatePendingErrorEventResumedTest);
- FRIEND_TEST(UpdateAttempterTest, DisableDeltaUpdateIfNeededTest);
- FRIEND_TEST(UpdateAttempterTest, DownloadProgressAccumulationTest);
- FRIEND_TEST(UpdateAttempterTest, InstallSetsStatusIdle);
- FRIEND_TEST(UpdateAttempterTest, IsEnterpriseRollbackInGetStatusTrue);
- FRIEND_TEST(UpdateAttempterTest, IsEnterpriseRollbackInGetStatusFalse);
- FRIEND_TEST(UpdateAttempterTest,
- PowerwashInGetStatusTrueBecausePowerwashRequired);
- FRIEND_TEST(UpdateAttempterTest, PowerwashInGetStatusTrueBecauseRollback);
- FRIEND_TEST(UpdateAttempterTest, MarkDeltaUpdateFailureTest);
- FRIEND_TEST(UpdateAttempterTest, PingOmahaTest);
- FRIEND_TEST(UpdateAttempterTest, ProcessingDoneInstallError);
- FRIEND_TEST(UpdateAttempterTest, ProcessingDoneUpdateError);
- FRIEND_TEST(UpdateAttempterTest, ReportDailyMetrics);
- FRIEND_TEST(UpdateAttempterTest, RollbackNotAllowed);
- FRIEND_TEST(UpdateAttempterTest, RollbackAfterInstall);
- FRIEND_TEST(UpdateAttempterTest, RollbackAllowed);
- FRIEND_TEST(UpdateAttempterTest, RollbackAllowedSetAndReset);
- FRIEND_TEST(UpdateAttempterTest, ChannelDowngradeNoRollback);
- FRIEND_TEST(UpdateAttempterTest, ChannelDowngradeRollback);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackFailure);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackFailure);
- FRIEND_TEST(UpdateAttempterTest, RollbackMetricsRollbackSuccess);
- FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionNoEventTest);
- FRIEND_TEST(UpdateAttempterTest, ScheduleErrorEventActionTest);
- FRIEND_TEST(UpdateAttempterTest, SessionIdTestEnforceEmptyStrPingOmaha);
- 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);
- FRIEND_TEST(UpdateAttempterTest, UpdateDeferredByPolicyTest);
- FRIEND_TEST(UpdateAttempterTest, UpdateIsNotRunningWhenUpdateAvailable);
- FRIEND_TEST(UpdateAttempterTest, GetSuccessfulDlcIds);
- FRIEND_TEST(UpdateAttempterTest, QuickFixTokenWhenDeviceIsEnterpriseEnrolled);
- FRIEND_TEST(UpdateAttempterTest, MoveToPrefs);
-
- // Returns the special flags to be added to ErrorCode values based on the
- // parameters used in the current update attempt.
- uint32_t GetErrorCodeFlags();
-
- // ActionProcessorDelegate methods |ProcessingDone()| internal helpers.
- void ProcessingDoneInternal(const ActionProcessor* processor, ErrorCode code);
- void ProcessingDoneUpdate(const ActionProcessor* processor, ErrorCode code);
- void ProcessingDoneInstall(const ActionProcessor* processor, ErrorCode code);
-
- // CertificateChecker::Observer method.
- // Report metrics about the certificate being checked.
- void CertificateChecked(ServerToCheck server_to_check,
- CertificateCheckResult result) override;
-
- // Checks if it's more than 24 hours since daily metrics were last
- // reported and, if so, reports daily metrics. Returns |true| if
- // metrics were reported, |false| otherwise.
- bool CheckAndReportDailyMetrics();
-
- // Calculates and reports the age of the currently running OS. This
- // is defined as the age of the /etc/lsb-release file.
- void ReportOSAge();
-
- // Sets the status to the given status and notifies a status update over dbus.
- void SetStatusAndNotify(UpdateStatus status);
-
- // Creates an error event object in |error_event_| to be included in an
- // OmahaRequestAction once the current action processor is done.
- void CreatePendingErrorEvent(AbstractAction* action, ErrorCode code);
-
- // If there's a pending error event allocated in |error_event_|, schedules an
- // OmahaRequestAction with that event in the current processor, clears the
- // pending event, updates the status and returns true. Returns false
- // otherwise.
- bool ScheduleErrorEventAction();
-
- // Schedules an event loop callback to start the action processor. This is
- // scheduled asynchronously to unblock the event loop.
- void ScheduleProcessingStart();
-
- // Checks if a full update is needed and forces it by updating the Omaha
- // request params.
- void DisableDeltaUpdateIfNeeded();
-
- // If this was a delta update attempt that failed, count it so that a full
- // update can be tried when needed.
- void MarkDeltaUpdateFailure();
-
- ProxyResolver* GetProxyResolver() {
- if (obeying_proxies_)
- return &chrome_proxy_resolver_;
- return &direct_proxy_resolver_;
- }
-
- // Sends a ping to Omaha.
- // This is used after an update has been applied and we're waiting for the
- // user to reboot. This ping helps keep the number of actives count
- // accurate in case a user takes a long time to reboot the device after an
- // update has been applied.
- void PingOmaha();
-
- // Helper method of Update() to calculate the update-related parameters
- // from various sources and set the appropriate state. Please refer to
- // Update() method for the meaning of the parameters.
- bool CalculateUpdateParams(
- const chromeos_update_manager::UpdateCheckParams& params);
-
- // Calculates all the scattering related parameters (such as waiting period,
- // which type of scattering is enabled, etc.) and also updates/deletes
- // the corresponding prefs file used in scattering. Should be called
- // only after the device policy has been loaded and set in the system state.
- void CalculateScatteringParams(bool interactive);
-
- // Sets a random value for the waiting period to wait for before downloading
- // an update, if one available. This value will be upperbounded by the
- // scatter factor value specified from policy.
- void GenerateNewWaitingPeriod();
-
- // Helper method of Update() to construct the sequence of actions to
- // be performed for an update check. Please refer to
- // Update() method for the meaning of the parameters.
- void BuildUpdateActions(bool interactive);
-
- // Decrements the count in the kUpdateCheckCountFilePath.
- // Returns True if successfully decremented, false otherwise.
- bool DecrementUpdateCheckCount();
-
- // Starts p2p and performs housekeeping. Returns true only if p2p is
- // running and housekeeping was done.
- bool StartP2PAndPerformHousekeeping();
-
- // Calculates whether peer-to-peer should be used. Sets the
- // |use_p2p_to_download_| and |use_p2p_to_share_| parameters
- // on the |omaha_request_params_| object.
- void CalculateP2PParams(bool interactive);
-
- // For each key, reads value from powerwash safe prefs and adds it to prefs
- // if key doesnt already exist. Then deletes the powerwash safe keys.
- void MoveToPrefs(const std::vector<std::string>& keys);
-
- // Starts P2P if it's enabled and there are files to actually share.
- // Called only at program startup. Returns true only if p2p was
- // started and housekeeping was performed.
- bool StartP2PAtStartup();
-
- // Writes to the processing completed marker. Does nothing if
- // |update_completed_marker_| is empty.
- void WriteUpdateCompletedMarker();
-
- // Reboots the system directly by calling /sbin/shutdown. Returns true on
- // success.
- bool RebootDirectly();
-
- // Callback for the async UpdateCheckAllowed policy request. If |status| is
- // |EvalStatus::kSucceeded|, either runs or suppresses periodic update checks,
- // based on the content of |params|. Otherwise, retries the policy request.
- void OnUpdateScheduled(
- chromeos_update_manager::EvalStatus status,
- const chromeos_update_manager::UpdateCheckParams& params);
-
- // Updates the time an update was last attempted to the current time.
- void UpdateLastCheckedTime();
-
- // Checks whether we need to clear the rollback-happened preference after
- // policy is available again.
- void UpdateRollbackHappened();
-
- // Returns if an update is: running, applied and needs reboot, or scheduled.
- bool IsBusyOrUpdateScheduled();
-
- void CalculateStagingParams(bool interactive);
-
- // Reports a metric that tracks the time from when the update was first seen
- // to the time when the update was finally downloaded and applied. This metric
- // will only be reported for enterprise enrolled devices.
- void ReportTimeToUpdateAppliedMetric();
-
- // Resets interactivity and forced update flags.
- void ResetInteractivityFlags();
-
- // Resets all the DLC prefs.
- bool ResetDlcPrefs(const std::string& dlc_id);
-
- // Sets given pref key for DLC and platform.
- void SetPref(const std::string& pref_key,
- const std::string& pref_value,
- const std::string& payload_id);
-
- // Get the integer values from the DLC metadata for |kPrefsPingLastActive|
- // or |kPrefsPingLastRollcall|.
- // The value is equal to -2 when the value cannot be read or is not numeric.
- // The value is equal to -1 the first time it is being sent, which is
- // when the metadata file doesn't exist.
- int64_t GetPingMetadata(const std::string& metadata_key) const;
-
- // Calculates the update parameters for DLCs. Sets the |dlc_ids_|
- // parameter on the |omaha_request_params_| object.
- void CalculateDlcParams();
-
- // Returns the list of DLC IDs that were installed/updated, excluding the ones
- // which had "noupdate" in the Omaha response.
- std::vector<std::string> GetSuccessfulDlcIds();
-
- // Last status notification timestamp used for throttling. Use monotonic
- // TimeTicks to ensure that notifications are sent even if the system clock is
- // set back in the middle of an update.
- base::TimeTicks last_notify_time_;
-
- // Our two proxy resolvers
- DirectProxyResolver direct_proxy_resolver_;
- ChromeBrowserProxyResolver chrome_proxy_resolver_;
-
- std::unique_ptr<ActionProcessor> processor_;
-
- ActionProcessor aux_processor_;
-
- // Pointer to the certificate checker instance to use.
- CertificateChecker* cert_checker_;
-
- // The list of services observing changes in the updater.
- std::set<ServiceObserverInterface*> service_observers_;
-
- // The install plan.
- std::unique_ptr<InstallPlan> install_plan_;
-
- // Pointer to the preferences store interface. This is just a cached
- // copy of SystemState::Get()->prefs() because it's used in many methods and
- // is convenient this way.
- PrefsInterface* prefs_ = nullptr;
-
- // Pending error event, if any.
- std::unique_ptr<OmahaEvent> error_event_;
-
- // If we should request a reboot even tho we failed the update
- bool fake_update_success_ = false;
-
- // HTTP server response code from the last HTTP request action.
- int http_response_code_ = 0;
-
- // The attempt error code when the update attempt finished.
- ErrorCode attempt_error_code_ = ErrorCode::kSuccess;
-
- // CPU limiter during the update.
- CPULimiter cpu_limiter_;
-
- // For status:
- UpdateStatus status_{UpdateStatus::IDLE};
- double download_progress_ = 0.0;
- int64_t last_checked_time_ = 0;
- std::string prev_version_;
- std::string new_version_ = "0.0.0.0";
- uint64_t new_payload_size_ = 0;
- // Flags influencing all periodic update checks
- UpdateAttemptFlags update_attempt_flags_ = UpdateAttemptFlags::kNone;
- // Flags influencing the currently in-progress check (cached at the start of
- // the update check).
- UpdateAttemptFlags current_update_attempt_flags_ = UpdateAttemptFlags::kNone;
-
- // Common parameters for all Omaha requests.
- OmahaRequestParams* omaha_request_params_ = nullptr;
-
- // Number of consecutive manual update checks we've had where we obeyed
- // Chrome's proxy settings.
- int proxy_manual_checks_ = 0;
-
- // If true, this update cycle we are obeying proxies
- bool obeying_proxies_ = true;
-
- // Used for fetching information about the device policy.
- std::unique_ptr<policy::PolicyProvider> policy_provider_;
-
- // The current scatter factor as found in the policy setting.
- base::TimeDelta scatter_factor_;
-
- // The number of consecutive failed update checks. Needed for calculating the
- // next update check interval.
- unsigned int consecutive_failed_update_checks_ = 0;
-
- // The poll interval (in seconds) that was dictated by Omaha, if any; zero
- // otherwise. This is needed for calculating the update check interval.
- unsigned int server_dictated_poll_interval_ = 0;
-
- // Tracks whether we have scheduled update checks.
- bool waiting_for_scheduled_check_ = false;
-
- // A callback to use when a forced update request is either received (true) or
- // cleared by an update attempt (false). The second argument indicates whether
- // this is an interactive update, and its value is significant iff the first
- // argument is true.
- std::unique_ptr<base::Callback<void(bool, bool)>>
- forced_update_pending_callback_;
-
- // The |app_version| and |omaha_url| parameters received during the latest
- // forced update request. They are retrieved for use once the update is
- // actually scheduled.
- std::string forced_app_version_;
- std::string forced_omaha_url_;
-
- // A list of DLC module IDs.
- std::vector<std::string> dlc_ids_;
- // Whether the operation is install (write to the current slot not the
- // inactive slot).
- bool is_install_;
-
- // If this is not TimeDelta(), then that means staging is turned on.
- base::TimeDelta staging_wait_time_;
- chromeos_update_manager::StagingSchedule staging_schedule_;
-
- // This is the session ID used to track update flow to Omaha.
- std::string session_id_;
-
- // Interface for excluder.
- std::unique_ptr<ExcluderInterface> excluder_;
-
- DISALLOW_COPY_AND_ASSIGN(UpdateAttempter);
-};
-
-// Turns a generic ErrorCode::kError to a generic error code specific
-// to |action| (e.g., ErrorCode::kFilesystemVerifierError). If |code| is
-// not ErrorCode::kError, or the action is not matched, returns |code|
-// unchanged.
-
-ErrorCode GetErrorCodeForAction(AbstractAction* action, ErrorCode code);
-
-} // namespace chromeos_update_engine
-
-#endif // UPDATE_ENGINE_CROS_UPDATE_ATTEMPTER_H_
diff --git a/cros/update_attempter_unittest.cc b/cros/update_attempter_unittest.cc
deleted file mode 100644
index a7f5236e..00000000
--- a/cros/update_attempter_unittest.cc
+++ /dev/null
@@ -1,2479 +0,0 @@
-//
-// Copyright (C) 2012 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/cros/update_attempter.h"
-
-#include <stdint.h>
-
-#include <limits>
-#include <map>
-#include <memory>
-#include <string>
-#include <unordered_set>
-
-#include <base/files/file_util.h>
-#include <base/files/scoped_temp_dir.h>
-#include <base/task/single_thread_task_executor.h>
-#include <brillo/message_loops/base_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gtest/gtest.h>
-#include <policy/libpolicy.h>
-#include <policy/mock_device_policy.h>
-#include <policy/mock_libpolicy.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/dlcservice_interface.h"
-#include "update_engine/common/mock_action.h"
-#include "update_engine/common/mock_action_processor.h"
-#include "update_engine/common/mock_http_fetcher.h"
-#include "update_engine/common/mock_service_observer.h"
-#include "update_engine/common/platform_constants.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/test_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/download_action_chromeos.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/cros/mock_p2p_manager.h"
-#include "update_engine/cros/mock_payload_state.h"
-#include "update_engine/cros/omaha_utils.h"
-#include "update_engine/libcurl_http_fetcher.h"
-#include "update_engine/payload_consumer/filesystem_verifier_action.h"
-#include "update_engine/payload_consumer/install_plan.h"
-#include "update_engine/payload_consumer/payload_constants.h"
-#include "update_engine/payload_consumer/postinstall_runner_action.h"
-#include "update_engine/update_boot_flags_action.h"
-#include "update_engine/update_manager/mock_update_manager.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_manager::EvalStatus;
-using chromeos_update_manager::MockUpdateManager;
-using chromeos_update_manager::StagingSchedule;
-using chromeos_update_manager::UpdateCheckParams;
-using policy::DevicePolicy;
-using std::map;
-using std::string;
-using std::unique_ptr;
-using std::unordered_set;
-using std::vector;
-using testing::_;
-using testing::Contains;
-using testing::DoAll;
-using testing::ElementsAre;
-using testing::Field;
-using testing::InSequence;
-using testing::Invoke;
-using testing::Ne;
-using testing::NiceMock;
-using testing::Pointee;
-using testing::Property;
-using testing::Return;
-using testing::ReturnPointee;
-using testing::ReturnRef;
-using testing::SaveArg;
-using testing::SetArgPointee;
-using update_engine::UpdateAttemptFlags;
-using update_engine::UpdateEngineStatus;
-using update_engine::UpdateStatus;
-
-namespace chromeos_update_engine {
-
-namespace {
-
-const UpdateStatus kNonIdleUpdateStatuses[] = {
- UpdateStatus::CHECKING_FOR_UPDATE,
- UpdateStatus::UPDATE_AVAILABLE,
- UpdateStatus::DOWNLOADING,
- UpdateStatus::VERIFYING,
- UpdateStatus::FINALIZING,
- UpdateStatus::UPDATED_NEED_REBOOT,
- UpdateStatus::REPORTING_ERROR_EVENT,
- UpdateStatus::ATTEMPTING_ROLLBACK,
- UpdateStatus::DISABLED,
- UpdateStatus::NEED_PERMISSION_TO_UPDATE,
-};
-
-struct CheckForUpdateTestParams {
- // Setups + Inputs:
- UpdateStatus status = UpdateStatus::IDLE;
- string app_version = "fake_app_version";
- string omaha_url = "fake_omaha_url";
- UpdateAttemptFlags flags = UpdateAttemptFlags::kNone;
- bool is_official_build = true;
- bool are_dev_features_enabled = false;
-
- // Expects:
- string expected_forced_app_version = "";
- string expected_forced_omaha_url = "";
- bool should_schedule_updates_be_called = true;
- bool expected_result = true;
-};
-
-struct OnUpdateScheduledTestParams {
- // Setups + Inputs:
- UpdateCheckParams params = {};
- EvalStatus status = EvalStatus::kFailed;
- // Expects:
- UpdateStatus exit_status = UpdateStatus::IDLE;
- bool should_schedule_updates_be_called = false;
- bool should_update_be_called = false;
-};
-
-struct ProcessingDoneTestParams {
- // Setups + Inputs:
- bool is_install = false;
- UpdateStatus status = UpdateStatus::CHECKING_FOR_UPDATE;
- ActionProcessor* processor = nullptr;
- ErrorCode code = ErrorCode::kSuccess;
- map<string, OmahaRequestParams::AppParams> dlc_apps_params;
-
- // Expects:
- const bool kExpectedIsInstall = false;
- bool should_schedule_updates_be_called = true;
- UpdateStatus expected_exit_status = UpdateStatus::IDLE;
- bool should_install_completed_be_called = false;
- bool should_update_completed_be_called = false;
- vector<string> args_to_install_completed;
- vector<string> args_to_update_completed;
-};
-
-class MockDlcService : public DlcServiceInterface {
- public:
- MOCK_METHOD1(GetDlcsToUpdate, bool(vector<string>*));
- MOCK_METHOD1(InstallCompleted, bool(const vector<string>&));
- MOCK_METHOD1(UpdateCompleted, bool(const vector<string>&));
-};
-
-} // namespace
-
-const char kRollbackVersion[] = "10575.39.2";
-
-// Test a subclass rather than the main class directly so that we can mock out
-// methods within the class. There're explicit unit tests for the mocked out
-// methods.
-class UpdateAttempterUnderTest : public UpdateAttempter {
- public:
- UpdateAttempterUnderTest() : UpdateAttempter(nullptr) {}
-
- void Update(const UpdateCheckParams& params) override {
- update_called_ = true;
- if (do_update_) {
- UpdateAttempter::Update(params);
- return;
- }
- LOG(INFO) << "[TEST] Update() disabled.";
- status_ = UpdateStatus::CHECKING_FOR_UPDATE;
- }
-
- void DisableUpdate() { do_update_ = false; }
-
- bool WasUpdateCalled() const { return update_called_; }
-
- // Wrap the update scheduling method, allowing us to opt out of scheduled
- // updates for testing purposes.
- bool ScheduleUpdates() override {
- schedule_updates_called_ = true;
- if (do_schedule_updates_)
- return UpdateAttempter::ScheduleUpdates();
- LOG(INFO) << "[TEST] Update scheduling disabled.";
- waiting_for_scheduled_check_ = true;
- return true;
- }
-
- void DisableScheduleUpdates() { do_schedule_updates_ = false; }
-
- // Indicates whether |ScheduleUpdates()| was called.
- bool WasScheduleUpdatesCalled() const { return schedule_updates_called_; }
-
- // Need to expose following private members of |UpdateAttempter| for tests.
- const string& forced_app_version() const { return forced_app_version_; }
- const string& forced_omaha_url() const { return forced_omaha_url_; }
-
- // Need to expose |waiting_for_scheduled_check_| for testing.
- void SetWaitingForScheduledCheck(bool waiting) {
- waiting_for_scheduled_check_ = waiting;
- }
-
- private:
- // Used for overrides of |Update()|.
- bool update_called_ = false;
- bool do_update_ = true;
-
- // Used for overrides of |ScheduleUpdates()|.
- bool schedule_updates_called_ = false;
- bool do_schedule_updates_ = true;
-};
-
-class UpdateAttempterTest : public ::testing::Test {
- protected:
- void SetUp() override {
- // Override system state members.
- FakeSystemState::CreateInstance();
- FakeSystemState::Get()->set_connection_manager(&mock_connection_manager);
- FakeSystemState::Get()->set_update_attempter(&attempter_);
- FakeSystemState::Get()->set_dlcservice(&mock_dlcservice_);
- FakeSystemState::Get()->set_update_manager(&mock_update_manager_);
- loop_.SetAsCurrent();
-
- prefs_ = FakeSystemState::Get()->fake_prefs();
- certificate_checker_.reset(
- new CertificateChecker(prefs_, &openssl_wrapper_));
- certificate_checker_->Init();
-
- attempter_.set_forced_update_pending_callback(
- new base::Callback<void(bool, bool)>(base::Bind([](bool, bool) {})));
- // Finish initializing the attempter.
- attempter_.Init();
-
- EXPECT_EQ(0, attempter_.http_response_code_);
- EXPECT_EQ(UpdateStatus::IDLE, attempter_.status_);
- EXPECT_EQ(0.0, attempter_.download_progress_);
- EXPECT_EQ(0, attempter_.last_checked_time_);
- EXPECT_EQ("0.0.0.0", attempter_.new_version_);
- EXPECT_EQ(0ULL, attempter_.new_payload_size_);
- processor_ = new NiceMock<MockActionProcessor>();
- attempter_.processor_.reset(processor_); // Transfers ownership.
-
- // Setup store/load semantics of P2P properties via the mock |PayloadState|.
- actual_using_p2p_for_downloading_ = false;
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- SetUsingP2PForDownloading(_))
- .WillRepeatedly(SaveArg<0>(&actual_using_p2p_for_downloading_));
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- GetUsingP2PForDownloading())
- .WillRepeatedly(ReturnPointee(&actual_using_p2p_for_downloading_));
- actual_using_p2p_for_sharing_ = false;
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- SetUsingP2PForSharing(_))
- .WillRepeatedly(SaveArg<0>(&actual_using_p2p_for_sharing_));
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- GetUsingP2PForDownloading())
- .WillRepeatedly(ReturnPointee(&actual_using_p2p_for_sharing_));
- }
-
- public:
- void ScheduleQuitMainLoop();
-
- // Callbacks to run the different tests from the main loop.
- void UpdateTestStart();
- void UpdateTestVerify();
- void RollbackTestStart(bool enterprise_rollback, bool valid_slot);
- void RollbackTestVerify();
- void PingOmahaTestStart();
- void ReadScatterFactorFromPolicyTestStart();
- void DecrementUpdateCheckCountTestStart();
- void NoScatteringDoneDuringManualUpdateTestStart();
- void P2PNotEnabledStart();
- void P2PEnabledStart();
- void P2PEnabledInteractiveStart();
- void P2PEnabledStartingFailsStart();
- void P2PEnabledHousekeepingFailsStart();
- void SessionIdTestChange();
- void SessionIdTestEnforceEmptyStrPingOmaha();
- void SessionIdTestConsistencyInUpdateFlow();
- void SessionIdTestInDownloadAction();
- void ResetRollbackHappenedStart(bool is_consumer,
- bool is_policy_available,
- bool expected_reset);
- // Staging related callbacks.
- void SetUpStagingTest(const StagingSchedule& schedule);
- void CheckStagingOff();
- void StagingSetsPrefsAndTurnsOffScatteringStart();
- void StagingOffIfInteractiveStart();
- void StagingOffIfOobeStart();
-
- bool actual_using_p2p_for_downloading() {
- return actual_using_p2p_for_downloading_;
- }
- bool actual_using_p2p_for_sharing() { return actual_using_p2p_for_sharing_; }
-
- // |CheckForUpdate()| related member functions.
- void TestCheckForUpdate();
-
- // |OnUpdateScheduled()| related member functions.
- void TestOnUpdateScheduled();
-
- // |ProcessingDone()| related member functions.
- void TestProcessingDone();
-
- base::SingleThreadTaskExecutor base_loop_{base::MessagePumpType::IO};
- brillo::BaseMessageLoop loop_{base_loop_.task_runner()};
-
- UpdateAttempterUnderTest attempter_;
- OpenSSLWrapper openssl_wrapper_;
- std::unique_ptr<CertificateChecker> certificate_checker_;
- MockDlcService mock_dlcservice_;
- MockUpdateManager mock_update_manager_;
-
- NiceMock<MockActionProcessor>* processor_;
- NiceMock<MockConnectionManager> mock_connection_manager;
-
- FakePrefs* prefs_;
-
- // |CheckForUpdate()| test params.
- CheckForUpdateTestParams cfu_params_;
-
- // |OnUpdateScheduled()| test params.
- OnUpdateScheduledTestParams ous_params_;
-
- // |ProcessingDone()| test params.
- ProcessingDoneTestParams pd_params_;
-
- bool actual_using_p2p_for_downloading_;
- bool actual_using_p2p_for_sharing_;
-};
-
-void UpdateAttempterTest::TestCheckForUpdate() {
- // Setup
- attempter_.status_ = cfu_params_.status;
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(
- cfu_params_.is_official_build);
- FakeSystemState::Get()->fake_hardware()->SetAreDevFeaturesEnabled(
- cfu_params_.are_dev_features_enabled);
-
- // Invocation
- EXPECT_EQ(
- cfu_params_.expected_result,
- attempter_.CheckForUpdate(
- cfu_params_.app_version, cfu_params_.omaha_url, cfu_params_.flags));
-
- // Verify
- EXPECT_EQ(cfu_params_.expected_forced_app_version,
- attempter_.forced_app_version());
- EXPECT_EQ(cfu_params_.expected_forced_omaha_url,
- attempter_.forced_omaha_url());
- EXPECT_EQ(cfu_params_.should_schedule_updates_be_called,
- attempter_.WasScheduleUpdatesCalled());
-}
-
-void UpdateAttempterTest::TestProcessingDone() {
- // Setup
- attempter_.DisableScheduleUpdates();
- attempter_.is_install_ = pd_params_.is_install;
- attempter_.status_ = pd_params_.status;
- attempter_.omaha_request_params_->set_dlc_apps_params(
- pd_params_.dlc_apps_params);
-
- // Expects
- if (pd_params_.should_install_completed_be_called)
- EXPECT_CALL(mock_dlcservice_,
- InstallCompleted(pd_params_.args_to_install_completed))
- .WillOnce(Return(true));
- else
- EXPECT_CALL(mock_dlcservice_, InstallCompleted(_)).Times(0);
- if (pd_params_.should_update_completed_be_called)
- EXPECT_CALL(mock_dlcservice_,
- UpdateCompleted(pd_params_.args_to_update_completed))
- .WillOnce(Return(true));
- else
- EXPECT_CALL(mock_dlcservice_, UpdateCompleted(_)).Times(0);
-
- // Invocation
- attempter_.ProcessingDone(pd_params_.processor, pd_params_.code);
-
- // Verify
- EXPECT_EQ(pd_params_.kExpectedIsInstall, attempter_.is_install_);
- EXPECT_EQ(pd_params_.should_schedule_updates_be_called,
- attempter_.WasScheduleUpdatesCalled());
- EXPECT_EQ(pd_params_.expected_exit_status, attempter_.status_);
-}
-
-void UpdateAttempterTest::ScheduleQuitMainLoop() {
- loop_.PostTask(
- FROM_HERE,
- base::Bind([](brillo::BaseMessageLoop* loop) { loop->BreakLoop(); },
- base::Unretained(&loop_)));
-}
-
-void UpdateAttempterTest::SessionIdTestChange() {
- EXPECT_NE(UpdateStatus::UPDATED_NEED_REBOOT, attempter_.status());
- const auto old_session_id = attempter_.session_id_;
- attempter_.Update({});
- EXPECT_NE(old_session_id, attempter_.session_id_);
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, SessionIdTestChange) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::SessionIdTestChange,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::SessionIdTestEnforceEmptyStrPingOmaha() {
- // The |session_id_| should not be changed and should remain as an empty
- // string when |status_| is |UPDATED_NEED_REBOOT| (only for consistency)
- // and |PingOmaha()| is called.
- attempter_.DisableScheduleUpdates();
- attempter_.status_ = UpdateStatus::UPDATED_NEED_REBOOT;
- const auto old_session_id = attempter_.session_id_;
- auto CheckIfEmptySessionId = [](AbstractAction* aa) {
- if (aa->Type() == OmahaRequestAction::StaticType()) {
- EXPECT_TRUE(static_cast<OmahaRequestAction*>(aa)->session_id_.empty());
- }
- };
- EXPECT_CALL(*processor_, EnqueueAction(Pointee(_)))
- .WillRepeatedly(Invoke(CheckIfEmptySessionId));
- EXPECT_CALL(*processor_, StartProcessing());
- attempter_.PingOmaha();
- EXPECT_EQ(old_session_id, attempter_.session_id_);
- EXPECT_EQ(UpdateStatus::UPDATED_NEED_REBOOT, attempter_.status_);
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, SessionIdTestEnforceEmptyStrPingOmaha) {
- loop_.PostTask(
- FROM_HERE,
- base::Bind(&UpdateAttempterTest::SessionIdTestEnforceEmptyStrPingOmaha,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::SessionIdTestConsistencyInUpdateFlow() {
- // All session IDs passed into |OmahaRequestActions| should be enforced to
- // have the same value in |BuildUpdateActions()|.
- unordered_set<string> session_ids;
- // Gather all the session IDs being passed to |OmahaRequestActions|.
- auto CheckSessionId = [&session_ids](AbstractAction* aa) {
- if (aa->Type() == OmahaRequestAction::StaticType())
- session_ids.insert(static_cast<OmahaRequestAction*>(aa)->session_id_);
- };
- EXPECT_CALL(*processor_, EnqueueAction(Pointee(_)))
- .WillRepeatedly(Invoke(CheckSessionId));
- attempter_.BuildUpdateActions(false);
- // Validate that all the session IDs are the same.
- EXPECT_EQ(1, session_ids.size());
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, SessionIdTestConsistencyInUpdateFlow) {
- loop_.PostTask(
- FROM_HERE,
- base::Bind(&UpdateAttempterTest::SessionIdTestConsistencyInUpdateFlow,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::SessionIdTestInDownloadAction() {
- // The session ID passed into |DownloadAction|'s |LibcurlHttpFetcher| should
- // be enforced to be included in the HTTP header as X-Goog-Update-SessionId.
- string header_value;
- auto CheckSessionIdInDownloadAction = [&header_value](AbstractAction* aa) {
- if (aa->Type() == DownloadActionChromeos::StaticType()) {
- DownloadActionChromeos* da = static_cast<DownloadActionChromeos*>(aa);
- EXPECT_TRUE(da->http_fetcher()->GetHeader(kXGoogleUpdateSessionId,
- &header_value));
- }
- };
- EXPECT_CALL(*processor_, EnqueueAction(Pointee(_)))
- .WillRepeatedly(Invoke(CheckSessionIdInDownloadAction));
- attempter_.BuildUpdateActions(false);
- // Validate that X-Goog-Update_SessionId is set correctly in HTTP Header.
- EXPECT_EQ(attempter_.session_id_, header_value);
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, SessionIdTestInDownloadAction) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::SessionIdTestInDownloadAction,
- base::Unretained(this)));
- loop_.Run();
-}
-
-TEST_F(UpdateAttempterTest, ActionCompletedDownloadTest) {
- unique_ptr<MockHttpFetcher> fetcher(new MockHttpFetcher("", 0, nullptr));
- fetcher->FailTransfer(503); // Sets the HTTP response code.
- DownloadActionChromeos action(
- prefs_, nullptr, nullptr, fetcher.release(), false /* interactive */);
- attempter_.ActionCompleted(nullptr, &action, ErrorCode::kSuccess);
- EXPECT_FALSE(prefs_->Exists(kPrefsDeltaUpdateFailures));
- EXPECT_EQ(UpdateStatus::FINALIZING, attempter_.status());
- EXPECT_EQ(0.0, attempter_.download_progress_);
- ASSERT_EQ(nullptr, attempter_.error_event_.get());
-}
-
-TEST_F(UpdateAttempterTest, ActionCompletedErrorTest) {
- MockAction action;
- EXPECT_CALL(action, Type()).WillRepeatedly(Return("MockAction"));
- attempter_.status_ = UpdateStatus::DOWNLOADING;
- attempter_.ActionCompleted(nullptr, &action, ErrorCode::kError);
- ASSERT_NE(nullptr, attempter_.error_event_.get());
-}
-
-TEST_F(UpdateAttempterTest, DownloadProgressAccumulationTest) {
- // Simple test case, where all the values match (nothing was skipped)
- uint64_t bytes_progressed_1 = 1024 * 1024; // 1MB
- uint64_t bytes_progressed_2 = 1024 * 1024; // 1MB
- uint64_t bytes_received_1 = bytes_progressed_1;
- uint64_t bytes_received_2 = bytes_received_1 + bytes_progressed_2;
- uint64_t bytes_total = 20 * 1024 * 1024; // 20MB
-
- double progress_1 =
- static_cast<double>(bytes_received_1) / static_cast<double>(bytes_total);
- double progress_2 =
- static_cast<double>(bytes_received_2) / static_cast<double>(bytes_total);
-
- EXPECT_EQ(0.0, attempter_.download_progress_);
- // This is set via inspecting the InstallPlan payloads when the
- // |OmahaResponseAction| is completed.
- attempter_.new_payload_size_ = bytes_total;
- NiceMock<MockServiceObserver> observer;
- EXPECT_CALL(observer,
- SendStatusUpdate(AllOf(
- Field(&UpdateEngineStatus::progress, progress_1),
- Field(&UpdateEngineStatus::status, UpdateStatus::DOWNLOADING),
- Field(&UpdateEngineStatus::new_size_bytes, bytes_total))));
- EXPECT_CALL(observer,
- SendStatusUpdate(AllOf(
- Field(&UpdateEngineStatus::progress, progress_2),
- Field(&UpdateEngineStatus::status, UpdateStatus::DOWNLOADING),
- Field(&UpdateEngineStatus::new_size_bytes, bytes_total))));
- attempter_.AddObserver(&observer);
- attempter_.BytesReceived(bytes_progressed_1, bytes_received_1, bytes_total);
- EXPECT_EQ(progress_1, attempter_.download_progress_);
- // This iteration validates that a later set of updates to the variables are
- // properly handled (so that |getStatus()| will return the same progress info
- // as the callback is receiving.
- attempter_.BytesReceived(bytes_progressed_2, bytes_received_2, bytes_total);
- EXPECT_EQ(progress_2, attempter_.download_progress_);
-}
-
-TEST_F(UpdateAttempterTest, ChangeToDownloadingOnReceivedBytesTest) {
- // The transition into |UpdateStatus::DOWNLOADING| happens when the
- // first bytes are received.
- uint64_t bytes_progressed = 1024 * 1024; // 1MB
- uint64_t bytes_received = 2 * 1024 * 1024; // 2MB
- uint64_t bytes_total = 20 * 1024 * 1024; // 300MB
- attempter_.status_ = UpdateStatus::CHECKING_FOR_UPDATE;
- // This is set via inspecting the InstallPlan payloads when the
- // |OmahaResponseAction| is completed.
- attempter_.new_payload_size_ = bytes_total;
- EXPECT_EQ(0.0, attempter_.download_progress_);
- NiceMock<MockServiceObserver> observer;
- EXPECT_CALL(observer,
- SendStatusUpdate(AllOf(
- Field(&UpdateEngineStatus::status, UpdateStatus::DOWNLOADING),
- Field(&UpdateEngineStatus::new_size_bytes, bytes_total))));
- attempter_.AddObserver(&observer);
- attempter_.BytesReceived(bytes_progressed, bytes_received, bytes_total);
- EXPECT_EQ(UpdateStatus::DOWNLOADING, attempter_.status_);
-}
-
-TEST_F(UpdateAttempterTest, BroadcastCompleteDownloadTest) {
- // There is a special case to ensure that at 100% downloaded,
- // |download_progress_| is updated and broadcastest.
- uint64_t bytes_progressed = 0; // ignored
- uint64_t bytes_received = 5 * 1024 * 1024; // ignored
- uint64_t bytes_total = 5 * 1024 * 1024; // 300MB
- attempter_.status_ = UpdateStatus::DOWNLOADING;
- attempter_.new_payload_size_ = bytes_total;
- EXPECT_EQ(0.0, attempter_.download_progress_);
- NiceMock<MockServiceObserver> observer;
- EXPECT_CALL(observer,
- SendStatusUpdate(AllOf(
- Field(&UpdateEngineStatus::progress, 1.0),
- Field(&UpdateEngineStatus::status, UpdateStatus::DOWNLOADING),
- Field(&UpdateEngineStatus::new_size_bytes, bytes_total))));
- attempter_.AddObserver(&observer);
- attempter_.BytesReceived(bytes_progressed, bytes_received, bytes_total);
- EXPECT_EQ(1.0, attempter_.download_progress_);
-}
-
-TEST_F(UpdateAttempterTest, ActionCompletedOmahaRequestTest) {
- unique_ptr<MockHttpFetcher> fetcher(new MockHttpFetcher("", 0, nullptr));
- fetcher->FailTransfer(500); // Sets the HTTP response code.
- OmahaRequestAction action(nullptr, std::move(fetcher), false, "");
- ObjectCollectorAction<OmahaResponse> collector_action;
- BondActions(&action, &collector_action);
- OmahaResponse response;
- response.poll_interval = 234;
- action.SetOutputObject(response);
- attempter_.ActionCompleted(nullptr, &action, ErrorCode::kSuccess);
- EXPECT_FALSE(prefs_->Exists(kPrefsDeltaUpdateFailures));
- EXPECT_EQ(500, attempter_.http_response_code());
- EXPECT_EQ(UpdateStatus::IDLE, attempter_.status());
- EXPECT_EQ(234U, attempter_.server_dictated_poll_interval_);
- ASSERT_TRUE(attempter_.error_event_.get() == nullptr);
-}
-
-TEST_F(UpdateAttempterTest, ConstructWithUpdatedMarkerTest) {
- string boot_id;
- EXPECT_TRUE(utils::GetBootId(&boot_id));
- FakeSystemState::Get()->fake_prefs()->SetString(kPrefsUpdateCompletedOnBootId,
- boot_id);
- attempter_.Init();
- EXPECT_EQ(UpdateStatus::UPDATED_NEED_REBOOT, attempter_.status());
-}
-
-TEST_F(UpdateAttempterTest, GetErrorCodeForActionTest) {
- EXPECT_EQ(ErrorCode::kSuccess,
- GetErrorCodeForAction(nullptr, ErrorCode::kSuccess));
-
- OmahaRequestAction omaha_request_action(nullptr, nullptr, false, "");
- EXPECT_EQ(ErrorCode::kOmahaRequestError,
- GetErrorCodeForAction(&omaha_request_action, ErrorCode::kError));
- OmahaResponseHandlerAction omaha_response_handler_action;
- EXPECT_EQ(
- ErrorCode::kOmahaResponseHandlerError,
- GetErrorCodeForAction(&omaha_response_handler_action, ErrorCode::kError));
- DynamicPartitionControlStub dynamic_control_stub;
- FilesystemVerifierAction filesystem_verifier_action(&dynamic_control_stub);
- EXPECT_EQ(
- ErrorCode::kFilesystemVerifierError,
- GetErrorCodeForAction(&filesystem_verifier_action, ErrorCode::kError));
- PostinstallRunnerAction postinstall_runner_action(
- FakeSystemState::Get()->fake_boot_control(),
- FakeSystemState::Get()->fake_hardware());
- EXPECT_EQ(
- ErrorCode::kPostinstallRunnerError,
- GetErrorCodeForAction(&postinstall_runner_action, ErrorCode::kError));
- MockAction action_mock;
- EXPECT_CALL(action_mock, Type()).WillOnce(Return("MockAction"));
- EXPECT_EQ(ErrorCode::kError,
- GetErrorCodeForAction(&action_mock, ErrorCode::kError));
-}
-
-TEST_F(UpdateAttempterTest, DisableDeltaUpdateIfNeededTest) {
- attempter_.omaha_request_params_->set_delta_okay(true);
- attempter_.DisableDeltaUpdateIfNeeded();
- EXPECT_TRUE(attempter_.omaha_request_params_->delta_okay());
- prefs_->SetInt64(kPrefsDeltaUpdateFailures,
- UpdateAttempter::kMaxDeltaUpdateFailures - 1);
- attempter_.DisableDeltaUpdateIfNeeded();
- EXPECT_TRUE(attempter_.omaha_request_params_->delta_okay());
- prefs_->SetInt64(kPrefsDeltaUpdateFailures,
- UpdateAttempter::kMaxDeltaUpdateFailures);
- attempter_.DisableDeltaUpdateIfNeeded();
- EXPECT_FALSE(attempter_.omaha_request_params_->delta_okay());
- attempter_.DisableDeltaUpdateIfNeeded();
- EXPECT_FALSE(attempter_.omaha_request_params_->delta_okay());
-}
-
-TEST_F(UpdateAttempterTest, MarkDeltaUpdateFailureTest) {
- attempter_.MarkDeltaUpdateFailure();
-
- EXPECT_TRUE(prefs_->SetInt64(kPrefsDeltaUpdateFailures, -1));
- attempter_.MarkDeltaUpdateFailure();
- int64_t value = 0;
- EXPECT_TRUE(prefs_->GetInt64(kPrefsDeltaUpdateFailures, &value));
- EXPECT_EQ(value, 1);
-
- attempter_.MarkDeltaUpdateFailure();
- EXPECT_TRUE(prefs_->GetInt64(kPrefsDeltaUpdateFailures, &value));
- EXPECT_EQ(value, 2);
-
- EXPECT_TRUE(prefs_->SetInt64(kPrefsDeltaUpdateFailures,
- UpdateAttempter::kMaxDeltaUpdateFailures));
- attempter_.MarkDeltaUpdateFailure();
- EXPECT_TRUE(prefs_->GetInt64(kPrefsDeltaUpdateFailures, &value));
- EXPECT_EQ(value, UpdateAttempter::kMaxDeltaUpdateFailures + 1);
-}
-
-TEST_F(UpdateAttempterTest, ScheduleErrorEventActionNoEventTest) {
- EXPECT_CALL(*processor_, EnqueueAction(_)).Times(0);
- EXPECT_CALL(*processor_, StartProcessing()).Times(0);
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(), UpdateFailed(_))
- .Times(0);
- OmahaResponse response;
- string url1 = "http://url1";
- response.packages.push_back({.payload_urls = {url1, "https://url"}});
- EXPECT_CALL(*(FakeSystemState::Get()->mock_payload_state()), GetCurrentUrl())
- .WillRepeatedly(Return(url1));
- FakeSystemState::Get()->mock_payload_state()->SetResponse(response);
- attempter_.ScheduleErrorEventAction();
- EXPECT_EQ(url1,
- FakeSystemState::Get()->mock_payload_state()->GetCurrentUrl());
-}
-
-TEST_F(UpdateAttempterTest, ScheduleErrorEventActionTest) {
- EXPECT_CALL(*processor_,
- EnqueueAction(Pointee(Property(
- &AbstractAction::Type, OmahaRequestAction::StaticType()))));
- EXPECT_CALL(*processor_, StartProcessing());
- ErrorCode err = ErrorCode::kError;
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(), UpdateFailed(err));
- attempter_.error_event_.reset(new OmahaEvent(
- OmahaEvent::kTypeUpdateComplete, OmahaEvent::kResultError, err));
- attempter_.ScheduleErrorEventAction();
- EXPECT_EQ(UpdateStatus::REPORTING_ERROR_EVENT, attempter_.status());
-}
-
-namespace {
-// Actions that will be built as part of an update check.
-vector<string> GetUpdateActionTypes() {
- return {OmahaRequestAction::StaticType(),
- OmahaResponseHandlerAction::StaticType(),
- UpdateBootFlagsAction::StaticType(),
- OmahaRequestAction::StaticType(),
- DownloadActionChromeos::StaticType(),
- OmahaRequestAction::StaticType(),
- FilesystemVerifierAction::StaticType(),
- PostinstallRunnerAction::StaticType(),
- OmahaRequestAction::StaticType()};
-}
-
-// Actions that will be built as part of a user-initiated rollback.
-vector<string> GetRollbackActionTypes() {
- return {InstallPlanAction::StaticType(),
- PostinstallRunnerAction::StaticType()};
-}
-
-const StagingSchedule kValidStagingSchedule = {
- {4, 10}, {10, 40}, {19, 70}, {26, 100}};
-
-} // namespace
-
-void UpdateAttempterTest::UpdateTestStart() {
- attempter_.set_http_response_code(200);
-
- // Expect that the device policy is loaded by the |UpdateAttempter| at some
- // point by calling |RefreshDevicePolicy()|.
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- EXPECT_CALL(*device_policy, LoadPolicy())
- .Times(testing::AtLeast(1))
- .WillRepeatedly(Return(true));
- attempter_.policy_provider_.reset(
- new policy::PolicyProvider(std::move(device_policy)));
-
- {
- InSequence s;
- for (const auto& update_action_type : GetUpdateActionTypes()) {
- EXPECT_CALL(*processor_,
- EnqueueAction(Pointee(
- Property(&AbstractAction::Type, update_action_type))));
- }
- EXPECT_CALL(*processor_, StartProcessing());
- }
-
- attempter_.Update({});
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::UpdateTestVerify,
- base::Unretained(this)));
-}
-
-void UpdateAttempterTest::UpdateTestVerify() {
- EXPECT_EQ(0, attempter_.http_response_code());
- EXPECT_EQ(&attempter_, processor_->delegate());
- EXPECT_EQ(UpdateStatus::CHECKING_FOR_UPDATE, attempter_.status());
- loop_.BreakLoop();
-}
-
-void UpdateAttempterTest::RollbackTestStart(bool enterprise_rollback,
- bool valid_slot) {
- // Create a device policy so that we can change settings.
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- EXPECT_CALL(*device_policy, LoadPolicy()).WillRepeatedly(Return(true));
- FakeSystemState::Get()->set_device_policy(device_policy.get());
- if (enterprise_rollback) {
- // We return an empty owner as this is an enterprise.
- EXPECT_CALL(*device_policy, GetOwner(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(string("")), Return(true)));
- } else {
- // We return a fake owner as this is an owned consumer device.
- EXPECT_CALL(*device_policy, GetOwner(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(string("fake.mail@fake.com")),
- Return(true)));
- }
-
- attempter_.policy_provider_.reset(
- new policy::PolicyProvider(std::move(device_policy)));
-
- if (valid_slot) {
- BootControlInterface::Slot rollback_slot = 1;
- LOG(INFO) << "Test Mark Bootable: "
- << BootControlInterface::SlotName(rollback_slot);
- FakeSystemState::Get()->fake_boot_control()->SetSlotBootable(rollback_slot,
- true);
- }
-
- bool is_rollback_allowed = false;
-
- // We only allow rollback on devices that are not enterprise enrolled and
- // which have a valid slot to rollback to.
- if (!enterprise_rollback && valid_slot) {
- is_rollback_allowed = true;
- }
-
- if (is_rollback_allowed) {
- InSequence s;
- for (const auto& rollback_action_type : GetRollbackActionTypes()) {
- EXPECT_CALL(*processor_,
- EnqueueAction(Pointee(
- Property(&AbstractAction::Type, rollback_action_type))));
- }
- EXPECT_CALL(*processor_, StartProcessing());
-
- EXPECT_TRUE(attempter_.Rollback(true));
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::RollbackTestVerify,
- base::Unretained(this)));
- } else {
- EXPECT_FALSE(attempter_.Rollback(true));
- loop_.BreakLoop();
- }
-}
-
-void UpdateAttempterTest::RollbackTestVerify() {
- // Verifies the actions that were enqueued.
- EXPECT_EQ(&attempter_, processor_->delegate());
- EXPECT_EQ(UpdateStatus::ATTEMPTING_ROLLBACK, attempter_.status());
- EXPECT_EQ(0U, attempter_.install_plan_->partitions.size());
- EXPECT_EQ(attempter_.install_plan_->powerwash_required, true);
- loop_.BreakLoop();
-}
-
-TEST_F(UpdateAttempterTest, UpdateTest) {
- UpdateTestStart();
- loop_.Run();
-}
-
-TEST_F(UpdateAttempterTest, RollbackTest) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::RollbackTestStart,
- base::Unretained(this),
- false,
- true));
- loop_.Run();
-}
-
-TEST_F(UpdateAttempterTest, InvalidSlotRollbackTest) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::RollbackTestStart,
- base::Unretained(this),
- false,
- false));
- loop_.Run();
-}
-
-TEST_F(UpdateAttempterTest, EnterpriseRollbackTest) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::RollbackTestStart,
- base::Unretained(this),
- true,
- true));
- loop_.Run();
-}
-
-void UpdateAttempterTest::PingOmahaTestStart() {
- EXPECT_CALL(*processor_,
- EnqueueAction(Pointee(Property(
- &AbstractAction::Type, OmahaRequestAction::StaticType()))));
- EXPECT_CALL(*processor_, StartProcessing());
- attempter_.PingOmaha();
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, PingOmahaTest) {
- EXPECT_FALSE(attempter_.waiting_for_scheduled_check_);
- EXPECT_FALSE(attempter_.WasScheduleUpdatesCalled());
- // Disable scheduling of subsequnet checks; we're using the |DefaultPolicy| in
- // testing, which is more permissive than we want to handle here.
- attempter_.DisableScheduleUpdates();
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::PingOmahaTestStart,
- base::Unretained(this)));
- brillo::MessageLoopRunMaxIterations(&loop_, 100);
- EXPECT_EQ(UpdateStatus::UPDATED_NEED_REBOOT, attempter_.status());
- EXPECT_TRUE(attempter_.WasScheduleUpdatesCalled());
-}
-
-TEST_F(UpdateAttempterTest, CreatePendingErrorEventTest) {
- MockAction action;
- const ErrorCode kCode = ErrorCode::kDownloadTransferError;
- attempter_.CreatePendingErrorEvent(&action, kCode);
- ASSERT_NE(nullptr, attempter_.error_event_.get());
- EXPECT_EQ(OmahaEvent::kTypeUpdateComplete, attempter_.error_event_->type);
- EXPECT_EQ(OmahaEvent::kResultError, attempter_.error_event_->result);
- EXPECT_EQ(
- static_cast<ErrorCode>(static_cast<int>(kCode) |
- static_cast<int>(ErrorCode::kTestOmahaUrlFlag)),
- attempter_.error_event_->error_code);
-}
-
-TEST_F(UpdateAttempterTest, CreatePendingErrorEventResumedTest) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_resume = true;
- MockAction action;
- const ErrorCode kCode = ErrorCode::kInstallDeviceOpenError;
- attempter_.CreatePendingErrorEvent(&action, kCode);
- ASSERT_NE(nullptr, attempter_.error_event_.get());
- EXPECT_EQ(OmahaEvent::kTypeUpdateComplete, attempter_.error_event_->type);
- EXPECT_EQ(OmahaEvent::kResultError, attempter_.error_event_->result);
- EXPECT_EQ(
- static_cast<ErrorCode>(static_cast<int>(kCode) |
- static_cast<int>(ErrorCode::kResumedFlag) |
- static_cast<int>(ErrorCode::kTestOmahaUrlFlag)),
- attempter_.error_event_->error_code);
-}
-
-TEST_F(UpdateAttempterTest, P2PNotStartedAtStartupWhenNotEnabled) {
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- mock_p2p_manager.fake().SetP2PEnabled(false);
- EXPECT_CALL(mock_p2p_manager, EnsureP2PRunning()).Times(0);
- attempter_.UpdateEngineStarted();
-}
-
-TEST_F(UpdateAttempterTest, P2PNotStartedAtStartupWhenEnabledButNotSharing) {
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- mock_p2p_manager.fake().SetP2PEnabled(true);
- EXPECT_CALL(mock_p2p_manager, EnsureP2PRunning()).Times(0);
- attempter_.UpdateEngineStarted();
-}
-
-TEST_F(UpdateAttempterTest, P2PStartedAtStartupWhenEnabledAndSharing) {
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- mock_p2p_manager.fake().SetP2PEnabled(true);
- mock_p2p_manager.fake().SetCountSharedFilesResult(1);
- EXPECT_CALL(mock_p2p_manager, EnsureP2PRunning());
- attempter_.UpdateEngineStarted();
-}
-
-TEST_F(UpdateAttempterTest, P2PNotEnabled) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::P2PNotEnabledStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::P2PNotEnabledStart() {
- // If P2P is not enabled, check that we do not attempt housekeeping
- // and do not convey that P2P is to be used.
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- mock_p2p_manager.fake().SetP2PEnabled(false);
- EXPECT_CALL(mock_p2p_manager, PerformHousekeeping()).Times(0);
- attempter_.Update({});
- EXPECT_FALSE(actual_using_p2p_for_downloading_);
- EXPECT_FALSE(actual_using_p2p_for_sharing());
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, P2PEnabledStartingFails) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::P2PEnabledStartingFailsStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::P2PEnabledStartingFailsStart() {
- // If P2P is enabled, but starting it fails ensure we don't do
- // any housekeeping and do not convey that P2P should be used.
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- mock_p2p_manager.fake().SetP2PEnabled(true);
- mock_p2p_manager.fake().SetEnsureP2PRunningResult(false);
- mock_p2p_manager.fake().SetPerformHousekeepingResult(false);
- EXPECT_CALL(mock_p2p_manager, PerformHousekeeping()).Times(0);
- attempter_.Update({});
- EXPECT_FALSE(actual_using_p2p_for_downloading());
- EXPECT_FALSE(actual_using_p2p_for_sharing());
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, P2PEnabledHousekeepingFails) {
- loop_.PostTask(
- FROM_HERE,
- base::Bind(&UpdateAttempterTest::P2PEnabledHousekeepingFailsStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::P2PEnabledHousekeepingFailsStart() {
- // If P2P is enabled, starting it works but housekeeping fails, ensure
- // we do not convey P2P is to be used.
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- mock_p2p_manager.fake().SetP2PEnabled(true);
- mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
- mock_p2p_manager.fake().SetPerformHousekeepingResult(false);
- EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update({});
- EXPECT_FALSE(actual_using_p2p_for_downloading());
- EXPECT_FALSE(actual_using_p2p_for_sharing());
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, P2PEnabled) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::P2PEnabledStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::P2PEnabledStart() {
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- // If P2P is enabled and starting it works, check that we performed
- // housekeeping and that we convey P2P should be used.
- mock_p2p_manager.fake().SetP2PEnabled(true);
- mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
- mock_p2p_manager.fake().SetPerformHousekeepingResult(true);
- EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update({});
- EXPECT_TRUE(actual_using_p2p_for_downloading());
- EXPECT_TRUE(actual_using_p2p_for_sharing());
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, P2PEnabledInteractive) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::P2PEnabledInteractiveStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::P2PEnabledInteractiveStart() {
- MockP2PManager mock_p2p_manager;
- FakeSystemState::Get()->set_p2p_manager(&mock_p2p_manager);
- // For an interactive check, if P2P is enabled and starting it
- // works, check that we performed housekeeping and that we convey
- // P2P should be used for sharing but NOT for downloading.
- mock_p2p_manager.fake().SetP2PEnabled(true);
- mock_p2p_manager.fake().SetEnsureP2PRunningResult(true);
- mock_p2p_manager.fake().SetPerformHousekeepingResult(true);
- EXPECT_CALL(mock_p2p_manager, PerformHousekeeping());
- attempter_.Update({.interactive = true});
- EXPECT_FALSE(actual_using_p2p_for_downloading());
- EXPECT_TRUE(actual_using_p2p_for_sharing());
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, ReadScatterFactorFromPolicy) {
- loop_.PostTask(
- FROM_HERE,
- base::Bind(&UpdateAttempterTest::ReadScatterFactorFromPolicyTestStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-// Tests that the scatter_factor_in_seconds value is properly fetched
-// from the device policy.
-void UpdateAttempterTest::ReadScatterFactorFromPolicyTestStart() {
- int64_t scatter_factor_in_seconds = 36000;
-
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- EXPECT_CALL(*device_policy, LoadPolicy()).WillRepeatedly(Return(true));
- FakeSystemState::Get()->set_device_policy(device_policy.get());
-
- EXPECT_CALL(*device_policy, GetScatterFactorInSeconds(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(scatter_factor_in_seconds), Return(true)));
-
- attempter_.policy_provider_.reset(
- new policy::PolicyProvider(std::move(device_policy)));
-
- attempter_.Update({});
- EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
-
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, DecrementUpdateCheckCountTest) {
- loop_.PostTask(
- FROM_HERE,
- base::Bind(&UpdateAttempterTest::DecrementUpdateCheckCountTestStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::DecrementUpdateCheckCountTestStart() {
- // Tests that the scatter_factor_in_seconds value is properly fetched
- // from the device policy and is decremented if value > 0.
- int64_t initial_value = 5;
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(Time::UnixEpoch());
-
- EXPECT_TRUE(fake_prefs->SetInt64(kPrefsUpdateCheckCount, initial_value));
-
- int64_t scatter_factor_in_seconds = 10;
-
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- EXPECT_CALL(*device_policy, LoadPolicy()).WillRepeatedly(Return(true));
- FakeSystemState::Get()->set_device_policy(device_policy.get());
-
- EXPECT_CALL(*device_policy, GetScatterFactorInSeconds(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(scatter_factor_in_seconds), Return(true)));
-
- attempter_.policy_provider_.reset(
- new policy::PolicyProvider(std::move(device_policy)));
-
- attempter_.Update({});
- EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
-
- // Make sure the file still exists.
- EXPECT_TRUE(fake_prefs->Exists(kPrefsUpdateCheckCount));
-
- int64_t new_value;
- EXPECT_TRUE(fake_prefs->GetInt64(kPrefsUpdateCheckCount, &new_value));
- EXPECT_EQ(initial_value - 1, new_value);
-
- EXPECT_TRUE(
- attempter_.omaha_request_params_->update_check_count_wait_enabled());
-
- // 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({});
- EXPECT_TRUE(fake_prefs->Exists(kPrefsUpdateCheckCount));
- EXPECT_TRUE(fake_prefs->GetInt64(kPrefsUpdateCheckCount, &new_value));
- EXPECT_EQ(initial_value, new_value);
-
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, NoScatteringDoneDuringManualUpdateTestStart) {
- loop_.PostTask(
- FROM_HERE,
- base::Bind(
- &UpdateAttempterTest::NoScatteringDoneDuringManualUpdateTestStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::NoScatteringDoneDuringManualUpdateTestStart() {
- // Tests that no scattering logic is enabled if the update check
- // is manually done (as opposed to a scheduled update check)
- int64_t initial_value = 8;
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(Time::UnixEpoch());
-
- EXPECT_TRUE(
- fake_prefs->SetInt64(kPrefsWallClockScatteringWaitPeriod, initial_value));
- EXPECT_TRUE(fake_prefs->SetInt64(kPrefsUpdateCheckCount, initial_value));
-
- // make sure scatter_factor is non-zero as scattering is disabled
- // otherwise.
- int64_t scatter_factor_in_seconds = 50;
-
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- EXPECT_CALL(*device_policy, LoadPolicy()).WillRepeatedly(Return(true));
- FakeSystemState::Get()->set_device_policy(device_policy.get());
-
- EXPECT_CALL(*device_policy, GetScatterFactorInSeconds(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(scatter_factor_in_seconds), Return(true)));
-
- attempter_.policy_provider_.reset(
- new policy::PolicyProvider(std::move(device_policy)));
-
- // Trigger an interactive check so we can test that scattering is disabled.
- attempter_.Update({.interactive = true});
- EXPECT_EQ(scatter_factor_in_seconds, attempter_.scatter_factor_.InSeconds());
-
- // Make sure scattering is disabled for manual (i.e. user initiated) update
- // checks and all artifacts are removed.
- EXPECT_FALSE(
- attempter_.omaha_request_params_->wall_clock_based_wait_enabled());
- EXPECT_FALSE(fake_prefs->Exists(kPrefsWallClockScatteringWaitPeriod));
- EXPECT_EQ(0, attempter_.omaha_request_params_->waiting_period().InSeconds());
- EXPECT_FALSE(
- attempter_.omaha_request_params_->update_check_count_wait_enabled());
- EXPECT_FALSE(fake_prefs->Exists(kPrefsUpdateCheckCount));
-
- ScheduleQuitMainLoop();
-}
-
-void UpdateAttempterTest::SetUpStagingTest(const StagingSchedule& schedule) {
- int64_t initial_value = 8;
- EXPECT_TRUE(
- prefs_->SetInt64(kPrefsWallClockScatteringWaitPeriod, initial_value));
- EXPECT_TRUE(prefs_->SetInt64(kPrefsUpdateCheckCount, initial_value));
- attempter_.scatter_factor_ = TimeDelta::FromSeconds(20);
-
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- EXPECT_CALL(*device_policy, LoadPolicy()).WillRepeatedly(Return(true));
- FakeSystemState::Get()->set_device_policy(device_policy.get());
- EXPECT_CALL(*device_policy, GetDeviceUpdateStagingSchedule(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(schedule), Return(true)));
-
- attempter_.policy_provider_.reset(
- new policy::PolicyProvider(std::move(device_policy)));
-}
-
-TEST_F(UpdateAttempterTest, StagingSetsPrefsAndTurnsOffScattering) {
- loop_.PostTask(
- FROM_HERE,
- base::Bind(
- &UpdateAttempterTest::StagingSetsPrefsAndTurnsOffScatteringStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::StagingSetsPrefsAndTurnsOffScatteringStart() {
- // Tests that staging sets its prefs properly and turns off scattering.
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(Time::UnixEpoch());
- SetUpStagingTest(kValidStagingSchedule);
-
- attempter_.Update({});
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- // Check that prefs have the correct values.
- int64_t update_count;
- EXPECT_TRUE(fake_prefs->GetInt64(kPrefsUpdateCheckCount, &update_count));
- int64_t waiting_time_days;
- EXPECT_TRUE(fake_prefs->GetInt64(kPrefsWallClockStagingWaitPeriod,
- &waiting_time_days));
- EXPECT_GT(waiting_time_days, 0);
- // Update count should have been decremented.
- EXPECT_EQ(7, update_count);
- // Check that Omaha parameters were updated correctly.
- EXPECT_TRUE(
- attempter_.omaha_request_params_->update_check_count_wait_enabled());
- EXPECT_TRUE(
- attempter_.omaha_request_params_->wall_clock_based_wait_enabled());
- EXPECT_EQ(waiting_time_days,
- attempter_.omaha_request_params_->waiting_period().InDays());
- // Check class variables.
- EXPECT_EQ(waiting_time_days, attempter_.staging_wait_time_.InDays());
- EXPECT_EQ(kValidStagingSchedule, attempter_.staging_schedule_);
- // Check that scattering is turned off
- EXPECT_EQ(0, attempter_.scatter_factor_.InSeconds());
- EXPECT_FALSE(fake_prefs->Exists(kPrefsWallClockScatteringWaitPeriod));
-
- ScheduleQuitMainLoop();
-}
-
-void UpdateAttempterTest::CheckStagingOff() {
- // Check that all prefs were removed.
- EXPECT_FALSE(prefs_->Exists(kPrefsUpdateCheckCount));
- EXPECT_FALSE(prefs_->Exists(kPrefsWallClockScatteringWaitPeriod));
- EXPECT_FALSE(prefs_->Exists(kPrefsWallClockStagingWaitPeriod));
- // Check that the Omaha parameters have the correct value.
- EXPECT_EQ(0, attempter_.omaha_request_params_->waiting_period().InDays());
- EXPECT_EQ(attempter_.omaha_request_params_->waiting_period(),
- attempter_.staging_wait_time_);
- EXPECT_FALSE(
- attempter_.omaha_request_params_->update_check_count_wait_enabled());
- EXPECT_FALSE(
- attempter_.omaha_request_params_->wall_clock_based_wait_enabled());
- // Check that scattering is turned off too.
- EXPECT_EQ(0, attempter_.scatter_factor_.InSeconds());
-}
-
-TEST_F(UpdateAttempterTest, StagingOffIfInteractive) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::StagingOffIfInteractiveStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::StagingOffIfInteractiveStart() {
- // Tests that staging is turned off when an interactive update is requested.
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(Time::UnixEpoch());
- SetUpStagingTest(kValidStagingSchedule);
-
- attempter_.Update({.interactive = true});
- CheckStagingOff();
-
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, StagingOffIfOobe) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::StagingOffIfOobeStart,
- base::Unretained(this)));
- loop_.Run();
-}
-
-void UpdateAttempterTest::StagingOffIfOobeStart() {
- // Tests that staging is turned off if OOBE hasn't been completed.
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEEnabled(true);
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- SetUpStagingTest(kValidStagingSchedule);
-
- attempter_.Update({.interactive = true});
- CheckStagingOff();
-
- ScheduleQuitMainLoop();
-}
-
-// Checks that we only report daily metrics at most every 24 hours.
-TEST_F(UpdateAttempterTest, ReportDailyMetrics) {
- auto* fake_clock = FakeSystemState::Get()->fake_clock();
- Time epoch = Time::FromInternalValue(0);
- fake_clock->SetWallclockTime(epoch);
-
- // If there is no kPrefsDailyMetricsLastReportedAt state variable,
- // we should report.
- EXPECT_TRUE(attempter_.CheckAndReportDailyMetrics());
- // We should not report again if no time has passed.
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-
- // We should not report if only 10 hours has passed.
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(10));
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-
- // We should not report if only 24 hours - 1 sec has passed.
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(24) -
- TimeDelta::FromSeconds(1));
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-
- // We should report if 24 hours has passed.
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(24));
- EXPECT_TRUE(attempter_.CheckAndReportDailyMetrics());
-
- // But then we should not report again..
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-
- // .. until another 24 hours has passed
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(47));
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(48));
- EXPECT_TRUE(attempter_.CheckAndReportDailyMetrics());
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-
- // .. and another 24 hours
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(71));
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(72));
- EXPECT_TRUE(attempter_.CheckAndReportDailyMetrics());
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-
- // If the span between time of reporting and present time is
- // negative, we report. This is in order to reset the timestamp and
- // avoid an edge condition whereby a distant point in the future is
- // in the state variable resulting in us never ever reporting again.
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(71));
- EXPECT_TRUE(attempter_.CheckAndReportDailyMetrics());
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-
- // In this case we should not update until the clock reads 71 + 24 = 95.
- // Check that.
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(94));
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
- fake_clock->SetWallclockTime(epoch + TimeDelta::FromHours(95));
- EXPECT_TRUE(attempter_.CheckAndReportDailyMetrics());
- EXPECT_FALSE(attempter_.CheckAndReportDailyMetrics());
-}
-
-TEST_F(UpdateAttempterTest, BootTimeInUpdateMarkerFile) {
- FakeSystemState::Get()->fake_clock()->SetBootTime(Time::FromTimeT(42));
- attempter_.Init();
-
- Time boot_time;
- EXPECT_FALSE(attempter_.GetBootTimeAtUpdate(&boot_time));
-
- attempter_.WriteUpdateCompletedMarker();
-
- EXPECT_TRUE(attempter_.GetBootTimeAtUpdate(&boot_time));
- EXPECT_EQ(boot_time.ToTimeT(), 42);
-}
-
-TEST_F(UpdateAttempterTest, AnyUpdateSourceAllowedUnofficial) {
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(false);
- EXPECT_TRUE(attempter_.IsAnyUpdateSourceAllowed());
-}
-
-TEST_F(UpdateAttempterTest, AnyUpdateSourceAllowedOfficialDevmode) {
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(true);
- FakeSystemState::Get()->fake_hardware()->SetAreDevFeaturesEnabled(true);
- EXPECT_TRUE(attempter_.IsAnyUpdateSourceAllowed());
-}
-
-TEST_F(UpdateAttempterTest, AnyUpdateSourceDisallowedOfficialNormal) {
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(true);
- FakeSystemState::Get()->fake_hardware()->SetAreDevFeaturesEnabled(false);
- EXPECT_FALSE(attempter_.IsAnyUpdateSourceAllowed());
-}
-
-// TODO(kimjae): Follow testing pattern with params for |CheckForInstall()|.
-// When adding, remove older tests related to |CheckForInstall()|.
-TEST_F(UpdateAttempterTest, CheckForInstallNotIdleFails) {
- for (const auto status : kNonIdleUpdateStatuses) {
- // GIVEN a non-idle status.
- attempter_.status_ = status;
-
- EXPECT_FALSE(attempter_.CheckForInstall({}, ""));
- }
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateNotIdleFails) {
- for (const auto status : kNonIdleUpdateStatuses) {
- // GIVEN a non-idle status.
- cfu_params_.status = status;
-
- // THEN |ScheduleUpdates()| should not be called.
- cfu_params_.should_schedule_updates_be_called = false;
- // THEN result should indicate failure.
- cfu_params_.expected_result = false;
-
- TestCheckForUpdate();
- }
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateOfficalBuildClearsSource) {
- // GIVEN a official build.
-
- // THEN we except forced app version + forced omaha url to be cleared.
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateUnofficialBuildChangesSource) {
- // GIVEN a nonofficial build with dev features enabled.
- cfu_params_.is_official_build = false;
- cfu_params_.are_dev_features_enabled = true;
-
- // THEN the forced app version + forced omaha url changes based on input.
- cfu_params_.expected_forced_app_version = cfu_params_.app_version;
- cfu_params_.expected_forced_omaha_url = cfu_params_.omaha_url;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateOfficialBuildScheduledAUTest) {
- // GIVEN a scheduled autest omaha url.
- cfu_params_.omaha_url = "autest-scheduled";
-
- // THEN forced app version is cleared.
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateUnofficialBuildScheduledAUTest) {
- // GIVEN a scheduled autest omaha url.
- cfu_params_.omaha_url = "autest-scheduled";
- // GIVEN a nonofficial build with dev features enabled.
- cfu_params_.is_official_build = false;
- cfu_params_.are_dev_features_enabled = true;
-
- // THEN forced app version changes based on input.
- cfu_params_.expected_forced_app_version = cfu_params_.app_version;
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateOfficialBuildAUTest) {
- // GIVEN a autest omaha url.
- cfu_params_.omaha_url = "autest";
-
- // THEN forced app version is cleared.
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateUnofficialBuildAUTest) {
- // GIVEN a autest omha url.
- cfu_params_.omaha_url = "autest";
- // GIVEN a nonofficial build with dev features enabled.
- cfu_params_.is_official_build = false;
- cfu_params_.are_dev_features_enabled = true;
-
- // THEN forced app version changes based on input.
- cfu_params_.expected_forced_app_version = cfu_params_.app_version;
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest,
- CheckForUpdateNonInteractiveOfficialBuildScheduledAUTest) {
- // GIVEN a scheduled autest omaha url.
- cfu_params_.omaha_url = "autest-scheduled";
- // GIVEN a noninteractive update.
- cfu_params_.flags = UpdateAttemptFlags::kFlagNonInteractive;
-
- // THEN forced app version is cleared.
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest,
- CheckForUpdateNonInteractiveUnofficialBuildScheduledAUTest) {
- // GIVEN a scheduled autest omaha url.
- cfu_params_.omaha_url = "autest-scheduled";
- // GIVEN a noninteractive update.
- cfu_params_.flags = UpdateAttemptFlags::kFlagNonInteractive;
- // GIVEN a nonofficial build with dev features enabled.
- cfu_params_.is_official_build = false;
- cfu_params_.are_dev_features_enabled = true;
-
- // THEN forced app version changes based on input.
- cfu_params_.expected_forced_app_version = cfu_params_.app_version;
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateNonInteractiveOfficialBuildAUTest) {
- // GIVEN a autest omaha url.
- cfu_params_.omaha_url = "autest";
- // GIVEN a noninteractive update.
- cfu_params_.flags = UpdateAttemptFlags::kFlagNonInteractive;
-
- // THEN forced app version is cleared.
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateNonInteractiveUnofficialBuildAUTest) {
- // GIVEN a autest omaha url.
- cfu_params_.omaha_url = "autest";
- // GIVEN a noninteractive update.
- cfu_params_.flags = UpdateAttemptFlags::kFlagNonInteractive;
- // GIVEN a nonofficial build with dev features enabled.
- cfu_params_.is_official_build = false;
- cfu_params_.are_dev_features_enabled = true;
-
- // THEN forced app version changes based on input.
- cfu_params_.expected_forced_app_version = cfu_params_.app_version;
- // THEN forced omaha url changes to default constant.
- cfu_params_.expected_forced_omaha_url = constants::kOmahaDefaultAUTestURL;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateMissingForcedCallback1) {
- // GIVEN a official build.
- // GIVEN forced callback is not set.
- attempter_.set_forced_update_pending_callback(nullptr);
-
- // THEN we except forced app version + forced omaha url to be cleared.
- // THEN |ScheduleUpdates()| should not be called.
- cfu_params_.should_schedule_updates_be_called = false;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForUpdateMissingForcedCallback2) {
- // GIVEN a nonofficial build with dev features enabled.
- cfu_params_.is_official_build = false;
- cfu_params_.are_dev_features_enabled = true;
- // GIVEN forced callback is not set.
- attempter_.set_forced_update_pending_callback(nullptr);
-
- // THEN the forced app version + forced omaha url changes based on input.
- cfu_params_.expected_forced_app_version = cfu_params_.app_version;
- cfu_params_.expected_forced_omaha_url = cfu_params_.omaha_url;
- // THEN |ScheduleUpdates()| should not be called.
- cfu_params_.should_schedule_updates_be_called = false;
-
- TestCheckForUpdate();
-}
-
-TEST_F(UpdateAttempterTest, CheckForInstallTest) {
- FakeSystemState::Get()->fake_hardware()->SetIsOfficialBuild(true);
- FakeSystemState::Get()->fake_hardware()->SetAreDevFeaturesEnabled(false);
- attempter_.CheckForInstall({}, "autest");
- EXPECT_EQ(constants::kOmahaDefaultAUTestURL, attempter_.forced_omaha_url());
-
- attempter_.CheckForInstall({}, "autest-scheduled");
- EXPECT_EQ(constants::kOmahaDefaultAUTestURL, attempter_.forced_omaha_url());
-
- attempter_.CheckForInstall({}, "http://omaha.phishing");
- EXPECT_EQ("", attempter_.forced_omaha_url());
-}
-
-TEST_F(UpdateAttempterTest, InstallSetsStatusIdle) {
- attempter_.CheckForInstall({}, "http://foo.bar");
- attempter_.status_ = UpdateStatus::DOWNLOADING;
- EXPECT_TRUE(attempter_.is_install_);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- // Should set status to idle after an install operation.
- EXPECT_EQ(UpdateStatus::IDLE, status.status);
-}
-
-TEST_F(UpdateAttempterTest, RollbackAfterInstall) {
- attempter_.is_install_ = true;
- attempter_.Rollback(false);
- EXPECT_FALSE(attempter_.is_install_);
-}
-
-TEST_F(UpdateAttempterTest, UpdateAfterInstall) {
- attempter_.is_install_ = true;
- attempter_.CheckForUpdate("", "", UpdateAttemptFlags::kNone);
- EXPECT_FALSE(attempter_.is_install_);
-}
-
-TEST_F(UpdateAttempterTest, TargetVersionPrefixSetAndReset) {
- UpdateCheckParams params;
- attempter_.CalculateUpdateParams({.target_version_prefix = "1234"});
- EXPECT_EQ("1234",
- FakeSystemState::Get()->request_params()->target_version_prefix());
-
- attempter_.CalculateUpdateParams({});
- EXPECT_TRUE(FakeSystemState::Get()
- ->request_params()
- ->target_version_prefix()
- .empty());
-}
-
-TEST_F(UpdateAttempterTest, TargetChannelHintSetAndReset) {
- attempter_.CalculateUpdateParams({.lts_tag = "hint"});
- EXPECT_EQ("hint", FakeSystemState::Get()->request_params()->lts_tag());
-
- attempter_.CalculateUpdateParams({});
- EXPECT_TRUE(FakeSystemState::Get()->request_params()->lts_tag().empty());
-}
-
-TEST_F(UpdateAttempterTest, RollbackAllowedSetAndReset) {
- attempter_.CalculateUpdateParams({
- .target_version_prefix = "1234",
- .rollback_allowed = true,
- .rollback_allowed_milestones = 4,
- });
- EXPECT_TRUE(FakeSystemState::Get()->request_params()->rollback_allowed());
- EXPECT_EQ(
- 4,
- FakeSystemState::Get()->request_params()->rollback_allowed_milestones());
-
- attempter_.CalculateUpdateParams({
- .target_version_prefix = "1234",
- .rollback_allowed_milestones = 4,
- });
- EXPECT_FALSE(FakeSystemState::Get()->request_params()->rollback_allowed());
- EXPECT_EQ(
- 4,
- FakeSystemState::Get()->request_params()->rollback_allowed_milestones());
-}
-
-TEST_F(UpdateAttempterTest, ChannelDowngradeNoRollback) {
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
- FakeSystemState::Get()->request_params()->set_root(tempdir.GetPath().value());
- attempter_.CalculateUpdateParams({
- .target_channel = "stable-channel",
- });
- EXPECT_FALSE(
- FakeSystemState::Get()->request_params()->is_powerwash_allowed());
-}
-
-TEST_F(UpdateAttempterTest, ChannelDowngradeRollback) {
- base::ScopedTempDir tempdir;
- ASSERT_TRUE(tempdir.CreateUniqueTempDir());
- FakeSystemState::Get()->request_params()->set_root(tempdir.GetPath().value());
- attempter_.CalculateUpdateParams({
- .rollback_on_channel_downgrade = true,
- .target_channel = "stable-channel",
- });
- EXPECT_TRUE(FakeSystemState::Get()->request_params()->is_powerwash_allowed());
-}
-
-TEST_F(UpdateAttempterTest, UpdateDeferredByPolicyTest) {
- // Construct an OmahaResponseHandlerAction that has processed an InstallPlan,
- // but the update is being deferred by the Policy.
- OmahaResponseHandlerAction response_action;
- response_action.install_plan_.version = "a.b.c.d";
- response_action.install_plan_.payloads.push_back(
- {.size = 1234ULL, .type = InstallPayloadType::kFull});
- // Inform the UpdateAttempter that the OmahaResponseHandlerAction has
- // completed, with the deferred-update error code.
- attempter_.ActionCompleted(
- nullptr, &response_action, ErrorCode::kOmahaUpdateDeferredPerPolicy);
- {
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_EQ(UpdateStatus::UPDATE_AVAILABLE, status.status);
- EXPECT_TRUE(attempter_.install_plan_);
- EXPECT_EQ(attempter_.install_plan_->version, status.new_version);
- EXPECT_EQ(attempter_.install_plan_->payloads[0].size,
- status.new_size_bytes);
- }
- // An "error" event should have been created to tell Omaha that the update is
- // being deferred.
- EXPECT_TRUE(nullptr != attempter_.error_event_);
- EXPECT_EQ(OmahaEvent::kTypeUpdateComplete, attempter_.error_event_->type);
- EXPECT_EQ(OmahaEvent::kResultUpdateDeferred, attempter_.error_event_->result);
- ErrorCode expected_code = static_cast<ErrorCode>(
- static_cast<int>(ErrorCode::kOmahaUpdateDeferredPerPolicy) |
- static_cast<int>(ErrorCode::kTestOmahaUrlFlag));
- EXPECT_EQ(expected_code, attempter_.error_event_->error_code);
- // End the processing
- attempter_.ProcessingDone(nullptr, ErrorCode::kOmahaUpdateDeferredPerPolicy);
- // Validate the state of the attempter.
- {
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_EQ(UpdateStatus::REPORTING_ERROR_EVENT, status.status);
- EXPECT_EQ(response_action.install_plan_.version, status.new_version);
- EXPECT_EQ(response_action.install_plan_.payloads[0].size,
- status.new_size_bytes);
- }
-}
-
-TEST_F(UpdateAttempterTest, UpdateIsNotRunningWhenUpdateAvailable) {
- // Default construction for |waiting_for_scheduled_check_| is false.
- EXPECT_FALSE(attempter_.IsBusyOrUpdateScheduled());
- // Verify in-progress update with UPDATE_AVAILABLE is running
- attempter_.status_ = UpdateStatus::UPDATE_AVAILABLE;
- EXPECT_TRUE(attempter_.IsBusyOrUpdateScheduled());
-}
-
-TEST_F(UpdateAttempterTest, UpdateAttemptFlagsCachedAtUpdateStart) {
- attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kFlagRestrictDownload);
-
- UpdateCheckParams params = {.updates_enabled = true};
- attempter_.OnUpdateScheduled(EvalStatus::kSucceeded, params);
-
- EXPECT_EQ(UpdateAttemptFlags::kFlagRestrictDownload,
- attempter_.GetCurrentUpdateAttemptFlags());
-}
-
-TEST_F(UpdateAttempterTest, RollbackNotAllowed) {
- UpdateCheckParams params = {.updates_enabled = true,
- .rollback_allowed = false};
- attempter_.OnUpdateScheduled(EvalStatus::kSucceeded, params);
- EXPECT_FALSE(FakeSystemState::Get()->request_params()->rollback_allowed());
-}
-
-TEST_F(UpdateAttempterTest, RollbackAllowed) {
- UpdateCheckParams params = {.updates_enabled = true,
- .rollback_allowed = true};
- attempter_.OnUpdateScheduled(EvalStatus::kSucceeded, params);
- EXPECT_TRUE(FakeSystemState::Get()->request_params()->rollback_allowed());
-}
-
-TEST_F(UpdateAttempterTest, InteractiveUpdateUsesPassedRestrictions) {
- attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kFlagRestrictDownload);
-
- attempter_.CheckForUpdate("", "", UpdateAttemptFlags::kNone);
- EXPECT_EQ(UpdateAttemptFlags::kNone,
- attempter_.GetCurrentUpdateAttemptFlags());
-}
-
-TEST_F(UpdateAttempterTest, NonInteractiveUpdateUsesSetRestrictions) {
- attempter_.SetUpdateAttemptFlags(UpdateAttemptFlags::kNone);
-
- // This tests that when CheckForUpdate() is called with the non-interactive
- // flag set, that it doesn't change the current UpdateAttemptFlags.
- attempter_.CheckForUpdate("",
- "",
- UpdateAttemptFlags::kFlagNonInteractive |
- UpdateAttemptFlags::kFlagRestrictDownload);
- EXPECT_EQ(UpdateAttemptFlags::kNone,
- attempter_.GetCurrentUpdateAttemptFlags());
-}
-
-void UpdateAttempterTest::ResetRollbackHappenedStart(bool is_consumer,
- bool is_policy_loaded,
- bool expected_reset) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- GetRollbackHappened())
- .WillRepeatedly(Return(true));
- auto mock_policy_provider =
- std::make_unique<NiceMock<policy::MockPolicyProvider>>();
- EXPECT_CALL(*mock_policy_provider, IsConsumerDevice())
- .WillRepeatedly(Return(is_consumer));
- EXPECT_CALL(*mock_policy_provider, device_policy_is_loaded())
- .WillRepeatedly(Return(is_policy_loaded));
- const policy::MockDevicePolicy device_policy;
- EXPECT_CALL(*mock_policy_provider, GetDevicePolicy())
- .WillRepeatedly(ReturnRef(device_policy));
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- SetRollbackHappened(false))
- .Times(expected_reset ? 1 : 0);
- attempter_.policy_provider_ = std::move(mock_policy_provider);
- attempter_.Update({});
- ScheduleQuitMainLoop();
-}
-
-TEST_F(UpdateAttempterTest, ResetRollbackHappenedOobe) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
- base::Unretained(this),
- /*is_consumer=*/false,
- /*is_policy_loaded=*/false,
- /*expected_reset=*/false));
- loop_.Run();
-}
-
-TEST_F(UpdateAttempterTest, ResetRollbackHappenedConsumer) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
- base::Unretained(this),
- /*is_consumer=*/true,
- /*is_policy_loaded=*/false,
- /*expected_reset=*/true));
- loop_.Run();
-}
-
-TEST_F(UpdateAttempterTest, ResetRollbackHappenedEnterprise) {
- loop_.PostTask(FROM_HERE,
- base::Bind(&UpdateAttempterTest::ResetRollbackHappenedStart,
- base::Unretained(this),
- /*is_consumer=*/false,
- /*is_policy_loaded=*/true,
- /*expected_reset=*/true));
- loop_.Run();
-}
-
-TEST_F(UpdateAttempterTest, SetRollbackHappenedRollback) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = true;
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- SetRollbackHappened(true))
- .Times(1);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
-}
-
-TEST_F(UpdateAttempterTest, SetRollbackHappenedNotRollback) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = false;
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_payload_state(),
- SetRollbackHappened(true))
- .Times(0);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
-}
-
-TEST_F(UpdateAttempterTest, RollbackMetricsRollbackSuccess) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = true;
- attempter_.install_plan_->version = kRollbackVersion;
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseRollbackMetrics(true, kRollbackVersion))
- .Times(1);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
-}
-
-TEST_F(UpdateAttempterTest, RollbackMetricsNotRollbackSuccess) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = false;
- attempter_.install_plan_->version = kRollbackVersion;
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseRollbackMetrics(_, _))
- .Times(0);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
-}
-
-TEST_F(UpdateAttempterTest, RollbackMetricsRollbackFailure) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = true;
- attempter_.install_plan_->version = kRollbackVersion;
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseRollbackMetrics(false, kRollbackVersion))
- .Times(1);
- MockAction action;
- attempter_.CreatePendingErrorEvent(&action, ErrorCode::kRollbackNotPossible);
- attempter_.ProcessingDone(nullptr, ErrorCode::kRollbackNotPossible);
-}
-
-TEST_F(UpdateAttempterTest, RollbackMetricsNotRollbackFailure) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = false;
- attempter_.install_plan_->version = kRollbackVersion;
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseRollbackMetrics(_, _))
- .Times(0);
- MockAction action;
- attempter_.CreatePendingErrorEvent(&action, ErrorCode::kRollbackNotPossible);
- attempter_.ProcessingDone(nullptr, ErrorCode::kRollbackNotPossible);
-}
-
-TEST_F(UpdateAttempterTest, TimeToUpdateAppliedMetricFailure) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseUpdateSeenToDownloadDays(_, _))
- .Times(0);
- attempter_.ProcessingDone(nullptr, ErrorCode::kOmahaUpdateDeferredPerPolicy);
-}
-
-TEST_F(UpdateAttempterTest, TimeToUpdateAppliedOnNonEnterprise) {
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- FakeSystemState::Get()->set_device_policy(device_policy.get());
- // Make device policy return that this is not enterprise enrolled
- EXPECT_CALL(*device_policy, IsEnterpriseEnrolled()).WillOnce(Return(false));
-
- // Ensure that the metric is not recorded.
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseUpdateSeenToDownloadDays(_, _))
- .Times(0);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
-}
-
-TEST_F(UpdateAttempterTest,
- TimeToUpdateAppliedWithTimeRestrictionMetricSuccess) {
- constexpr int kDaysToUpdate = 15;
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- FakeSystemState::Get()->set_device_policy(device_policy.get());
- // Make device policy return that this is enterprise enrolled
- EXPECT_CALL(*device_policy, IsEnterpriseEnrolled()).WillOnce(Return(true));
- // Pretend that there's a time restriction policy in place
- EXPECT_CALL(*device_policy, GetDisallowedTimeIntervals(_))
- .WillOnce(Return(true));
-
- Time update_first_seen_at = Time::Now();
- FakeSystemState::Get()->fake_prefs()->SetInt64(
- kPrefsUpdateFirstSeenAt, update_first_seen_at.ToInternalValue());
-
- Time update_finished_at =
- update_first_seen_at + TimeDelta::FromDays(kDaysToUpdate);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(update_finished_at);
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseUpdateSeenToDownloadDays(true, kDaysToUpdate))
- .Times(1);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
-}
-
-TEST_F(UpdateAttempterTest,
- TimeToUpdateAppliedWithoutTimeRestrictionMetricSuccess) {
- constexpr int kDaysToUpdate = 15;
- auto device_policy = std::make_unique<policy::MockDevicePolicy>();
- FakeSystemState::Get()->set_device_policy(device_policy.get());
- // Make device policy return that this is enterprise enrolled
- EXPECT_CALL(*device_policy, IsEnterpriseEnrolled()).WillOnce(Return(true));
- // Pretend that there's no time restriction policy in place
- EXPECT_CALL(*device_policy, GetDisallowedTimeIntervals(_))
- .WillOnce(Return(false));
-
- Time update_first_seen_at = Time::Now();
- FakeSystemState::Get()->fake_prefs()->SetInt64(
- kPrefsUpdateFirstSeenAt, update_first_seen_at.ToInternalValue());
-
- Time update_finished_at =
- update_first_seen_at + TimeDelta::FromDays(kDaysToUpdate);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(update_finished_at);
-
- EXPECT_CALL(*FakeSystemState::Get()->mock_metrics_reporter(),
- ReportEnterpriseUpdateSeenToDownloadDays(false, kDaysToUpdate))
- .Times(1);
- attempter_.ProcessingDone(nullptr, ErrorCode::kSuccess);
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneUpdated) {
- // GIVEN an update finished.
-
- // THEN update_engine should call update completion.
- pd_params_.should_update_completed_be_called = true;
- // THEN need reboot since update applied.
- pd_params_.expected_exit_status = UpdateStatus::UPDATED_NEED_REBOOT;
- // THEN install indication should be false.
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneUpdatedDlcFilter) {
- // GIVEN an update finished.
- // GIVEN DLC |AppParams| list.
- auto dlc_1 = "dlc_1", dlc_2 = "dlc_2";
- pd_params_.dlc_apps_params = {{dlc_1, {.name = dlc_1, .updated = false}},
- {dlc_2, {.name = dlc_2}}};
-
- // THEN update_engine should call update completion.
- pd_params_.should_update_completed_be_called = true;
- pd_params_.args_to_update_completed = {dlc_2};
- // THEN need reboot since update applied.
- pd_params_.expected_exit_status = UpdateStatus::UPDATED_NEED_REBOOT;
- // THEN install indication should be false.
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneInstalled) {
- // GIVEN an install finished.
- pd_params_.is_install = true;
-
- // THEN update_engine should call install completion.
- pd_params_.should_install_completed_be_called = true;
- // THEN go idle.
- // THEN install indication should be false.
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneInstalledDlcFilter) {
- // GIVEN an install finished.
- pd_params_.is_install = true;
- // GIVEN DLC |AppParams| list.
- auto dlc_1 = "dlc_1", dlc_2 = "dlc_2";
- pd_params_.dlc_apps_params = {{dlc_1, {.name = dlc_1, .updated = false}},
- {dlc_2, {.name = dlc_2}}};
-
- // THEN update_engine should call install completion.
- pd_params_.should_install_completed_be_called = true;
- pd_params_.args_to_install_completed = {dlc_2};
- // THEN go idle.
- // THEN install indication should be false.
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneInstallReportingError) {
- // GIVEN an install finished.
- pd_params_.is_install = true;
- // GIVEN a reporting error occurred.
- pd_params_.status = UpdateStatus::REPORTING_ERROR_EVENT;
-
- // THEN update_engine should not call install completion.
- // THEN go idle.
- // THEN install indication should be false.
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneNoUpdate) {
- // GIVEN an update finished.
- // GIVEN an action error occured.
- pd_params_.code = ErrorCode::kNoUpdate;
-
- // THEN update_engine should not call update completion.
- // THEN go idle.
- // THEN install indication should be false.
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneNoInstall) {
- // GIVEN an install finished.
- pd_params_.is_install = true;
- // GIVEN an action error occured.
- pd_params_.code = ErrorCode::kNoUpdate;
-
- // THEN update_engine should not call install completion.
- // THEN go idle.
- // THEN install indication should be false.
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneUpdateError) {
- // GIVEN an update finished.
- // GIVEN an action error occured.
- pd_params_.code = ErrorCode::kError;
- // GIVEN an event error is set.
- attempter_.error_event_.reset(new OmahaEvent(OmahaEvent::kTypeUpdateComplete,
- OmahaEvent::kResultError,
- ErrorCode::kError));
-
- // THEN indicate a error event.
- pd_params_.expected_exit_status = UpdateStatus::REPORTING_ERROR_EVENT;
- // THEN install indication should be false.
-
- // THEN update_engine should not call update completion.
- // THEN expect critical actions of |ScheduleErrorEventAction()|.
- EXPECT_CALL(*processor_, EnqueueAction(Pointee(_))).Times(1);
- EXPECT_CALL(*processor_, StartProcessing()).Times(1);
- // THEN |ScheduleUpdates()| will be called next |ProcessingDone()| so skip.
- pd_params_.should_schedule_updates_be_called = false;
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, ProcessingDoneInstallError) {
- // GIVEN an install finished.
- pd_params_.is_install = true;
- // GIVEN an action error occured.
- pd_params_.code = ErrorCode::kError;
- // GIVEN an event error is set.
- attempter_.error_event_.reset(new OmahaEvent(OmahaEvent::kTypeUpdateComplete,
- OmahaEvent::kResultError,
- ErrorCode::kError));
-
- // THEN indicate a error event.
- pd_params_.expected_exit_status = UpdateStatus::REPORTING_ERROR_EVENT;
- // THEN install indication should be false.
-
- // THEN update_engine should not call install completion.
- // THEN expect critical actions of |ScheduleErrorEventAction()|.
- EXPECT_CALL(*processor_, EnqueueAction(Pointee(_))).Times(1);
- EXPECT_CALL(*processor_, StartProcessing()).Times(1);
- // THEN |ScheduleUpdates()| will be called next |ProcessingDone()| so skip.
- pd_params_.should_schedule_updates_be_called = false;
-
- TestProcessingDone();
-}
-
-TEST_F(UpdateAttempterTest, QuickFixTokenWhenDeviceIsEnterpriseEnrolled) {
- attempter_.CalculateUpdateParams({.quick_fix_build_token = "token"});
- EXPECT_EQ("token",
- FakeSystemState::Get()->request_params()->autoupdate_token());
-
- attempter_.CalculateUpdateParams({});
- EXPECT_TRUE(
- FakeSystemState::Get()->request_params()->autoupdate_token().empty());
-}
-
-TEST_F(UpdateAttempterTest, ScheduleUpdateSpamHandlerTest) {
- EXPECT_CALL(mock_update_manager_, AsyncPolicyRequestUpdateCheckAllowed(_, _))
- .Times(1);
- EXPECT_TRUE(attempter_.ScheduleUpdates());
- // Now there is an update scheduled which means that all subsequent
- // |ScheduleUpdates()| should fail.
- EXPECT_FALSE(attempter_.ScheduleUpdates());
- EXPECT_FALSE(attempter_.ScheduleUpdates());
- EXPECT_FALSE(attempter_.ScheduleUpdates());
-}
-
-// Critical tests to always make sure that an update is scheduled. The following
-// unittest(s) try and cover the correctness in synergy between
-// |UpdateAttempter| and |UpdateManager|. Also it is good to remember the
-// actions that happen in the flow when |UpdateAttempter| get callbacked on
-// |OnUpdateScheduled()| -> (various cases which leads to) -> |ProcessingDone()|
-void UpdateAttempterTest::TestOnUpdateScheduled() {
- // Setup
- attempter_.SetWaitingForScheduledCheck(true);
- attempter_.DisableUpdate();
- attempter_.DisableScheduleUpdates();
-
- // Invocation
- attempter_.OnUpdateScheduled(ous_params_.status, ous_params_.params);
-
- // Verify
- EXPECT_EQ(ous_params_.exit_status, attempter_.status());
- EXPECT_EQ(ous_params_.should_schedule_updates_be_called,
- attempter_.WasScheduleUpdatesCalled());
- EXPECT_EQ(ous_params_.should_update_be_called, attempter_.WasUpdateCalled());
-}
-
-TEST_F(UpdateAttempterTest, OnUpdatesScheduledFailed) {
- // GIVEN failed status.
-
- // THEN update should be scheduled.
- ous_params_.should_schedule_updates_be_called = true;
-
- TestOnUpdateScheduled();
-}
-
-TEST_F(UpdateAttempterTest, OnUpdatesScheduledAskMeAgainLater) {
- // GIVEN ask me again later status.
- ous_params_.status = EvalStatus::kAskMeAgainLater;
-
- // THEN update should be scheduled.
- ous_params_.should_schedule_updates_be_called = true;
-
- TestOnUpdateScheduled();
-}
-
-TEST_F(UpdateAttempterTest, OnUpdatesScheduledContinue) {
- // GIVEN continue status.
- ous_params_.status = EvalStatus::kContinue;
-
- // THEN update should be scheduled.
- ous_params_.should_schedule_updates_be_called = true;
-
- TestOnUpdateScheduled();
-}
-
-TEST_F(UpdateAttempterTest, OnUpdatesScheduledSucceededButUpdateDisabledFails) {
- // GIVEN updates disabled.
- ous_params_.params = {.updates_enabled = false};
- // GIVEN succeeded status.
- ous_params_.status = EvalStatus::kSucceeded;
-
- // THEN update should not be scheduled.
-
- TestOnUpdateScheduled();
-}
-
-TEST_F(UpdateAttempterTest, OnUpdatesScheduledSucceeded) {
- // GIVEN updates enabled.
- ous_params_.params = {.updates_enabled = true};
- // GIVEN succeeded status.
- ous_params_.status = EvalStatus::kSucceeded;
-
- // THEN update should be called indicating status change.
- ous_params_.exit_status = UpdateStatus::CHECKING_FOR_UPDATE;
- ous_params_.should_update_be_called = true;
-
- TestOnUpdateScheduled();
-}
-
-TEST_F(UpdateAttempterTest, IsEnterpriseRollbackInGetStatusDefault) {
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_FALSE(status.is_enterprise_rollback);
-}
-
-TEST_F(UpdateAttempterTest, IsEnterpriseRollbackInGetStatusFalse) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = false;
-
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_FALSE(status.is_enterprise_rollback);
-}
-
-TEST_F(UpdateAttempterTest, IsEnterpriseRollbackInGetStatusTrue) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = true;
-
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_TRUE(status.is_enterprise_rollback);
-}
-
-TEST_F(UpdateAttempterTest, PowerwashInGetStatusDefault) {
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_FALSE(status.will_powerwash_after_reboot);
-}
-
-TEST_F(UpdateAttempterTest, PowerwashInGetStatusTrueBecausePowerwashRequired) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->powerwash_required = true;
-
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_TRUE(status.will_powerwash_after_reboot);
-}
-
-TEST_F(UpdateAttempterTest, PowerwashInGetStatusTrueBecauseRollback) {
- attempter_.install_plan_.reset(new InstallPlan);
- attempter_.install_plan_->is_rollback = true;
-
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_TRUE(status.will_powerwash_after_reboot);
-}
-
-TEST_F(UpdateAttempterTest, FutureEolTest) {
- EolDate eol_date = std::numeric_limits<int64_t>::max();
- EXPECT_TRUE(prefs_->SetString(kPrefsOmahaEolDate, EolDateToString(eol_date)));
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_EQ(eol_date, status.eol_date);
-}
-
-TEST_F(UpdateAttempterTest, PastEolTest) {
- EolDate eol_date = 1;
- EXPECT_TRUE(prefs_->SetString(kPrefsOmahaEolDate, EolDateToString(eol_date)));
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_EQ(eol_date, status.eol_date);
-}
-
-TEST_F(UpdateAttempterTest, MissingEolTest) {
- UpdateEngineStatus status;
- attempter_.GetStatus(&status);
- EXPECT_EQ(kEolDateInvalid, status.eol_date);
-}
-
-TEST_F(UpdateAttempterTest, CalculateDlcParamsInstallTest) {
- string dlc_id = "dlc0";
- attempter_.is_install_ = true;
- attempter_.dlc_ids_ = {dlc_id};
- attempter_.CalculateDlcParams();
-
- OmahaRequestParams* params = FakeSystemState::Get()->request_params();
- EXPECT_EQ(1, params->dlc_apps_params().count(params->GetDlcAppId(dlc_id)));
- OmahaRequestParams::AppParams dlc_app_params =
- params->dlc_apps_params().at(params->GetDlcAppId(dlc_id));
- EXPECT_STREQ(dlc_id.c_str(), dlc_app_params.name.c_str());
- EXPECT_EQ(false, dlc_app_params.send_ping);
- // When the DLC gets installed, a ping is not sent, therefore we don't store
- // the values sent by Omaha.
- auto last_active_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastActive});
- EXPECT_FALSE(FakeSystemState::Get()->prefs()->Exists(last_active_key));
- auto last_rollcall_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastRollcall});
- EXPECT_FALSE(FakeSystemState::Get()->prefs()->Exists(last_rollcall_key));
-}
-
-TEST_F(UpdateAttempterTest, CalculateDlcParamsNoPrefFilesTest) {
- string dlc_id = "dlc0";
- EXPECT_CALL(mock_dlcservice_, GetDlcsToUpdate(_))
- .WillOnce(
- DoAll(SetArgPointee<0>(std::vector<string>({dlc_id})), Return(true)));
-
- attempter_.is_install_ = false;
- attempter_.CalculateDlcParams();
-
- OmahaRequestParams* params = FakeSystemState::Get()->request_params();
- EXPECT_EQ(1, params->dlc_apps_params().count(params->GetDlcAppId(dlc_id)));
- OmahaRequestParams::AppParams dlc_app_params =
- params->dlc_apps_params().at(params->GetDlcAppId(dlc_id));
- EXPECT_STREQ(dlc_id.c_str(), dlc_app_params.name.c_str());
-
- EXPECT_EQ(true, dlc_app_params.send_ping);
- EXPECT_EQ(0, dlc_app_params.ping_active);
- EXPECT_EQ(-1, dlc_app_params.ping_date_last_active);
- EXPECT_EQ(-1, dlc_app_params.ping_date_last_rollcall);
-}
-
-TEST_F(UpdateAttempterTest, CalculateDlcParamsNonParseableValuesTest) {
- string dlc_id = "dlc0";
- MemoryPrefs prefs;
- FakeSystemState::Get()->set_prefs(&prefs);
- EXPECT_CALL(mock_dlcservice_, GetDlcsToUpdate(_))
- .WillOnce(
- DoAll(SetArgPointee<0>(std::vector<string>({dlc_id})), Return(true)));
-
- // Write non numeric values in the metadata files.
- auto active_key =
- PrefsInterface::CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
- auto last_active_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastActive});
- auto last_rollcall_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastRollcall});
- FakeSystemState::Get()->prefs()->SetString(active_key, "z2yz");
- FakeSystemState::Get()->prefs()->SetString(last_active_key, "z2yz");
- FakeSystemState::Get()->prefs()->SetString(last_rollcall_key, "z2yz");
- attempter_.is_install_ = false;
- attempter_.CalculateDlcParams();
-
- OmahaRequestParams* params = FakeSystemState::Get()->request_params();
- EXPECT_EQ(1, params->dlc_apps_params().count(params->GetDlcAppId(dlc_id)));
- OmahaRequestParams::AppParams dlc_app_params =
- params->dlc_apps_params().at(params->GetDlcAppId(dlc_id));
- EXPECT_STREQ(dlc_id.c_str(), dlc_app_params.name.c_str());
-
- EXPECT_EQ(true, dlc_app_params.send_ping);
- EXPECT_EQ(0, dlc_app_params.ping_active);
- EXPECT_EQ(-2, dlc_app_params.ping_date_last_active);
- EXPECT_EQ(-2, dlc_app_params.ping_date_last_rollcall);
-}
-
-TEST_F(UpdateAttempterTest, CalculateDlcParamsValidValuesTest) {
- string dlc_id = "dlc0";
- EXPECT_CALL(mock_dlcservice_, GetDlcsToUpdate(_))
- .WillOnce(
- DoAll(SetArgPointee<0>(std::vector<string>({dlc_id})), Return(true)));
-
- // Write numeric values in the metadata files.
- auto active_key =
- PrefsInterface::CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
- auto last_active_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastActive});
- auto last_rollcall_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastRollcall});
-
- FakeSystemState::Get()->prefs()->SetInt64(active_key, 1);
- FakeSystemState::Get()->prefs()->SetInt64(last_active_key, 78);
- FakeSystemState::Get()->prefs()->SetInt64(last_rollcall_key, 99);
- attempter_.is_install_ = false;
- attempter_.CalculateDlcParams();
-
- OmahaRequestParams* params = FakeSystemState::Get()->request_params();
- EXPECT_EQ(1, params->dlc_apps_params().count(params->GetDlcAppId(dlc_id)));
- OmahaRequestParams::AppParams dlc_app_params =
- params->dlc_apps_params().at(params->GetDlcAppId(dlc_id));
- EXPECT_STREQ(dlc_id.c_str(), dlc_app_params.name.c_str());
-
- EXPECT_EQ(true, dlc_app_params.send_ping);
- EXPECT_EQ(1, dlc_app_params.ping_active);
- EXPECT_EQ(78, dlc_app_params.ping_date_last_active);
- EXPECT_EQ(99, dlc_app_params.ping_date_last_rollcall);
-}
-
-TEST_F(UpdateAttempterTest, CalculateDlcParamsRemoveStaleMetadata) {
- string dlc_id = "dlc0";
- auto active_key =
- PrefsInterface::CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
- auto last_active_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastActive});
- auto last_rollcall_key = PrefsInterface::CreateSubKey(
- {kDlcPrefsSubDir, dlc_id, kPrefsPingLastRollcall});
- FakeSystemState::Get()->prefs()->SetInt64(active_key, kPingInactiveValue);
- FakeSystemState::Get()->prefs()->SetInt64(last_active_key, 0);
- FakeSystemState::Get()->prefs()->SetInt64(last_rollcall_key, 0);
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->Exists(active_key));
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->Exists(last_active_key));
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->Exists(last_rollcall_key));
-
- attempter_.dlc_ids_ = {dlc_id};
- attempter_.is_install_ = true;
- attempter_.CalculateDlcParams();
-
- EXPECT_FALSE(FakeSystemState::Get()->prefs()->Exists(last_active_key));
- EXPECT_FALSE(FakeSystemState::Get()->prefs()->Exists(last_rollcall_key));
- // Active key is set on install.
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->Exists(active_key));
- int64_t temp_int;
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->GetInt64(active_key, &temp_int));
- EXPECT_EQ(temp_int, kPingActiveValue);
-}
-
-TEST_F(UpdateAttempterTest, SetDlcActiveValue) {
- string dlc_id = "dlc0";
- attempter_.SetDlcActiveValue(true, dlc_id);
- int64_t temp_int;
- auto active_key =
- PrefsInterface::CreateSubKey({kDlcPrefsSubDir, dlc_id, kPrefsPingActive});
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->Exists(active_key));
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->GetInt64(active_key, &temp_int));
- EXPECT_EQ(temp_int, kPingActiveValue);
-}
-
-TEST_F(UpdateAttempterTest, SetDlcInactive) {
- string dlc_id = "dlc0";
- auto sub_keys = {
- kPrefsPingActive, kPrefsPingLastActive, kPrefsPingLastRollcall};
- for (auto& sub_key : sub_keys) {
- auto key = PrefsInterface::CreateSubKey({kDlcPrefsSubDir, dlc_id, sub_key});
- FakeSystemState::Get()->prefs()->SetInt64(key, 1);
- EXPECT_TRUE(FakeSystemState::Get()->prefs()->Exists(key));
- }
- attempter_.SetDlcActiveValue(false, dlc_id);
- for (auto& sub_key : sub_keys) {
- auto key = PrefsInterface::CreateSubKey({kDlcPrefsSubDir, dlc_id, sub_key});
- EXPECT_FALSE(FakeSystemState::Get()->prefs()->Exists(key));
- }
-}
-
-TEST_F(UpdateAttempterTest, GetSuccessfulDlcIds) {
- auto dlc_1 = "1", dlc_2 = "2", dlc_3 = "3";
- attempter_.omaha_request_params_->set_dlc_apps_params(
- {{dlc_1, {.name = dlc_1, .updated = false}},
- {dlc_2, {.name = dlc_2}},
- {dlc_3, {.name = dlc_3, .updated = false}}});
- EXPECT_THAT(attempter_.GetSuccessfulDlcIds(), ElementsAre(dlc_2));
-}
-
-TEST_F(UpdateAttempterTest, MoveToPrefs) {
- string key1 = kPrefsLastActivePingDay;
- string key2 = kPrefsPingLastRollcall;
-
- FakePrefs fake_prefs;
- EXPECT_TRUE(fake_prefs.SetString(key2, "current-rollcall"));
- FakeSystemState::Get()->set_prefs(&fake_prefs);
-
- FakePrefs powerwash_safe_prefs;
- EXPECT_TRUE(powerwash_safe_prefs.SetString(key1, "powerwash-last-active"));
- EXPECT_TRUE(powerwash_safe_prefs.SetString(key2, "powerwash-last-rollcall"));
- FakeSystemState::Get()->set_powerwash_safe_prefs(&powerwash_safe_prefs);
-
- attempter_.Init();
- attempter_.MoveToPrefs({key1, key2});
-
- string pref_value_1;
- fake_prefs.GetString(key1, &pref_value_1);
- EXPECT_EQ(pref_value_1, "powerwash-last-active");
- // Do not overwrite if value already exists.
- string pref_value_2;
- fake_prefs.GetString(key2, &pref_value_2);
- EXPECT_EQ(pref_value_2, "current-rollcall");
-
- // Make sure keys are deleted from powerwash safe prefs regardless of whether
- // they are written to prefs.
- EXPECT_FALSE(FakeSystemState::Get()->powerwash_safe_prefs()->Exists(key1));
- EXPECT_FALSE(FakeSystemState::Get()->powerwash_safe_prefs()->Exists(key2));
-}
-
-} // namespace chromeos_update_engine
diff --git a/cros/update_engine_client.cc b/cros/update_engine_client.cc
deleted file mode 100644
index 6f20f11a..00000000
--- a/cros/update_engine_client.cc
+++ /dev/null
@@ -1,601 +0,0 @@
-//
-// Copyright (C) 2012 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 <inttypes.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/command_line.h>
-#include <base/logging.h>
-#include <base/macros.h>
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_split.h>
-#include <base/threading/platform_thread.h>
-#include <base/threading/thread_task_runner_handle.h>
-#include <brillo/daemons/daemon.h>
-#include <brillo/flag_helper.h>
-#include <brillo/key_value_store.h>
-
-#include "update_engine/client.h"
-#include "update_engine/common/error_code.h"
-#include "update_engine/common/error_code_utils.h"
-#include "update_engine/cros/omaha_utils.h"
-#include "update_engine/status_update_handler.h"
-#include "update_engine/update_status.h"
-#include "update_engine/update_status_utils.h"
-
-using brillo::KeyValueStore;
-using chromeos_update_engine::EolDate;
-using chromeos_update_engine::EolDateToString;
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::UpdateEngineStatusToString;
-using chromeos_update_engine::UpdateStatusToString;
-using chromeos_update_engine::utils::ErrorCodeToString;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-using update_engine::UpdateEngineStatus;
-using update_engine::UpdateStatus;
-
-namespace {
-
-// Constant to signal that we need to continue running the daemon after
-// initialization.
-const int kContinueRunning = -1;
-
-// The ShowStatus request will be retried `kShowStatusRetryCount` times at
-// `kShowStatusRetryInterval` second intervals on failure.
-const int kShowStatusRetryCount = 30;
-const int kShowStatusRetryIntervalInSeconds = 2;
-
-class UpdateEngineClient : public brillo::Daemon {
- public:
- UpdateEngineClient(int argc, char** argv) : argc_(argc), argv_(argv) {}
-
- ~UpdateEngineClient() override = default;
-
- protected:
- int OnInit() override {
- int ret = Daemon::OnInit();
- if (ret != EX_OK)
- return ret;
-
- client_ = update_engine::UpdateEngineClient::CreateInstance();
-
- if (!client_) {
- LOG(ERROR) << "UpdateEngineService not available.";
- return 1;
- }
-
- // We can't call QuitWithExitCode from OnInit(), so we delay the execution
- // of the ProcessFlags method after the Daemon initialization is done.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&UpdateEngineClient::ProcessFlagsAndExit,
- base::Unretained(this)));
- return EX_OK;
- }
-
- private:
- // Show the status of the update engine in stdout.
- bool ShowStatus();
-
- // Return whether we need to reboot. 0 if reboot is needed, 1 if an error
- // occurred, 2 if no reboot is needed.
- int GetNeedReboot();
-
- // Main method that parses and triggers all the actions based on the passed
- // flags. Returns the exit code of the program of kContinueRunning if it
- // should not exit.
- int ProcessFlags();
-
- // Processes the flags and exits the program accordingly.
- void ProcessFlagsAndExit();
-
- // Copy of argc and argv passed to main().
- int argc_;
- char** argv_;
-
- // Library-based client
- unique_ptr<update_engine::UpdateEngineClient> client_;
-
- // Pointers to handlers for cleanup
- vector<unique_ptr<update_engine::StatusUpdateHandler>> handlers_;
-
- DISALLOW_COPY_AND_ASSIGN(UpdateEngineClient);
-};
-
-class ExitingStatusUpdateHandler : public update_engine::StatusUpdateHandler {
- public:
- ~ExitingStatusUpdateHandler() override = default;
-
- void IPCError(const string& error) override;
-};
-
-void ExitingStatusUpdateHandler::IPCError(const string& error) {
- LOG(ERROR) << error;
- exit(1);
-}
-
-class WatchingStatusUpdateHandler : public ExitingStatusUpdateHandler {
- public:
- ~WatchingStatusUpdateHandler() override = default;
-
- void HandleStatusUpdate(const UpdateEngineStatus& status) override;
-};
-
-void WatchingStatusUpdateHandler::HandleStatusUpdate(
- const UpdateEngineStatus& status) {
- LOG(INFO) << "Got status update: " << UpdateEngineStatusToString(status);
-}
-
-bool UpdateEngineClient::ShowStatus() {
- UpdateEngineStatus status;
- int retry_count = kShowStatusRetryCount;
- while (retry_count > 0) {
- if (client_->GetStatus(&status)) {
- break;
- }
- if (--retry_count == 0) {
- return false;
- }
- LOG(WARNING)
- << "Failed to get the update_engine status. This can happen when the"
- " update_engine is busy doing a heavy operation or if the"
- " update-engine service is down. If it doesn't resolve, a restart of"
- " the update-engine service is needed."
- " Will try "
- << retry_count << " more times!";
- base::PlatformThread::Sleep(
- base::TimeDelta::FromSeconds(kShowStatusRetryIntervalInSeconds));
- }
-
- printf("%s", UpdateEngineStatusToString(status).c_str());
-
- return true;
-}
-
-int UpdateEngineClient::GetNeedReboot() {
- UpdateEngineStatus status;
- if (!client_->GetStatus(&status)) {
- return 1;
- }
-
- if (status.status == UpdateStatus::UPDATED_NEED_REBOOT) {
- return 0;
- }
-
- return 2;
-}
-
-class UpdateWaitHandler : public ExitingStatusUpdateHandler {
- public:
- explicit UpdateWaitHandler(bool exit_on_error,
- update_engine::UpdateEngineClient* client)
- : exit_on_error_(exit_on_error), client_(client) {}
-
- ~UpdateWaitHandler() override = default;
-
- void HandleStatusUpdate(const UpdateEngineStatus& status) override;
-
- private:
- bool exit_on_error_;
- update_engine::UpdateEngineClient* client_;
-};
-
-void UpdateWaitHandler::HandleStatusUpdate(const UpdateEngineStatus& status) {
- if (exit_on_error_ && status.status == UpdateStatus::IDLE) {
- int last_attempt_error = static_cast<int>(ErrorCode::kSuccess);
- ErrorCode code = ErrorCode::kSuccess;
- if (client_ && client_->GetLastAttemptError(&last_attempt_error))
- code = static_cast<ErrorCode>(last_attempt_error);
-
- LOG(ERROR) << "Update failed, current operation is "
- << UpdateStatusToString(status.status) << ", last error code is "
- << ErrorCodeToString(code) << "(" << last_attempt_error << ")";
- exit(1);
- }
- if (status.status == UpdateStatus::UPDATED_NEED_REBOOT) {
- LOG(INFO) << "Update succeeded -- reboot needed.";
- exit(0);
- }
-}
-
-int UpdateEngineClient::ProcessFlags() {
- DEFINE_string(app_version, "", "Force the current app version.");
- DEFINE_string(channel,
- "",
- "Set the target channel. The device will be powerwashed if the "
- "target channel is more stable than the current channel unless "
- "--nopowerwash is specified.");
- DEFINE_bool(check_for_update, false, "Initiate check for updates.");
- DEFINE_string(
- cohort_hint, "", "Set the current cohort hint to the passed value.");
- DEFINE_bool(follow,
- false,
- "Wait for any update operations to complete."
- "Exit status is 0 if the update succeeded, and 1 otherwise.");
- DEFINE_bool(interactive, true, "Mark the update request as interactive.");
- DEFINE_string(omaha_url, "", "The URL of the Omaha update server.");
- DEFINE_string(p2p_update,
- "",
- "Enables (\"yes\") or disables (\"no\") the peer-to-peer update"
- " sharing.");
- DEFINE_bool(powerwash,
- true,
- "When performing rollback or channel change, "
- "do a powerwash or allow it respectively.");
- DEFINE_bool(reboot, false, "Initiate a reboot if needed.");
- DEFINE_bool(is_reboot_needed,
- false,
- "Exit status 0 if reboot is needed, "
- "2 if reboot is not needed or 1 if an error occurred.");
- DEFINE_bool(block_until_reboot_is_needed,
- false,
- "Blocks until reboot is "
- "needed. Returns non-zero exit status if an error occurred.");
- DEFINE_bool(reset_status, false, "Sets the status in update_engine to idle.");
- DEFINE_bool(rollback,
- false,
- "Perform a rollback to the previous partition. The device will "
- "be powerwashed unless --nopowerwash is specified.");
- DEFINE_bool(can_rollback,
- false,
- "Shows whether rollback partition "
- "is available.");
- DEFINE_bool(show_channel, false, "Show the current and target channels.");
- DEFINE_bool(show_cohort_hint, false, "Show the current cohort hint.");
- DEFINE_bool(show_p2p_update,
- false,
- "Show the current setting for peer-to-peer update sharing.");
- DEFINE_bool(show_update_over_cellular,
- false,
- "Show the current setting for updates over cellular networks.");
- DEFINE_bool(status, false, "Print the status to stdout.");
- DEFINE_bool(update,
- false,
- "Forces an update and waits for it to complete. "
- "Implies --follow.");
- DEFINE_string(update_over_cellular,
- "",
- "Enables (\"yes\") or disables (\"no\") the updates over "
- "cellular networks.");
- DEFINE_bool(watch_for_updates,
- false,
- "Listen for status updates and print them to the screen.");
- DEFINE_bool(prev_version,
- false,
- "Show the previous OS version used before the update reboot.");
- DEFINE_bool(last_attempt_error, false, "Show the last attempt error.");
- DEFINE_bool(eol_status, false, "Show the current end-of-life status.");
-
- // Boilerplate init commands.
- base::CommandLine::Init(argc_, argv_);
- brillo::FlagHelper::Init(argc_, argv_, "A/B Update Engine Client");
-
- // Ensure there are no positional arguments.
- const vector<string> positional_args =
- base::CommandLine::ForCurrentProcess()->GetArgs();
- if (!positional_args.empty()) {
- LOG(ERROR) << "Found a positional argument '" << positional_args.front()
- << "'. If you want to pass a value to a flag, pass it as "
- "--flag=value.";
- return 1;
- }
-
- // Update the status if requested.
- if (FLAGS_reset_status) {
- LOG(INFO) << "Setting Update Engine status to idle ...";
-
- if (client_->ResetStatus()) {
- LOG(INFO) << "ResetStatus succeeded; to undo partition table changes "
- "run:\n"
- "(D=$(rootdev -d) P=$(rootdev -s); cgpt p -i$(($(echo "
- "${P#$D} | sed 's/^[^0-9]*//')-1)) $D;)";
- } else {
- LOG(ERROR) << "ResetStatus failed";
- return 1;
- }
- }
-
- // Changes the current update over cellular network setting.
- if (!FLAGS_update_over_cellular.empty()) {
- bool allowed = FLAGS_update_over_cellular == "yes";
- if (!allowed && FLAGS_update_over_cellular != "no") {
- LOG(ERROR) << "Unknown option: \"" << FLAGS_update_over_cellular
- << "\". Please specify \"yes\" or \"no\".";
- } else {
- if (!client_->SetUpdateOverCellularPermission(allowed)) {
- LOG(ERROR) << "Error setting the update over cellular setting.";
- return 1;
- }
- }
- }
-
- // Show the current update over cellular network setting.
- if (FLAGS_show_update_over_cellular) {
- bool allowed;
-
- if (!client_->GetUpdateOverCellularPermission(&allowed)) {
- LOG(ERROR) << "Error getting the update over cellular setting.";
- return 1;
- }
-
- LOG(INFO) << "Current update over cellular network setting: "
- << (allowed ? "ENABLED" : "DISABLED");
- }
-
- // Change/show the cohort hint.
- bool set_cohort_hint =
- base::CommandLine::ForCurrentProcess()->HasSwitch("cohort_hint");
- if (set_cohort_hint) {
- LOG(INFO) << "Setting cohort hint to: \"" << FLAGS_cohort_hint << "\"";
- if (!client_->SetCohortHint(FLAGS_cohort_hint)) {
- LOG(ERROR) << "Error setting the cohort hint.";
- return 1;
- }
- }
-
- if (FLAGS_show_cohort_hint || set_cohort_hint) {
- string cohort_hint;
- if (!client_->GetCohortHint(&cohort_hint)) {
- LOG(ERROR) << "Error getting the cohort hint.";
- return 1;
- }
-
- LOG(INFO) << "Current cohort hint: \"" << cohort_hint << "\"";
- }
-
- if (!FLAGS_powerwash && !FLAGS_rollback && FLAGS_channel.empty()) {
- LOG(ERROR) << "powerwash flag only makes sense rollback or channel change";
- return 1;
- }
-
- // Change the P2P enabled setting.
- if (!FLAGS_p2p_update.empty()) {
- bool enabled = FLAGS_p2p_update == "yes";
- if (!enabled && FLAGS_p2p_update != "no") {
- LOG(ERROR) << "Unknown option: \"" << FLAGS_p2p_update
- << "\". Please specify \"yes\" or \"no\".";
- } else {
- if (!client_->SetP2PUpdatePermission(enabled)) {
- LOG(ERROR) << "Error setting the peer-to-peer update setting.";
- return 1;
- }
- }
- }
-
- // Show the rollback availability.
- if (FLAGS_can_rollback) {
- string rollback_partition;
-
- if (!client_->GetRollbackPartition(&rollback_partition)) {
- LOG(ERROR) << "Error while querying rollback partition availability.";
- return 1;
- }
-
- bool can_rollback = true;
- if (rollback_partition.empty()) {
- rollback_partition = "UNAVAILABLE";
- can_rollback = false;
- } else {
- rollback_partition = "AVAILABLE: " + rollback_partition;
- }
-
- LOG(INFO) << "Rollback partition: " << rollback_partition;
- if (!can_rollback) {
- return 1;
- }
- }
-
- // Show the current P2P enabled setting.
- if (FLAGS_show_p2p_update) {
- bool enabled;
-
- if (!client_->GetP2PUpdatePermission(&enabled)) {
- LOG(ERROR) << "Error getting the peer-to-peer update setting.";
- return 1;
- }
-
- LOG(INFO) << "Current update using P2P setting: "
- << (enabled ? "ENABLED" : "DISABLED");
- }
-
- // First, update the target channel if requested.
- if (!FLAGS_channel.empty()) {
- if (!client_->SetTargetChannel(FLAGS_channel, FLAGS_powerwash)) {
- LOG(ERROR) << "Error setting the channel.";
- return 1;
- }
-
- LOG(INFO) << "Channel permanently set to: " << FLAGS_channel;
- }
-
- // Show the current and target channels if requested.
- if (FLAGS_show_channel) {
- string current_channel;
- string target_channel;
-
- if (!client_->GetChannel(&current_channel)) {
- LOG(ERROR) << "Error getting the current channel.";
- return 1;
- }
-
- if (!client_->GetTargetChannel(&target_channel)) {
- LOG(ERROR) << "Error getting the target channel.";
- return 1;
- }
-
- LOG(INFO) << "Current Channel: " << current_channel;
-
- if (!target_channel.empty())
- LOG(INFO) << "Target Channel (pending update): " << target_channel;
- }
-
- bool do_update_request = FLAGS_check_for_update || FLAGS_update ||
- !FLAGS_app_version.empty() ||
- !FLAGS_omaha_url.empty();
- if (FLAGS_update)
- FLAGS_follow = true;
-
- if (do_update_request && FLAGS_rollback) {
- LOG(ERROR) << "Incompatible flags specified with rollback."
- << "Rollback should not include update-related flags.";
- return 1;
- }
-
- if (FLAGS_rollback) {
- LOG(INFO) << "Requesting rollback.";
- if (!client_->Rollback(FLAGS_powerwash)) {
- LOG(ERROR) << "Rollback request failed.";
- return 1;
- }
- }
-
- // Initiate an update check, if necessary.
- if (do_update_request) {
- LOG_IF(WARNING, FLAGS_reboot) << "-reboot flag ignored.";
- string app_version = FLAGS_app_version;
- if (FLAGS_update && app_version.empty()) {
- app_version = "ForcedUpdate";
- LOG(INFO) << "Forcing an update by setting app_version to ForcedUpdate.";
- }
- LOG(INFO) << "Initiating update check.";
- if (!client_->AttemptUpdate(
- app_version, FLAGS_omaha_url, FLAGS_interactive)) {
- LOG(ERROR) << "Error checking for update.";
- return 1;
- }
- }
-
- // These final options are all mutually exclusive with one another.
- if (FLAGS_follow + FLAGS_watch_for_updates + FLAGS_reboot + FLAGS_status +
- FLAGS_is_reboot_needed + FLAGS_block_until_reboot_is_needed >
- 1) {
- LOG(ERROR) << "Multiple exclusive options selected. "
- << "Select only one of --follow, --watch_for_updates, --reboot, "
- << "--is_reboot_needed, --block_until_reboot_is_needed, "
- << "or --status.";
- return 1;
- }
-
- if (FLAGS_status) {
- LOG(INFO) << "Querying Update Engine status...";
- if (!ShowStatus()) {
- LOG(ERROR) << "Failed to query status";
- return 1;
- }
- return 0;
- }
-
- if (FLAGS_follow) {
- LOG(INFO) << "Waiting for update to complete.";
- auto handler = new UpdateWaitHandler(true, client_.get());
- handlers_.emplace_back(handler);
- client_->RegisterStatusUpdateHandler(handler);
- return kContinueRunning;
- }
-
- if (FLAGS_watch_for_updates) {
- LOG(INFO) << "Watching for status updates.";
- auto handler = new WatchingStatusUpdateHandler();
- handlers_.emplace_back(handler);
- client_->RegisterStatusUpdateHandler(handler);
- return kContinueRunning;
- }
-
- if (FLAGS_reboot) {
- LOG(INFO) << "Requesting a reboot...";
- client_->RebootIfNeeded();
- return 0;
- }
-
- if (FLAGS_prev_version) {
- string prev_version;
-
- if (!client_->GetPrevVersion(&prev_version)) {
- LOG(ERROR) << "Error getting previous version.";
- } else {
- LOG(INFO) << "Previous version = " << prev_version;
- }
- }
-
- if (FLAGS_is_reboot_needed) {
- int ret = GetNeedReboot();
-
- if (ret == 1) {
- LOG(ERROR) << "Could not query the current operation.";
- }
-
- return ret;
- }
-
- if (FLAGS_block_until_reboot_is_needed) {
- auto handler = new UpdateWaitHandler(false, nullptr);
- handlers_.emplace_back(handler);
- client_->RegisterStatusUpdateHandler(handler);
- return kContinueRunning;
- }
-
- if (FLAGS_last_attempt_error) {
- int last_attempt_error;
- if (!client_->GetLastAttemptError(&last_attempt_error)) {
- LOG(ERROR) << "Error getting last attempt error.";
- } else {
- ErrorCode code = static_cast<ErrorCode>(last_attempt_error);
-
- KeyValueStore last_attempt_error_store;
- last_attempt_error_store.SetString(
- "ERROR_CODE", base::NumberToString(last_attempt_error));
- last_attempt_error_store.SetString("ERROR_MESSAGE",
- ErrorCodeToString(code));
- printf("%s", last_attempt_error_store.SaveToString().c_str());
- }
- }
-
- if (FLAGS_eol_status) {
- UpdateEngineStatus status;
- if (!client_->GetStatus(&status)) {
- LOG(ERROR) << "Error GetStatus() for getting EOL info.";
- } else {
- EolDate eol_date_code = status.eol_date;
-
- KeyValueStore eol_status_store;
- eol_status_store.SetString("EOL_DATE", EolDateToString(eol_date_code));
- printf("%s", eol_status_store.SaveToString().c_str());
- }
- }
-
- return 0;
-}
-
-void UpdateEngineClient::ProcessFlagsAndExit() {
- int ret = ProcessFlags();
- if (ret != kContinueRunning)
- QuitWithExitCode(ret);
-}
-
-} // namespace
-
-int main(int argc, char** argv) {
- UpdateEngineClient client(argc, argv);
- return client.Run();
-}
diff --git a/dbus_bindings/dbus-service-config.json b/dbus_bindings/dbus-service-config.json
deleted file mode 100644
index fdae3baf..00000000
--- a/dbus_bindings/dbus-service-config.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "service_name": "org.chromium.UpdateEngine"
-}
diff --git a/dbus_bindings/org.chromium.KioskAppService.dbus-xml b/dbus_bindings/org.chromium.KioskAppService.dbus-xml
deleted file mode 100644
index 11b888b9..00000000
--- a/dbus_bindings/org.chromium.KioskAppService.dbus-xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<node name="/org/chromium/KioskAppService"
- xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
- <interface name="org.chromium.KioskAppServiceInterface">
- <method name="GetRequiredPlatformVersion">
- <arg name="required_platform_version" type="s" direction="out" />
- </method>
- </interface>
-</node>
diff --git a/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml b/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
deleted file mode 100644
index ac2f0211..00000000
--- a/dbus_bindings/org.chromium.UpdateEngineInterface.dbus-xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- Copyright (C) 2019 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.
-!-->
-<node name="/org/chromium/UpdateEngine">
- <interface name="org.chromium.UpdateEngineInterface">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol"
- value="update_engine_service" />
- <annotation name="org.freedesktop.DBus.GLib.ClientCSymbol"
- value="update_engine_client" />
- <method name="AttemptUpdate">
- <arg type="s" name="app_version" direction="in" />
- <arg type="s" name="omaha_url" direction="in" />
- </method>
- <!-- TODO(zeuthen,chromium:286399): Rename to AttemptUpdate and
- update Chrome and other users of the AttemptUpdate() method
- in lockstep.
- -->
- <method name="AttemptUpdateWithFlags">
- <arg type="s" name="app_version" direction="in" />
- <arg type="s" name="omaha_url" direction="in" />
- <!-- See AttemptUpdateFlags enum in update_engine/dbus-constants.h. -->
- <arg type="i" name="flags" direction="in" />
- </method>
- <method name="AttemptInstall">
- <arg type="s" name="omaha_url" direction="in" />
- <arg type="as" name="dlc_ids" direction="in">
- <tp:docstring>
- The list of DLC IDs that needs to be installed.
- </tp:docstring>
- </arg>
- </method>
- <method name="AttemptRollback">
- <arg type="b" name="powerwash" direction="in" />
- </method>
- <method name="CanRollback">
- <arg type="b" name="can_rollback" direction="out" />
- </method>
- <method name="ResetStatus">
- </method>
- <method name="SetDlcActiveValue">
- <arg type="b" name="is_active" direction="in">
- <tp:docstring>
- If the DLC is being set to active or inactive.
- </tp:docstring>
- </arg>
- <arg type="s" name="dlc_id" direction="in">
- <tp:docstring>
- The ID of the DLC module that will be set to active/inactive.
- </tp:docstring>
- </arg>
- </method>
- <method name="GetStatusAdvanced">
- <arg type="ay" name="status" direction="out">
- <tp:docstring>
- The current status serialized in a protobuf.
- </tp:docstring>
- <annotation name="org.chromium.DBus.Argument.ProtobufClass"
- value="update_engine::StatusResult"/>
- </arg>
- </method>
- <method name="RebootIfNeeded">
- </method>
- <method name="SetChannel">
- <arg type="s" name="target_channel" direction="in" />
- <arg type="b" name="is_powerwash_allowed" direction="in" />
- </method>
- <method name="GetChannel">
- <arg type="b" name="get_current_channel" direction="in" />
- <arg type="s" name="channel" direction="out" />
- </method>
- <method name="SetCohortHint">
- <arg type="s" name="cohort_hint" direction="in" />
- </method>
- <method name="GetCohortHint">
- <arg type="s" name="cohort_hint" direction="out" />
- </method>
- <method name="SetP2PUpdatePermission">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol"
- value="update_engine_service_set_p2p_update_permission" />
- <annotation name="org.freedesktop.DBus.GLib.ClientCSymbol"
- value="update_engine_client_set_p2p_update_permission" />
- <arg type="b" name="enabled" direction="in" />
- </method>
- <method name="GetP2PUpdatePermission">
- <annotation name="org.freedesktop.DBus.GLib.CSymbol"
- value="update_engine_service_get_p2p_update_permission" />
- <annotation name="org.freedesktop.DBus.GLib.ClientCSymbol"
- value="update_engine_client_get_p2p_update_permission" />
- <arg type="b" name="enabled" direction="out" />
- </method>
- <method name="SetUpdateOverCellularPermission">
- <arg type="b" name="allowed" direction="in" />
- </method>
- <method name="SetUpdateOverCellularTarget">
- <arg type="s" name="target_version" direction="in" />
- <arg type="x" name="target_size" direction="in" />
- </method>
- <method name="GetUpdateOverCellularPermission">
- <arg type="b" name="allowed" direction="out" />
- </method>
- <method name="GetDurationSinceUpdate">
- <arg type="x" name="usec_wallclock" direction="out" />
- </method>
- <signal name="StatusUpdateAdvanced">
- <arg type="ay" name="status" direction="out">
- <tp:docstring>
- The current status serialized in a protobuf.
- </tp:docstring>
- <annotation name="org.chromium.DBus.Argument.ProtobufClass"
- value="update_engine::StatusResult"/>
- </arg>
- </signal>
- <method name="GetPrevVersion">
- <arg type="s" name="prev_version" direction="out" />
- </method>
- <method name="GetRollbackPartition">
- <arg type="s" name="rollback_partition_name" direction="out" />
- </method>
- <method name="GetLastAttemptError">
- <arg type="i" name="last_attempt_error" direction="out" />
- </method>
- </interface>
-</node>
diff --git a/download_action.cc b/download_action.cc
index 62a84230..03585691 100644
--- a/download_action.cc
+++ b/download_action.cc
@@ -41,14 +41,16 @@ DownloadAction::DownloadAction(PrefsInterface* prefs,
BootControlInterface* boot_control,
HardwareInterface* hardware,
HttpFetcher* http_fetcher,
- bool interactive)
+ bool interactive,
+ std::string update_certificates_path)
: prefs_(prefs),
boot_control_(boot_control),
hardware_(hardware),
http_fetcher_(new MultiRangeHttpFetcher(http_fetcher)),
interactive_(interactive),
code_(ErrorCode::kSuccess),
- delegate_(nullptr) {}
+ delegate_(nullptr),
+ update_certificates_path_(std::move(update_certificates_path)) {}
DownloadAction::~DownloadAction() {}
@@ -132,7 +134,8 @@ void DownloadAction::StartDownloading() {
delegate_,
&install_plan_,
payload_,
- interactive_));
+ interactive_,
+ update_certificates_path_));
}
if (install_plan_.is_resume &&
@@ -147,13 +150,15 @@ void DownloadAction::StartDownloading() {
if (!LoadCachedManifest(manifest_metadata_size + manifest_signature_size)) {
if (delta_performer_) {
// Create a new DeltaPerformer to reset all its state
- delta_performer_ = std::make_unique<DeltaPerformer>(prefs_,
- boot_control_,
- hardware_,
- delegate_,
- &install_plan_,
- payload_,
- interactive_);
+ delta_performer_ =
+ std::make_unique<DeltaPerformer>(prefs_,
+ boot_control_,
+ hardware_,
+ delegate_,
+ &install_plan_,
+ payload_,
+ interactive_,
+ update_certificates_path_);
}
http_fetcher_->AddRange(base_offset_,
manifest_metadata_size + manifest_signature_size);
diff --git a/download_action_android_unittest.cc b/download_action_android_unittest.cc
index fef2d24d..bef43424 100644
--- a/download_action_android_unittest.cc
+++ b/download_action_android_unittest.cc
@@ -33,6 +33,7 @@
#include "update_engine/common/mock_http_fetcher.h"
#include "update_engine/common/mock_prefs.h"
#include "update_engine/common/test_utils.h"
+#include "update_engine/common/testing_constants.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/payload_consumer/payload_constants.h"
@@ -46,9 +47,6 @@ using testing::DoAll;
using testing::Return;
using testing::SetArgPointee;
-extern const char* kUnittestPrivateKeyPath;
-extern const char* kUnittestPublicKeyPath;
-
class DownloadActionTest : public ::testing::Test {
public:
static constexpr int64_t METADATA_SIZE = 1024;
diff --git a/libcurl_http_fetcher_unittest.cc b/libcurl_http_fetcher_unittest.cc
index 5d675707..3543870b 100644
--- a/libcurl_http_fetcher_unittest.cc
+++ b/libcurl_http_fetcher_unittest.cc
@@ -31,8 +31,8 @@ using std::string;
namespace chromeos_update_engine {
namespace {
+
constexpr char kHeaderName[] = "X-Goog-Test-Header";
-}
class LibcurlHttpFetcherTest : public ::testing::Test {
protected:
@@ -48,6 +48,8 @@ class LibcurlHttpFetcherTest : public ::testing::Test {
UnresolvedHostStateMachine state_machine_;
};
+} // namespace
+
TEST_F(LibcurlHttpFetcherTest, GetEmptyHeaderValueTest) {
const string header_value = "";
string actual_header_value;
diff --git a/lz4diff/lz4diff.cc b/lz4diff/lz4diff.cc
new file mode 100644
index 00000000..25dce000
--- /dev/null
+++ b/lz4diff/lz4diff.cc
@@ -0,0 +1,247 @@
+//
+// Copyright (C) 2021 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 "lz4diff.h"
+#include "lz4diff_compress.h"
+
+#include <bsdiff/bsdiff.h>
+#include <bsdiff/constants.h>
+#include <bsdiff/patch_writer_factory.h>
+#include <bsdiff/patch_writer.h>
+#include <puffin/common.h>
+#include <puffin/puffdiff.h>
+#include <lz4.h>
+#include <lz4hc.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/payload_generator/deflate_utils.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "lz4diff/lz4diff.pb.h"
+#include "lz4diff_format.h"
+
+namespace chromeos_update_engine {
+
+bool StoreDstCompressedFileInfo(std::string_view recompressed_blob,
+ std::string_view target_blob,
+ const CompressedFile& dst_file_info,
+ Lz4diffHeader* output) {
+ *output->mutable_dst_info()->mutable_algo() = dst_file_info.algo;
+ output->mutable_dst_info()->set_zero_padding_enabled(
+ dst_file_info.zero_padding_enabled);
+ const auto& block_info = dst_file_info.blocks;
+ auto& dst_block_info = *output->mutable_dst_info()->mutable_block_info();
+ dst_block_info.Clear();
+ size_t offset = 0;
+ for (const auto& block : block_info) {
+ auto& pb_block = *dst_block_info.Add();
+ pb_block.set_uncompressed_offset(block.uncompressed_offset);
+ pb_block.set_uncompressed_length(block.uncompressed_length);
+ pb_block.set_compressed_length(block.compressed_length);
+ CHECK_LT(offset, recompressed_blob.size());
+ auto s1 = recompressed_blob.substr(offset, block.compressed_length);
+ auto s2 = target_blob.substr(offset, block.compressed_length);
+ if (s1 != s2) {
+ ScopedTempFile patch;
+ int err =
+ bsdiff::bsdiff(reinterpret_cast<const unsigned char*>(s1.data()),
+ s1.size(),
+ reinterpret_cast<const unsigned char*>(s2.data()),
+ s2.size(),
+ patch.path().c_str(),
+ nullptr);
+ CHECK_EQ(err, 0);
+ LOG(WARNING) << "Recompress Postfix patch size: "
+ << utils::FileSize(patch.path());
+ std::string patch_content;
+ TEST_AND_RETURN_FALSE(utils::ReadFile(patch.path(), &patch_content));
+ pb_block.set_postfix_bspatch(std::move(patch_content));
+ }
+ // Include recompressed blob hash, so we can determine if the device
+ // produces same compressed output
+ Blob recompressed_blob_hash;
+ TEST_AND_RETURN_FALSE(HashCalculator::RawHashOfBytes(
+ s1.data(), s1.length(), &recompressed_blob_hash));
+ pb_block.set_sha256_hash(recompressed_blob_hash.data(),
+ recompressed_blob_hash.size());
+
+ offset += block.compressed_length;
+ }
+ return true;
+}
+
+template <typename Blob>
+static bool TryBsdiff(Blob src, Blob dst, Blob* output) noexcept {
+ static constexpr auto kLz4diffDefaultBrotliQuality = 9;
+ CHECK_NE(output, nullptr);
+ ScopedTempFile patch;
+
+ Blob bsdiff_delta;
+ bsdiff::BsdiffPatchWriter patch_writer(patch.path(),
+ {bsdiff::CompressorType::kBrotli},
+ kLz4diffDefaultBrotliQuality);
+ TEST_AND_RETURN_FALSE(0 == bsdiff::bsdiff(src.data(),
+ src.size(),
+ dst.data(),
+ dst.size(),
+ &patch_writer,
+ nullptr));
+
+ TEST_AND_RETURN_FALSE(utils::ReadFile(patch.path(), &bsdiff_delta));
+ TEST_AND_RETURN_FALSE(!bsdiff_delta.empty());
+ *output = std::move(bsdiff_delta);
+ return true;
+}
+
+bool TryFindDeflates(puffin::Buffer data,
+ std::vector<puffin::BitExtent>* deflates) {
+ if (puffin::LocateDeflatesInZipArchive(data, deflates)) {
+ return true;
+ }
+ deflates->clear();
+ if (puffin::LocateDeflatesInGzip(data, deflates)) {
+ return true;
+ }
+ deflates->clear();
+ return false;
+}
+
+static bool ConstructLz4diffPatch(Blob inner_patch,
+ const Lz4diffHeader& header,
+ Blob* output) {
+ Blob patch(kLz4diffHeaderSize);
+ std::memcpy(patch.data(), kLz4diffMagic.data(), kLz4diffMagic.size());
+ *reinterpret_cast<uint32_t*>(patch.data() + kLz4diffMagic.size()) =
+ htobe32(kLz4diffVersion);
+
+ std::string serialized_pb;
+ TEST_AND_RETURN_FALSE(header.SerializeToString(&serialized_pb));
+ *reinterpret_cast<uint32_t*>(patch.data() + kLz4diffMagic.size() + 4) =
+ htobe32(serialized_pb.size());
+ patch.insert(patch.end(), serialized_pb.begin(), serialized_pb.end());
+ patch.insert(patch.end(), inner_patch.begin(), inner_patch.end());
+
+ *output = std::move(patch);
+ return true;
+}
+
+static bool TryPuffdiff(puffin::Buffer src,
+ puffin::Buffer dst,
+ Blob* output) noexcept {
+ CHECK_NE(output, nullptr);
+ std::vector<puffin::BitExtent> src_deflates;
+ TEST_AND_RETURN_FALSE(TryFindDeflates(src, &src_deflates));
+ std::vector<puffin::BitExtent> dst_deflates;
+ TEST_AND_RETURN_FALSE(TryFindDeflates(dst, &dst_deflates));
+ if (src_deflates.empty() || dst_deflates.empty()) {
+ return false;
+ }
+
+ Blob puffdiff_delta;
+ ScopedTempFile temp_file("puffdiff-delta.XXXXXX");
+ // Perform PuffDiff operation.
+ TEST_AND_RETURN_FALSE(puffin::PuffDiff(
+ src, dst, src_deflates, dst_deflates, temp_file.path(), &puffdiff_delta));
+ TEST_AND_RETURN_FALSE(!puffdiff_delta.empty());
+
+ *output = std::move(puffdiff_delta);
+ return true;
+}
+
+static void StoreSrcCompressedFileInfo(const CompressedFile& src_file_info,
+ Lz4diffHeader* header) {
+ *header->mutable_src_info()->mutable_algo() = src_file_info.algo;
+ header->mutable_src_info()->set_zero_padding_enabled(
+ src_file_info.zero_padding_enabled);
+ auto& src_blocks = *header->mutable_src_info()->mutable_block_info();
+ src_blocks.Clear();
+ for (const auto& block : src_file_info.blocks) {
+ auto& block_info = *src_blocks.Add();
+ block_info.set_uncompressed_length(block.uncompressed_length);
+ block_info.set_uncompressed_offset(block.uncompressed_offset);
+ block_info.set_compressed_length(block.compressed_length);
+ }
+ return;
+}
+
+bool Lz4Diff(std::string_view src,
+ std::string_view dst,
+ const CompressedFile& src_file_info,
+ const CompressedFile& dst_file_info,
+ Blob* output,
+ InstallOperation::Type* op_type) noexcept {
+ const auto& src_block_info = src_file_info.blocks;
+ const auto& dst_block_info = dst_file_info.blocks;
+
+ auto decompressed_src = TryDecompressBlob(
+ src, src_block_info, src_file_info.zero_padding_enabled);
+ auto decompressed_dst = TryDecompressBlob(
+ dst, dst_block_info, dst_file_info.zero_padding_enabled);
+ if (decompressed_src.empty() || decompressed_dst.empty()) {
+ LOG(ERROR) << "Failed to decompress input data";
+ return false;
+ }
+
+ Lz4diffHeader header;
+ // BSDIFF isn't supposed to fail, so return error if BSDIFF failed.
+ Blob patch_data;
+ TEST_AND_RETURN_FALSE(
+ TryBsdiff(decompressed_src, decompressed_dst, &patch_data));
+ header.set_inner_type(InnerPatchType::BSDIFF);
+ if (op_type) {
+ *op_type = InstallOperation::LZ4DIFF_BSDIFF;
+ }
+ // PUFFDIFF might fail, as the input data might not be deflate compressed.
+
+ Blob puffdiff_delta;
+ if (TryPuffdiff(decompressed_src, decompressed_dst, &puffdiff_delta) &&
+ puffdiff_delta.size() < patch_data.size()) {
+ patch_data = std::move(puffdiff_delta);
+ header.set_inner_type(InnerPatchType::PUFFDIFF);
+ if (op_type) {
+ *op_type = InstallOperation::LZ4DIFF_PUFFDIFF;
+ }
+ }
+ // Free up memory used by |decompressed_src| , as we don't need it anymore.
+ decompressed_src = {};
+
+ auto recompressed_blob = TryCompressBlob(ToStringView(decompressed_dst),
+ dst_block_info,
+ dst_file_info.zero_padding_enabled,
+ dst_file_info.algo);
+ TEST_AND_RETURN_FALSE(recompressed_blob.size() > 0);
+
+ StoreSrcCompressedFileInfo(src_file_info, &header);
+ StoreDstCompressedFileInfo(
+ ToStringView(recompressed_blob), dst, dst_file_info, &header);
+ return ConstructLz4diffPatch(std::move(patch_data), header, output);
+}
+
+bool Lz4Diff(const Blob& src,
+ const Blob& dst,
+ const CompressedFile& src_file_info,
+ const CompressedFile& dst_file_info,
+ Blob* output,
+ InstallOperation::Type* op_type) noexcept {
+ return Lz4Diff(ToStringView(src),
+ ToStringView(dst),
+ src_file_info,
+ dst_file_info,
+ output,
+ op_type);
+}
+
+} // namespace chromeos_update_engine
diff --git a/lz4diff/lz4diff.h b/lz4diff/lz4diff.h
new file mode 100644
index 00000000..92bdb107
--- /dev/null
+++ b/lz4diff/lz4diff.h
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2021 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_LZ4DIFF_LZ4DIFF_H_
+#define UPDATE_ENGINE_LZ4DIFF_LZ4DIFF_H_
+
+#include <vector>
+#include <string_view>
+
+#include "lz4diff/lz4diff.pb.h"
+#include "update_engine/lz4diff/lz4diff_format.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+bool Lz4Diff(std::string_view src,
+ std::string_view dst,
+ const CompressedFile& src_file_info,
+ const CompressedFile& dst_file_info,
+ Blob* output,
+ InstallOperation::Type* op_type = nullptr) noexcept;
+
+bool Lz4Diff(const Blob& src,
+ const Blob& dst,
+ const CompressedFile& src_file_info,
+ const CompressedFile& dst_file_info,
+ Blob* output,
+ InstallOperation::Type* op_type = nullptr) noexcept;
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/lz4diff/lz4diff.proto b/lz4diff/lz4diff.proto
new file mode 100644
index 00000000..f1a3a36e
--- /dev/null
+++ b/lz4diff/lz4diff.proto
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2021 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.
+//
+
+syntax = "proto3";
+
+package chromeos_update_engine;
+option optimize_for = LITE_RUNTIME;
+
+message CompressionAlgorithm {
+ enum Type {
+ UNCOMPRESSED = 0;
+ LZ4 = 1;
+ LZ4HC = 2;
+ }
+ Type type = 1;
+ int32 level = 2;
+}
+
+message CompressedBlockInfo {
+ // Require fields
+ uint64 uncompressed_offset = 1;
+ uint64 uncompressed_length = 2;
+ uint64 compressed_length = 3;
+
+ // optional SHA256 hash of re-compressed blob
+ bytes sha256_hash = 4;
+ // Patch to apply to re-compressed blob
+ bytes postfix_bspatch = 5;
+}
+
+enum InnerPatchType {
+ BSDIFF = 0;
+ PUFFDIFF = 1;
+}
+
+message CompressionInfo {
+ CompressionAlgorithm algo = 1;
+ repeated CompressedBlockInfo block_info = 2;
+ bool zero_padding_enabled = 3;
+}
+
+message Lz4diffHeader {
+ CompressionInfo src_info = 1;
+ CompressionInfo dst_info = 2;
+ InnerPatchType inner_type = 3;
+}
diff --git a/lz4diff/lz4diff_compress.cc b/lz4diff/lz4diff_compress.cc
new file mode 100644
index 00000000..ce9082c7
--- /dev/null
+++ b/lz4diff/lz4diff_compress.cc
@@ -0,0 +1,257 @@
+//
+// Copyright (C) 2021 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 "lz4diff_compress.h"
+
+#include "update_engine/common/utils.h"
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/payload_generation_config.h"
+
+#include <base/logging.h>
+#include <lz4.h>
+#include <lz4hc.h>
+
+namespace chromeos_update_engine {
+
+bool TryCompressBlob(std::string_view blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled,
+ const CompressionAlgorithm compression_algo,
+ const SinkFunc& sink) {
+ size_t uncompressed_size = 0;
+ for (const auto& block : block_info) {
+ CHECK_EQ(uncompressed_size, block.uncompressed_offset)
+ << "Compressed block info is expected to be sorted.";
+ uncompressed_size += block.uncompressed_length;
+ }
+ auto hc = LZ4_createStreamHC();
+ DEFER {
+ if (hc) {
+ LZ4_freeStreamHC(hc);
+ hc = nullptr;
+ }
+ };
+ size_t compressed_offset = 0;
+ Blob block_buffer;
+ for (const auto& block : block_info) {
+ const auto uncompressed_block =
+ blob.substr(block.uncompressed_offset, block.uncompressed_length);
+ if (!block.IsCompressed()) {
+ TEST_EQ(sink(reinterpret_cast<const uint8_t*>(uncompressed_block.data()),
+ uncompressed_block.size()),
+ uncompressed_block.size());
+ continue;
+ }
+ block_buffer.resize(block.compressed_length);
+ // Execute the increment at end of each loop
+ DEFER {
+ compressed_offset += block.compressed_length;
+ block_buffer.clear();
+ };
+
+ int ret = 0;
+ // LZ4 spec enforces that last op of a compressed block must be an insert op
+ // of at least 5 bytes. Compressors will try to conform to that requirement
+ // if the input size is just right. We don't want that. So always give a
+ // little bit more data.
+ switch (int src_size = uncompressed_size - block.uncompressed_offset;
+ compression_algo.type()) {
+ case CompressionAlgorithm::LZ4HC:
+ ret = LZ4_compress_HC_destSize(
+ hc,
+ uncompressed_block.data(),
+ reinterpret_cast<char*>(block_buffer.data()),
+ &src_size,
+ block.compressed_length,
+ compression_algo.level());
+ break;
+ case CompressionAlgorithm::LZ4:
+ ret =
+ LZ4_compress_destSize(uncompressed_block.data(),
+ reinterpret_cast<char*>(block_buffer.data()),
+ &src_size,
+ block.compressed_length);
+ break;
+ default:
+ LOG(ERROR) << "Unrecognized compression algorithm: "
+ << compression_algo.type();
+ return {};
+ }
+ TEST_GT(ret, 0);
+ const uint64_t bytes_written = ret;
+ // Last block may have trailing zeros
+ TEST_LE(bytes_written, block.compressed_length);
+ if (bytes_written < block.compressed_length) {
+ if (zero_padding_enabled) {
+ const auto padding = block.compressed_length - bytes_written;
+ std::memmove(
+ block_buffer.data() + padding, block_buffer.data(), bytes_written);
+ std::fill(block_buffer.data(), block_buffer.data() + padding, 0);
+
+ } else {
+ std::fill(block_buffer.data() + bytes_written,
+ block_buffer.data() + block.compressed_length,
+ 0);
+ }
+ }
+ TEST_EQ(sink(block_buffer.data(), block_buffer.size()),
+ block_buffer.size());
+ }
+ // Any trailing data will be copied to the output buffer.
+ TEST_EQ(
+ sink(reinterpret_cast<const uint8_t*>(blob.data()) + uncompressed_size,
+ blob.size() - uncompressed_size),
+ blob.size() - uncompressed_size);
+ return true;
+}
+
+Blob TryCompressBlob(std::string_view blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled,
+ const CompressionAlgorithm compression_algo) {
+ size_t uncompressed_size = 0;
+ size_t compressed_size = 0;
+ for (const auto& block : block_info) {
+ CHECK_EQ(uncompressed_size, block.uncompressed_offset)
+ << "Compressed block info is expected to be sorted.";
+ uncompressed_size += block.uncompressed_length;
+ compressed_size += block.compressed_length;
+ }
+ TEST_EQ(uncompressed_size, blob.size());
+ Blob output;
+ output.reserve(utils::RoundUp(compressed_size, kBlockSize));
+ if (!TryCompressBlob(blob,
+ block_info,
+ zero_padding_enabled,
+ compression_algo,
+ [&output](const uint8_t* data, size_t size) {
+ output.insert(output.end(), data, data + size);
+ return size;
+ })) {
+ return {};
+ }
+
+ return output;
+}
+
+Blob TryDecompressBlob(std::string_view blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled) {
+ if (block_info.empty()) {
+ return {};
+ }
+ size_t uncompressed_size = 0;
+ size_t compressed_size = 0;
+ for (const auto& block : block_info) {
+ CHECK_EQ(uncompressed_size, block.uncompressed_offset)
+ << " Compressed block info is expected to be sorted, expected offset "
+ << uncompressed_size << ", actual block " << block;
+ uncompressed_size += block.uncompressed_length;
+ compressed_size += block.compressed_length;
+ }
+ if (blob.size() < compressed_size) {
+ LOG(INFO) << "File is chunked. Skip lz4 decompress. Expected size: "
+ << compressed_size << ", actual size: " << blob.size();
+ return {};
+ }
+ Blob output;
+ output.reserve(uncompressed_size);
+ size_t compressed_offset = 0;
+ for (const auto& block : block_info) {
+ std::string_view cluster =
+ blob.substr(compressed_offset, block.compressed_length);
+ if (!block.IsCompressed()) {
+ CHECK_NE(cluster.size(), 0UL);
+ output.insert(output.end(), cluster.begin(), cluster.end());
+ compressed_offset += cluster.size();
+ continue;
+ }
+ size_t inputmargin = 0;
+ if (zero_padding_enabled) {
+ while (inputmargin < std::min(kBlockSize, cluster.size()) &&
+ cluster[inputmargin] == 0) {
+ inputmargin++;
+ }
+ }
+ output.resize(output.size() + block.uncompressed_length);
+
+ const auto bytes_decompressed = LZ4_decompress_safe_partial(
+ cluster.data() + inputmargin,
+ reinterpret_cast<char*>(output.data()) + output.size() -
+ block.uncompressed_length,
+ cluster.size() - inputmargin,
+ block.uncompressed_length,
+ block.uncompressed_length);
+ if (bytes_decompressed < 0) {
+ LOG(FATAL) << "Failed to decompress, " << bytes_decompressed
+ << ", output_cursor = "
+ << output.size() - block.uncompressed_length
+ << ", input_cursor = " << compressed_offset
+ << ", blob.size() = " << blob.size()
+ << ", cluster_size = " << block.compressed_length
+ << ", dest capacity = " << block.uncompressed_length
+ << ", input margin = " << inputmargin << " "
+ << HashCalculator::SHA256Digest(cluster) << " "
+ << HashCalculator::SHA256Digest(blob);
+ return {};
+ }
+ compressed_offset += block.compressed_length;
+ CHECK_EQ(static_cast<uint64_t>(bytes_decompressed),
+ block.uncompressed_length);
+ }
+ CHECK_EQ(output.size(), uncompressed_size);
+
+ // Trailing data not recorded by compressed block info will be treated as
+ // uncompressed, most of the time these are xattrs or trailing zeros.
+ CHECK_EQ(blob.size(), compressed_offset)
+ << " Unexpected data the end of compressed data ";
+ if (compressed_offset < blob.size()) {
+ output.insert(output.end(), blob.begin() + compressed_offset, blob.end());
+ }
+
+ return output;
+}
+
+Blob TryDecompressBlob(const Blob& blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled) {
+ return TryDecompressBlob(
+ ToStringView(blob), block_info, zero_padding_enabled);
+}
+
+std::ostream& operator<<(std::ostream& out, const CompressedBlock& block) {
+ out << "CompressedBlock{.uncompressed_offset = " << block.uncompressed_offset
+ << ", .compressed_length = " << block.compressed_length
+ << ", .uncompressed_length = " << block.uncompressed_length << "}";
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CompressedBlockInfo& info) {
+ out << "BlockInfo { compressed_length: " << info.compressed_length()
+ << ", uncompressed_length: " << info.uncompressed_length()
+ << ", uncompressed_offset: " << info.uncompressed_offset();
+ if (!info.sha256_hash().empty()) {
+ out << ", sha256_hash: " << HexEncode(info.sha256_hash());
+ }
+ if (!info.postfix_bspatch().empty()) {
+ out << ", postfix_bspatch: " << info.postfix_bspatch().size();
+ }
+ out << "}";
+ return out;
+}
+
+} // namespace chromeos_update_engine
diff --git a/lz4diff/lz4diff_compress.h b/lz4diff/lz4diff_compress.h
new file mode 100644
index 00000000..a1ac8fa9
--- /dev/null
+++ b/lz4diff/lz4diff_compress.h
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2021 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_LZ4DIFF_LZ4DIFF_COMPRESS_H_
+#define UPDATE_ENGINE_LZ4DIFF_LZ4DIFF_COMPRESS_H_
+
+#include "lz4diff_format.h"
+#include <string_view>
+
+namespace chromeos_update_engine {
+
+using SinkFunc = std::function<size_t(const uint8_t*, size_t)>;
+
+// |TryCompressBlob| and |TryDecompressBlob| are inverse function of each other.
+// One compresses data into fixed size output chunks, one decompresses fixed
+// size blocks.
+// The |TryCompressBlob| routine is supposed to mimic how EROFS compresses input
+// files when creating an EROFS image. After calling |TryCompressBlob|, LZ4DIFF
+// will compare the re-compressed blob and EROFS's ground truth blob, and
+// generate a BSDIFF patch between them if there's mismatch. Therefore, it is OK
+// that |TryCompressBlob| produces slightly different output than mkfs.erofs, so
+// as long as |TryCompressBlob| exhibits consistne bebavior across platforms.
+Blob TryCompressBlob(std::string_view blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled,
+ const CompressionAlgorithm compression_algo);
+bool TryCompressBlob(std::string_view blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled,
+ const CompressionAlgorithm compression_algo,
+ const SinkFunc& sink);
+
+Blob TryDecompressBlob(std::string_view blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled);
+Blob TryDecompressBlob(const Blob& blob,
+ const std::vector<CompressedBlock>& block_info,
+ const bool zero_padding_enabled);
+
+std::ostream& operator<<(std::ostream& out, const CompressedBlockInfo& info);
+
+std::ostream& operator<<(std::ostream& out, const CompressedBlock& block);
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/lz4diff/lz4diff_compress_unittest.cc b/lz4diff/lz4diff_compress_unittest.cc
new file mode 100644
index 00000000..b4b56d20
--- /dev/null
+++ b/lz4diff/lz4diff_compress_unittest.cc
@@ -0,0 +1,117 @@
+//
+// Copyright (C) 2021 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 <unistd.h>
+
+#include <algorithm>
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include <base/format_macros.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+#include <erofs/internal.h>
+#include <erofs/io.h>
+
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/lz4diff/lz4diff_compress.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/erofs_filesystem.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+using std::string;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+namespace {
+
+static void ExtractErofsImage(const char* erofs_image,
+ const char* inode_path,
+ Blob* output) {
+ // EROFS has plenty of global variable usage. Protect calls to EROFS APIs with
+ // global mutex.
+ // TODO(b/202784930) Replace erofs-utils with a cleaner and more C++ friendly
+ // library. (Or turn erofs-utils into one)
+ static std::mutex mutex;
+ std::lock_guard lock(mutex);
+ auto err = dev_open_ro(erofs_image);
+ ASSERT_EQ(err, 0);
+ DEFER { dev_close(); };
+
+ err = erofs_read_superblock();
+ ASSERT_EQ(err, 0);
+ struct erofs_inode inode;
+ err = erofs_ilookup(inode_path, &inode);
+ ASSERT_EQ(err, 0);
+ output->resize(inode.i_size);
+ err = erofs_pread(&inode,
+ reinterpret_cast<char*>(output->data()),
+ output->size(),
+ 0 /* offset */);
+ ASSERT_EQ(err, 0);
+}
+
+class Lz4diffCompressTest : public ::testing::Test {};
+
+using test_utils::GetBuildArtifactsPath;
+
+// This test parses the sample images generated during build time with the
+// "generate_image.sh" script. The expected conditions of each file in these
+// images is encoded in the file name, as defined in the mentioned script.
+TEST_F(Lz4diffCompressTest, ExtractElfBinary) {
+ const auto build_path = GetBuildArtifactsPath("gen/erofs.img");
+ auto fs = ErofsFilesystem::CreateFromFile(build_path);
+ ASSERT_NE(fs, nullptr);
+ ASSERT_EQ(kBlockSize, fs->GetBlockSize());
+
+ vector<ErofsFilesystem::File> files;
+ ASSERT_TRUE(fs->GetFiles(&files));
+
+ const auto it =
+ std::find_if(files.begin(), files.end(), [](const auto& file) {
+ return file.name == "/delta_generator";
+ });
+ ASSERT_NE(it, files.end())
+ << "There should be a delta_generator entry in gen/erofs.img. Is the "
+ "generate_test_erofs_imgages.sh script implemented wrong?";
+
+ const auto delta_generator = *it;
+ Blob expected_blob;
+ ASSERT_NO_FATAL_FAILURE(ExtractErofsImage(
+ build_path.c_str(), "/delta_generator", &expected_blob));
+ Blob compressed_blob;
+ ASSERT_TRUE(utils::ReadExtents(
+ build_path, delta_generator.extents, &compressed_blob, kBlockSize));
+ auto decompressed_blob = TryDecompressBlob(
+ compressed_blob,
+ delta_generator.compressed_file_info.blocks,
+ delta_generator.compressed_file_info.zero_padding_enabled);
+ ASSERT_GT(decompressed_blob.size(), 0UL);
+ ASSERT_GE(decompressed_blob.size(),
+ static_cast<size_t>(delta_generator.file_stat.st_size));
+ decompressed_blob.resize(delta_generator.file_stat.st_size);
+ ASSERT_EQ(decompressed_blob, expected_blob);
+}
+
+} // namespace
+
+} // namespace chromeos_update_engine
diff --git a/lz4diff/lz4diff_format.h b/lz4diff/lz4diff_format.h
new file mode 100644
index 00000000..9875c123
--- /dev/null
+++ b/lz4diff/lz4diff_format.h
@@ -0,0 +1,72 @@
+//
+// Copyright (C) 2021 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_LZ4DIFF_LZ4DIFF_FORMAT_H_
+#define UPDATE_ENGINE_LZ4DIFF_LZ4DIFF_FORMAT_H_
+
+#include <string_view>
+#include <vector>
+
+#include <lz4diff/lz4diff.pb.h>
+
+namespace chromeos_update_engine {
+
+using Blob = std::vector<unsigned char>;
+
+// Format of LZ4diff patch:
+// struct lz4diff_header {
+// char magic[8] = kLz4diffMagic;
+// uint32_t version;
+// uint32_t pb_header_size; // size of protobuf message
+// char pf_header[pb_header_size];
+// }
+
+constexpr std::string_view kLz4diffMagic = "LZ4DIFF";
+
+// 8 bytes magic + 4 bytes version + 4 bytes pb_header_size
+constexpr size_t kLz4diffHeaderSize = 8 + 4 + 4;
+
+constexpr uint32_t kLz4diffVersion = 1;
+
+struct CompressedBlock {
+ constexpr CompressedBlock() : CompressedBlock(0, 0, 0) {}
+ constexpr CompressedBlock(uint64_t offset,
+ uint64_t length,
+ uint64_t uncompressed_length)
+ : uncompressed_offset(offset),
+ compressed_length(length),
+ uncompressed_length(uncompressed_length) {}
+ constexpr bool IsCompressed() const noexcept {
+ return compressed_length < uncompressed_length;
+ }
+ uint64_t uncompressed_offset;
+ uint64_t compressed_length;
+ uint64_t uncompressed_length;
+};
+
+struct CompressedFile {
+ // Extents in this array should be in range [0, file_size]. It represents
+ // which bytes inside this file are compressed. Useful for compressed file
+ // systems like EROFS.
+ std::vector<CompressedBlock> blocks;
+ CompressionAlgorithm algo;
+ // Whether the EROFS zero padding feature is enabled
+ bool zero_padding_enabled{};
+};
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/lz4diff/lz4diff_main.cc b/lz4diff/lz4diff_main.cc
new file mode 100644
index 00000000..981c4316
--- /dev/null
+++ b/lz4diff/lz4diff_main.cc
@@ -0,0 +1,197 @@
+//
+// Copyright (C) 2021 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 "lz4diff.h"
+#include "lz4diff/lz4patch.h"
+#include "lz4diff_compress.h"
+#include "update_engine/payload_generator/filesystem_interface.h"
+#include "update_engine/payload_generator/erofs_filesystem.h"
+#include "update_engine/common/utils.h"
+
+using namespace chromeos_update_engine;
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out, const std::vector<T>& vec) {
+ if (vec.begin() == vec.end()) {
+ out << "{}";
+ return out;
+ }
+ out << "{";
+ auto begin = vec.begin();
+ out << *begin;
+ for (const auto& ext : Range{++begin, vec.end()}) {
+ out << ", " << ext;
+ }
+ out << "}";
+ return out;
+}
+
+enum Lz4DiffOp { DIFF, PATCH, TEST };
+
+int ExecuteLz4diff(const char* src_image_path,
+ const char* dst_image_path,
+ const FilesystemInterface::File& src_file,
+ const FilesystemInterface::File& dst_file,
+ const char* patch_file,
+ Lz4DiffOp op) {
+ brillo::Blob src_blob;
+ CHECK(utils::ReadExtents(
+ src_image_path, src_file.extents, &src_blob, kBlockSize));
+ brillo::Blob dst_blob;
+ CHECK(utils::ReadExtents(
+ dst_image_path, dst_file.extents, &dst_blob, kBlockSize));
+
+ brillo::Blob lz4diff_patch;
+ if (op == DIFF || op == TEST) {
+ Lz4Diff(src_blob,
+ dst_blob,
+ src_file.compressed_file_info,
+ dst_file.compressed_file_info,
+ &lz4diff_patch);
+ if (patch_file) {
+ CHECK(utils::WriteFile(
+ patch_file, lz4diff_patch.data(), lz4diff_patch.size()));
+ }
+ }
+ if (op == PATCH || op == TEST) {
+ utils::ReadFile(patch_file, &lz4diff_patch);
+ Blob actual_target;
+ CHECK(Lz4Patch(
+ ToStringView(src_blob), ToStringView(lz4diff_patch), &actual_target));
+ if (actual_target != dst_blob) {
+ LOG(ERROR) << "Final postfixed blob mismatch. " << src_file.name;
+ } else {
+ LOG(INFO) << "LZ4patch success. Final blob matches. " << src_file.name;
+ }
+ }
+ return 0;
+}
+
+int ExecuteLz4diffOp(const char* src_image_path,
+ const char* dst_image_path,
+ const char* inode_path,
+ const char* patch_file,
+ Lz4DiffOp op) {
+ auto src_fs = ErofsFilesystem::CreateFromFile(src_image_path);
+ CHECK_NE(src_fs, nullptr);
+ auto dst_fs = ErofsFilesystem::CreateFromFile(dst_image_path);
+ CHECK_NE(dst_fs, nullptr);
+ std::vector<FilesystemInterface::File> src_files;
+ CHECK(src_fs->GetFiles(&src_files));
+ std::vector<FilesystemInterface::File> dst_files;
+ CHECK(dst_fs->GetFiles(&dst_files));
+ ScopedTempFile temp_patch;
+ if (patch_file == nullptr && op == TEST) {
+ patch_file = temp_patch.path().c_str();
+ }
+ if (inode_path == nullptr) {
+ for (const auto& src_file : src_files) {
+ auto dst_file = std::find_if(
+ dst_files.begin(),
+ dst_files.end(),
+ [path(src_file.name)](auto&& file) { return file.name == path; });
+ int err = ExecuteLz4diff(
+ src_image_path, dst_image_path, src_file, *dst_file, patch_file, op);
+ if (err) {
+ return err;
+ }
+ }
+ return 0;
+ }
+ auto src_file = std::find_if(
+ src_files.begin(), src_files.end(), [inode_path](auto&& file) {
+ return file.name == inode_path;
+ });
+ if (src_file == src_files.end()) {
+ LOG(ERROR) << "Failed to find " << inode_path << " in EROFS image"
+ << src_image_path;
+ return 2;
+ }
+ auto dst_file = std::find_if(
+ dst_files.begin(), dst_files.end(), [inode_path](auto&& file) {
+ return file.name == inode_path;
+ });
+ if (dst_file == dst_files.end()) {
+ LOG(ERROR) << "Failed to find " << inode_path << " in EROFS image"
+ << dst_image_path;
+ return 3;
+ }
+ return ExecuteLz4diff(
+ src_image_path, dst_image_path, *src_file, *dst_file, patch_file, op);
+}
+
+int main(int argc, const char** argv) {
+ if (argc < 4) {
+ printf(
+ "Usage: %s <diff/patch/test> <src EROFS image> <dst EROFS image> "
+ "...args\n",
+ argv[0]);
+ return 2;
+ }
+ const char* src_image_path = argv[2];
+ const char* dst_image_path = argv[3];
+ auto src_fs = ErofsFilesystem::CreateFromFile(src_image_path);
+ CHECK_NE(src_fs, nullptr);
+ auto dst_fs = ErofsFilesystem::CreateFromFile(dst_image_path);
+ CHECK_NE(dst_fs, nullptr);
+ std::vector<FilesystemInterface::File> src_files;
+ CHECK(src_fs->GetFiles(&src_files));
+ std::vector<FilesystemInterface::File> dst_files;
+ CHECK(dst_fs->GetFiles(&dst_files));
+ std::string_view op = argv[1];
+ if (op == "diff") {
+ if (argc != 6 && argc != 5) {
+ printf(
+ "Usage: %s diff <path to src erofs image> <path to dst erofs imaeg> "
+ "<path "
+ "of file inside erofs image> [output path]\n",
+ argv[0]);
+ return 1;
+ }
+ const char* path = argv[4];
+ const char* patch_file = argc == 6 ? argv[5] : nullptr;
+ return ExecuteLz4diffOp(
+ src_image_path, dst_image_path, path, patch_file, DIFF);
+ } else if (op == "patch") {
+ if (argc != 6 && argc != 7) {
+ printf(
+ "Usage: %s patch <path to src erofs image> <path to dst erofs imaeg> "
+ "<path "
+ "of file inside erofs image> <patch file>\n",
+ argv[0]);
+ return 3;
+ }
+ const char* inode_path = argv[4];
+ const char* patch_file = argv[5];
+ return ExecuteLz4diffOp(
+ src_image_path, dst_image_path, inode_path, patch_file, PATCH);
+ } else if (op == "test") {
+ if (argc != 4) {
+ printf(
+ "Usage: %s test <path to src erofs image> <path to dst erofs imaeg> "
+ "\n",
+ argv[0]);
+ return 4;
+ }
+ return ExecuteLz4diffOp(
+ src_image_path, dst_image_path, nullptr, nullptr, TEST);
+ } else {
+ LOG(ERROR) << "Unrecognized op " << op;
+ return 4;
+ }
+
+ return 0;
+} \ No newline at end of file
diff --git a/lz4diff/lz4diff_unittest.cc b/lz4diff/lz4diff_unittest.cc
new file mode 100644
index 00000000..aabff994
--- /dev/null
+++ b/lz4diff/lz4diff_unittest.cc
@@ -0,0 +1,110 @@
+//
+// Copyright (C) 2021 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 <unistd.h>
+
+#include <algorithm>
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include <base/format_macros.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+#include <erofs/internal.h>
+#include <erofs/io.h>
+
+#include "lz4diff/lz4diff.h"
+#include "lz4diff/lz4patch.h"
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/lz4diff/lz4diff_compress.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/erofs_filesystem.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+using std::string;
+using std::vector;
+
+namespace chromeos_update_engine {
+
+namespace {
+class Lz4diffTest : public ::testing::Test {};
+
+using test_utils::GetBuildArtifactsPath;
+
+// This test parses the sample images generated during build time with the
+// "generate_image.sh" script. The expected conditions of each file in these
+// images is encoded in the file name, as defined in the mentioned script.
+TEST_F(Lz4diffTest, DiffElfBinary) {
+ const auto old_img = GetBuildArtifactsPath("gen/erofs.img");
+ const auto new_img = GetBuildArtifactsPath("gen/erofs_new.img");
+ auto old_fs = ErofsFilesystem::CreateFromFile(old_img);
+ ASSERT_NE(old_fs, nullptr);
+ ASSERT_EQ(kBlockSize, old_fs->GetBlockSize());
+ auto new_fs = ErofsFilesystem::CreateFromFile(new_img);
+ ASSERT_NE(new_fs, nullptr);
+ ASSERT_EQ(kBlockSize, new_fs->GetBlockSize());
+
+ vector<ErofsFilesystem::File> old_files;
+ ASSERT_TRUE(old_fs->GetFiles(&old_files));
+ vector<ErofsFilesystem::File> new_files;
+ ASSERT_TRUE(new_fs->GetFiles(&new_files));
+
+ const auto it =
+ std::find_if(old_files.begin(), old_files.end(), [](const auto& file) {
+ return file.name == "/delta_generator";
+ });
+ ASSERT_NE(it, old_files.end())
+ << "There should be a delta_generator entry in gen/erofs.img. Is the "
+ "generate_test_erofs_imgages.sh script implemented wrong?";
+ const auto new_it =
+ std::find_if(new_files.begin(), new_files.end(), [](const auto& file) {
+ return file.name == "/delta_generator";
+ });
+ ASSERT_NE(new_it, new_files.end())
+ << "There should be a delta_generator entry in gen/erofs_new.img. Is the "
+ "generate_test_erofs_imgages.sh script implemented wrong?";
+
+ const auto old_delta_generator = *it;
+ auto new_delta_generator = *new_it;
+ Blob old_data;
+ ASSERT_TRUE(utils::ReadExtents(
+ old_img, old_delta_generator.extents, &old_data, kBlockSize));
+ Blob new_data;
+ ASSERT_TRUE(utils::ReadExtents(
+ new_img, new_delta_generator.extents, &new_data, kBlockSize));
+ // New image is actually generated with compression level 7, we use a
+ // different compression level so that recompressed blob is different. This
+ // way we can test the postfix functionality.
+ new_delta_generator.compressed_file_info.algo.set_level(5);
+ Blob diff_blob;
+ ASSERT_TRUE(Lz4Diff(old_data,
+ new_data,
+ old_delta_generator.compressed_file_info,
+ new_delta_generator.compressed_file_info,
+ &diff_blob));
+ Blob patched_new_data;
+ ASSERT_TRUE(Lz4Patch(old_data, diff_blob, &patched_new_data));
+ ASSERT_EQ(patched_new_data, new_data);
+}
+
+} // namespace
+
+} // namespace chromeos_update_engine
diff --git a/lz4diff/lz4patch.cc b/lz4diff/lz4patch.cc
new file mode 100644
index 00000000..9de6d580
--- /dev/null
+++ b/lz4diff/lz4patch.cc
@@ -0,0 +1,370 @@
+//
+// Copyright (C) 2021 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 "lz4patch.h"
+
+#include <endian.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <algorithm>
+#include <string_view>
+
+#include <bsdiff/bspatch.h>
+#include <bsdiff/memory_file.h>
+#include <bsdiff/file.h>
+#include <puffin/memory_stream.h>
+
+#include "android-base/strings.h"
+#include "lz4diff/lz4diff.h"
+#include "lz4diff/lz4diff.pb.h"
+#include "lz4diff_compress.h"
+#include "lz4diff_format.h"
+#include "puffin/puffpatch.h"
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/common/utils.h"
+
+namespace chromeos_update_engine {
+
+namespace {
+
+template <typename T>
+constexpr void BigEndianToHost(T& t) {
+ static_assert(std::is_integral_v<T>);
+ static_assert(sizeof(t) == 4 || sizeof(t) == 8 || sizeof(t) == 2);
+ if constexpr (sizeof(t) == 4) {
+ t = be32toh(t);
+ } else if constexpr (sizeof(t) == 8) {
+ t = be64toh(t);
+ } else if constexpr (sizeof(t) == 2) {
+ t = be16toh(t);
+ }
+}
+
+// In memory representation of an LZ4Diff patch, it's not marked as packed
+// because parsing isn't as simple as reinterpret_cast<> any way.
+struct Lz4diffPatch {
+ char magic[kLz4diffMagic.size()];
+ uint32_t version;
+ uint32_t pb_header_size; // size of protobuf message
+ Lz4diffHeader pb_header;
+ std::string_view inner_patch;
+};
+
+// Utility class to interact with puffin API. C++ does not have standard
+// Read/Write trait. So everybody invent their own file descriptor wrapper.
+class StringViewStream : public puffin::StreamInterface {
+ public:
+ ~StringViewStream() override = default;
+
+ bool GetSize(uint64_t* size) const override {
+ *size = read_memory_.size();
+ return true;
+ }
+
+ bool GetOffset(uint64_t* offset) const override {
+ *offset = offset_;
+ return true;
+ }
+
+ bool Seek(uint64_t offset) override {
+ TEST_AND_RETURN_FALSE(open_);
+ uint64_t size;
+ GetSize(&size);
+ TEST_AND_RETURN_FALSE(offset <= size);
+ offset_ = offset;
+ return true;
+ }
+
+ bool Read(void* buffer, size_t length) override {
+ TEST_AND_RETURN_FALSE(open_);
+ TEST_AND_RETURN_FALSE(offset_ + length <= read_memory_.size());
+ memcpy(buffer, read_memory_.data() + offset_, length);
+ offset_ += length;
+ return true;
+ }
+
+ bool Write(const void* buffer, size_t length) override {
+ LOG(ERROR) << "Unsupported operation " << __FUNCTION__;
+ return false;
+ }
+
+ bool Close() override {
+ open_ = false;
+ return true;
+ }
+
+ constexpr StringViewStream(std::string_view read_memory)
+ : read_memory_(read_memory) {
+ CHECK(!read_memory.empty());
+ }
+
+ private:
+ // The memory buffer for reading.
+ std::string_view read_memory_;
+
+ // The current offset.
+ uint64_t offset_{};
+ bool open_{true};
+};
+
+bool ParseLz4DifffPatch(std::string_view patch_data, Lz4diffPatch* output) {
+ CHECK_NE(output, nullptr);
+ if (!android::base::StartsWith(patch_data, kLz4diffMagic)) {
+ LOG(ERROR) << "Invalid lz4diff magic: "
+ << HexEncode(patch_data.substr(0, kLz4diffMagic.size()))
+ << ", expected: " << HexEncode(kLz4diffMagic);
+ return false;
+ }
+ Lz4diffPatch& patch = *output;
+ std::memcpy(patch.magic, patch_data.data(), kLz4diffMagic.size());
+ std::memcpy(&patch.version,
+ patch_data.data() + kLz4diffMagic.size(),
+ sizeof(patch.version));
+ BigEndianToHost(patch.version);
+ if (patch.version != kLz4diffVersion) {
+ LOG(ERROR) << "Unsupported lz4diff version: " << patch.version
+ << ", supported version: " << kLz4diffVersion;
+ return false;
+ }
+ std::memcpy(&patch.pb_header_size,
+ patch_data.data() + kLz4diffMagic.size() + sizeof(patch.version),
+ sizeof(patch.pb_header_size));
+ BigEndianToHost(patch.pb_header_size);
+ TEST_AND_RETURN_FALSE(patch.pb_header.ParseFromArray(
+ patch_data.data() + kLz4diffHeaderSize, patch.pb_header_size));
+ patch.inner_patch =
+ patch_data.substr(kLz4diffHeaderSize + patch.pb_header_size);
+ return true;
+}
+
+bool bspatch(std::string_view input_data,
+ std::string_view patch_data,
+ Blob* output) {
+ CHECK_NE(output, nullptr);
+ output->clear();
+ CHECK_GT(patch_data.size(), 0UL);
+ int err =
+ bsdiff::bspatch(reinterpret_cast<const uint8_t*>(input_data.data()),
+ input_data.size(),
+ reinterpret_cast<const uint8_t*>(patch_data.data()),
+ patch_data.size(),
+ [output](const uint8_t* data, size_t size) -> size_t {
+ output->insert(output->end(), data, data + size);
+ return size;
+ });
+ return err == 0;
+}
+
+bool puffpatch(std::string_view input_data,
+ std::string_view patch_data,
+ Blob* output) {
+ return puffin::PuffPatch(std::make_unique<StringViewStream>(input_data),
+ puffin::MemoryStream::CreateForWrite(output),
+ reinterpret_cast<const uint8_t*>(patch_data.data()),
+ patch_data.size());
+}
+
+std::vector<CompressedBlock> ToCompressedBlockVec(
+ const google::protobuf::RepeatedPtrField<CompressedBlockInfo>& rpf) {
+ std::vector<CompressedBlock> ret;
+ ret.reserve(rpf.size());
+ for (const auto& block : rpf) {
+ auto& info = ret.emplace_back();
+ info.compressed_length = block.compressed_length();
+ info.uncompressed_length = block.uncompressed_length();
+ info.uncompressed_offset = block.uncompressed_offset();
+ }
+ return ret;
+}
+
+bool HasPosfixPatches(const Lz4diffPatch& patch) {
+ for (const auto& info : patch.pb_header.dst_info().block_info()) {
+ if (!info.postfix_bspatch().empty()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+size_t GetCompressedSize(
+ const google::protobuf::RepeatedPtrField<CompressedBlockInfo>& info) {
+ size_t compressed_size = 0;
+ for (const auto& block : info) {
+ compressed_size += block.compressed_length();
+ }
+ return compressed_size;
+}
+
+size_t GetDecompressedSize(
+ const google::protobuf::RepeatedPtrField<CompressedBlockInfo>& info) {
+ size_t decompressed_size = 0;
+ for (const auto& block : info) {
+ decompressed_size += block.uncompressed_length();
+ }
+ return decompressed_size;
+}
+
+bool ApplyInnerPatch(Blob decompressed_src,
+ const Lz4diffPatch& patch,
+ Blob* decompressed_dst) {
+ switch (patch.pb_header.inner_type()) {
+ case InnerPatchType::BSDIFF:
+ TEST_AND_RETURN_FALSE(bspatch(
+ ToStringView(decompressed_src), patch.inner_patch, decompressed_dst));
+ break;
+ case InnerPatchType::PUFFDIFF:
+ TEST_AND_RETURN_FALSE(puffpatch(
+ ToStringView(decompressed_src), patch.inner_patch, decompressed_dst));
+ break;
+ default:
+ LOG(ERROR) << "Unsupported patch type: " << patch.pb_header.inner_type();
+ return false;
+ }
+ return true;
+}
+
+// TODO(zhangkelvin) Rewrite this in C++ 20 coroutine once that's available.
+// Hand coding CPS is not fun.
+bool Lz4Patch(std::string_view src_data,
+ const Lz4diffPatch& patch,
+ const SinkFunc& sink) {
+ auto decompressed_src = TryDecompressBlob(
+ src_data,
+ ToCompressedBlockVec(patch.pb_header.src_info().block_info()),
+ patch.pb_header.src_info().zero_padding_enabled());
+ TEST_AND_RETURN_FALSE(!decompressed_src.empty());
+ Blob decompressed_dst;
+ const auto decompressed_dst_size =
+ GetDecompressedSize(patch.pb_header.dst_info().block_info());
+ decompressed_dst.reserve(decompressed_dst_size);
+
+ ApplyInnerPatch(std::move(decompressed_src), patch, &decompressed_dst);
+
+ if (!HasPosfixPatches(patch)) {
+ return TryCompressBlob(
+ ToStringView(decompressed_dst),
+ ToCompressedBlockVec(patch.pb_header.dst_info().block_info()),
+ patch.pb_header.dst_info().zero_padding_enabled(),
+ patch.pb_header.dst_info().algo(),
+ sink);
+ }
+ auto postfix_patcher =
+ [&sink,
+ block_idx = 0,
+ &dst_block_info = patch.pb_header.dst_info().block_info()](
+ const uint8_t* data, size_t size) mutable -> size_t {
+ if (block_idx >= dst_block_info.size()) {
+ return sink(data, size);
+ }
+ const auto& block_info = dst_block_info[block_idx];
+ TEST_EQ(size, block_info.compressed_length());
+ DEFER { block_idx++; };
+ if (block_info.postfix_bspatch().empty()) {
+ return sink(data, size);
+ }
+ if (!block_info.sha256_hash().empty()) {
+ Blob actual_hash;
+ TEST_AND_RETURN_FALSE(
+ HashCalculator::RawHashOfBytes(data, size, &actual_hash));
+ if (ToStringView(actual_hash) != block_info.sha256_hash()) {
+ LOG(ERROR) << "Block " << block_info
+ << " is corrupted. This usually means the patch generator "
+ "used a different version of LZ4, or an incompatible LZ4 "
+ "patch generator was used, or LZ4 produces different "
+ "output on different platforms. Expected hash: "
+ << HexEncode(block_info.sha256_hash())
+ << ", actual hash: " << HexEncode(actual_hash);
+ return 0;
+ }
+ }
+ Blob fixed_block;
+ TEST_AND_RETURN_FALSE(
+ bspatch(std::string_view(reinterpret_cast<const char*>(data), size),
+ block_info.postfix_bspatch(),
+ &fixed_block));
+ return sink(fixed_block.data(), fixed_block.size());
+ };
+
+ return TryCompressBlob(
+ ToStringView(decompressed_dst),
+ ToCompressedBlockVec(patch.pb_header.dst_info().block_info()),
+ patch.pb_header.dst_info().zero_padding_enabled(),
+ patch.pb_header.dst_info().algo(),
+ postfix_patcher);
+}
+
+bool Lz4Patch(std::string_view src_data,
+ const Lz4diffPatch& patch,
+ Blob* output) {
+ Blob blob;
+ const auto output_size =
+ GetCompressedSize(patch.pb_header.dst_info().block_info());
+ blob.reserve(output_size);
+ TEST_AND_RETURN_FALSE(Lz4Patch(
+ src_data, patch, [&blob](const uint8_t* data, size_t size) -> size_t {
+ blob.insert(blob.end(), data, data + size);
+ return size;
+ }));
+ *output = std::move(blob);
+ return true;
+}
+
+} // namespace
+
+bool Lz4Patch(std::string_view src_data,
+ std::string_view patch_data,
+ Blob* output) {
+ Lz4diffPatch patch;
+ TEST_AND_RETURN_FALSE(ParseLz4DifffPatch(patch_data, &patch));
+ return Lz4Patch(src_data, patch, output);
+}
+
+bool Lz4Patch(std::string_view src_data,
+ std::string_view patch_data,
+ const SinkFunc& sink) {
+ Lz4diffPatch patch;
+ TEST_AND_RETURN_FALSE(ParseLz4DifffPatch(patch_data, &patch));
+ return Lz4Patch(src_data, patch, sink);
+}
+
+bool Lz4Patch(const Blob& src_data, const Blob& patch_data, Blob* output) {
+ return Lz4Patch(ToStringView(src_data), ToStringView(patch_data), output);
+}
+
+std::ostream& operator<<(std::ostream& out, const CompressionAlgorithm& info) {
+ out << "Algo {type: " << info.Type_Name(info.type());
+ if (info.level() != 0) {
+ out << ", level: " << info.level();
+ }
+ out << "}";
+
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const CompressionInfo& info) {
+ out << "CompressionInfo {block_info: " << info.block_info()
+ << ", algo: " << info.algo() << "}";
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const Lz4diffHeader& header) {
+ out << "Lz4diffHeader {src_info: " << header.src_info()
+ << ", dst_info: " << header.dst_info() << "}";
+ return out;
+}
+
+} // namespace chromeos_update_engine
diff --git a/lz4diff/lz4patch.h b/lz4diff/lz4patch.h
new file mode 100644
index 00000000..8b99c23b
--- /dev/null
+++ b/lz4diff/lz4patch.h
@@ -0,0 +1,59 @@
+//
+// Copyright (C) 2021 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_LZ4DIFF_LZ4PATCH_H_
+#define UPDATE_ENGINE_LZ4DIFF_LZ4PATCH_H_
+
+#include "lz4diff/lz4diff_compress.h"
+#include "lz4diff_format.h"
+
+namespace chromeos_update_engine {
+
+bool Lz4Patch(std::string_view src_data,
+ std::string_view patch_data,
+ const SinkFunc& sink);
+
+bool Lz4Patch(std::string_view src_data,
+ std::string_view patch_data,
+ Blob* output);
+bool Lz4Patch(const Blob& src_data, const Blob& patch_data, Blob* output);
+
+std::ostream& operator<<(std::ostream& out, const CompressionAlgorithm& info);
+
+std::ostream& operator<<(std::ostream& out, const Lz4diffHeader&);
+
+template <typename T>
+std::ostream& operator<<(std::ostream& out,
+ const google::protobuf::RepeatedPtrField<T>& arr) {
+ if (arr.empty()) {
+ out << "[]";
+ return out;
+ }
+ out << "[";
+ auto begin = arr.begin();
+ out << *begin;
+ ++begin;
+ for (; begin != arr.end(); ++begin) {
+ out << ", " << *begin;
+ }
+ out << "]";
+
+ return out;
+}
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/metrics_utils.cc b/metrics_utils.cc
index 34da5a1a..ec35fe22 100644
--- a/metrics_utils.cc
+++ b/metrics_utils.cc
@@ -294,7 +294,7 @@ metrics::ConnectionType GetConnectionType(ConnectionType type,
return metrics::ConnectionType::kUnknown;
}
-int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs) {
+int64_t GetPersistedValue(std::string_view key, PrefsInterface* prefs) {
CHECK(prefs);
if (!prefs->Exists(key))
return 0;
@@ -363,10 +363,12 @@ bool LoadAndReportTimeToReboot(MetricsReporterInterface* metrics_reporter,
return false;
Time system_updated_at = Time::FromInternalValue(stored_value);
- TimeDelta time_to_reboot = clock->GetMonotonicTime() - system_updated_at;
+ const auto current_time = clock->GetMonotonicTime();
+ TimeDelta time_to_reboot = current_time - system_updated_at;
if (time_to_reboot.ToInternalValue() < 0) {
- LOG(ERROR) << "time_to_reboot is negative - system_updated_at: "
- << utils::ToString(system_updated_at);
+ LOG(WARNING) << "time_to_reboot is negative - system_updated_at: "
+ << utils::ToString(system_updated_at) << " current time: "
+ << utils::ToString(current_time);
return false;
}
metrics_reporter->ReportTimeToReboot(time_to_reboot.InMinutes());
diff --git a/metrics_utils.h b/metrics_utils.h
index 3aac4e5b..16e9eec9 100644
--- a/metrics_utils.h
+++ b/metrics_utils.h
@@ -50,7 +50,7 @@ metrics::ConnectionType GetConnectionType(ConnectionType type,
// Returns the persisted value from prefs for the given key. It also
// validates that the value returned is non-negative.
-int64_t GetPersistedValue(const std::string& key, PrefsInterface* prefs);
+int64_t GetPersistedValue(std::string_view key, PrefsInterface* prefs);
// Persists the reboot count of the update attempt to |kPrefsNumReboots|.
void SetNumReboots(int64_t num_reboots, PrefsInterface* prefs);
diff --git a/payload_consumer/block_extent_writer.cc b/payload_consumer/block_extent_writer.cc
new file mode 100644
index 00000000..055b4850
--- /dev/null
+++ b/payload_consumer/block_extent_writer.cc
@@ -0,0 +1,116 @@
+//
+// Copyright (C) 2021 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/payload_consumer/block_extent_writer.h"
+
+#include <algorithm>
+#include <cstdint>
+
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+bool BlockExtentWriter::Init(
+ const google::protobuf::RepeatedPtrField<Extent>& extents,
+ uint32_t block_size) {
+ TEST_NE(extents.size(), 0);
+ extents_ = extents;
+ cur_extent_idx_ = 0;
+ buffer_.clear();
+ buffer_.reserve(block_size);
+ block_size_ = block_size;
+ return true;
+}
+
+size_t BlockExtentWriter::ConsumeWithBuffer(const uint8_t* data, size_t count) {
+ CHECK_LT(cur_extent_idx_, static_cast<size_t>(extents_.size()));
+ const auto& cur_extent = extents_[cur_extent_idx_];
+ const auto cur_extent_size = cur_extent.num_blocks() * block_size_;
+
+ if (buffer_.empty() && count >= cur_extent_size) {
+ if (!WriteExtent(data, cur_extent, block_size_)) {
+ LOG(ERROR) << "WriteExtent(" << cur_extent.start_block() << ", "
+ << static_cast<const void*>(data) << ", " << cur_extent_size
+ << ") failed.";
+ // return value is expected to be greater than 0. Return 0 to signal error
+ // condition
+ return 0;
+ }
+ if (!NextExtent()) {
+ if (count != cur_extent_size) {
+ LOG(ERROR) << "Exhausted all blocks, but still have "
+ << count - cur_extent_size << " bytes left";
+ return 0;
+ }
+ }
+ return cur_extent_size;
+ }
+ if (buffer_.size() >= cur_extent_size) {
+ LOG(ERROR)
+ << "Data left in buffer should never be >= cur_extent_size, otherwise "
+ "we should have send that data to CowWriter. Buffer size: "
+ << buffer_.size() << " current extent size: " << cur_extent_size;
+ }
+ const size_t bytes_to_copy =
+ std::min<size_t>(count, cur_extent_size - buffer_.size());
+ TEST_GT(bytes_to_copy, 0U);
+
+ buffer_.insert(buffer_.end(), data, data + bytes_to_copy);
+ TEST_LE(buffer_.size(), cur_extent_size);
+
+ if (buffer_.size() == cur_extent_size) {
+ if (!WriteExtent(buffer_.data(), cur_extent, block_size_)) {
+ LOG(ERROR) << "WriteExtent(" << buffer_.data() << ", "
+ << cur_extent.start_block() << ", " << cur_extent.num_blocks()
+ << ") failed.";
+ return 0;
+ }
+ buffer_.clear();
+ if (!NextExtent()) {
+ if (count != bytes_to_copy) {
+ LOG(ERROR) << "Exhausted all blocks, but still have "
+ << count - bytes_to_copy << " bytes left";
+ }
+ }
+ }
+ return bytes_to_copy;
+}
+
+// Returns true on success.
+// This will construct a COW_REPLACE operation and forward it to CowWriter. It
+// is important that caller does not perform SOURCE_COPY operation on this
+// class, otherwise raw data will be stored. Caller should find ways to use
+// COW_COPY whenever possible.
+bool BlockExtentWriter::Write(const void* bytes, size_t count) {
+ if (count == 0) {
+ return true;
+ }
+
+ auto data = static_cast<const uint8_t*>(bytes);
+ while (count > 0) {
+ const auto bytes_written = ConsumeWithBuffer(data, count);
+ TEST_AND_RETURN_FALSE(bytes_written > 0);
+ data += bytes_written;
+ count -= bytes_written;
+ }
+ return true;
+}
+
+bool BlockExtentWriter::NextExtent() {
+ cur_extent_idx_++;
+ return cur_extent_idx_ < static_cast<size_t>(extents_.size());
+}
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/block_extent_writer.h b/payload_consumer/block_extent_writer.h
new file mode 100644
index 00000000..902e3e16
--- /dev/null
+++ b/payload_consumer/block_extent_writer.h
@@ -0,0 +1,60 @@
+//
+// Copyright (C) 2021 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_BLOCK_EXTENT_WRITER_H_
+#define UPDATE_ENGINE_BLOCK_EXTENT_WRITER_H_
+
+#include <cstdint>
+#include <vector>
+
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+// Cache data upto size of one extent before writing.
+class BlockExtentWriter : public chromeos_update_engine::ExtentWriter {
+ public:
+ BlockExtentWriter() = default;
+ ~BlockExtentWriter() = default;
+ // Returns true on success.
+ bool Init(const google::protobuf::RepeatedPtrField<Extent>& extents,
+ uint32_t block_size) override;
+ // Returns true on success.
+ bool Write(const void* bytes, size_t count) final;
+ // Write data for 1 extent. |bytes| will be a pointer which points to data of
+ // size |extent.num_blocks()*block_size|. |extent| is the current extent we
+ // are writing to.
+ virtual bool WriteExtent(const void* bytes,
+ const Extent& extent,
+ size_t block_size) = 0;
+ size_t BlockSize() const { return block_size_; }
+
+ private:
+ bool NextExtent();
+ [[nodiscard]] size_t ConsumeWithBuffer(const uint8_t* bytes, size_t count);
+ // It's a non-owning pointer, because PartitionWriter owns the CowWruter. This
+ // allows us to use a single instance of CowWriter for all operations applied
+ // to the same partition.
+ google::protobuf::RepeatedPtrField<Extent> extents_;
+ size_t cur_extent_idx_;
+ std::vector<uint8_t> buffer_;
+ size_t block_size_;
+};
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/bzip_extent_writer.cc b/payload_consumer/bzip_extent_writer.cc
index 26fdc5f4..94919643 100644
--- a/payload_consumer/bzip_extent_writer.cc
+++ b/payload_consumer/bzip_extent_writer.cc
@@ -78,8 +78,7 @@ bool BzipExtentWriter::Write(const void* bytes, size_t count) {
// Store unconsumed data (if any) in |input_buffer_|.
if (stream_.avail_in || !input_buffer_.empty()) {
- brillo::Blob new_input_buffer(input_end - stream_.avail_in, input_end);
- new_input_buffer.swap(input_buffer_);
+ input_buffer_.assign(input_end - stream_.avail_in, input_end);
}
return true;
diff --git a/payload_consumer/bzip_extent_writer_unittest.cc b/payload_consumer/bzip_extent_writer_unittest.cc
index c93545ab..9493f740 100644
--- a/payload_consumer/bzip_extent_writer_unittest.cc
+++ b/payload_consumer/bzip_extent_writer_unittest.cc
@@ -28,6 +28,7 @@
#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
using std::min;
using std::string;
@@ -35,10 +36,6 @@ using std::vector;
namespace chromeos_update_engine {
-namespace {
-const uint32_t kBlockSize = 4096;
-}
-
class BzipExtentWriterTest : public ::testing::Test {
protected:
void SetUp() override {
diff --git a/payload_consumer/cached_file_descriptor.cc b/payload_consumer/cached_file_descriptor.cc
index 7f2515e9..aa0dbcd3 100644
--- a/payload_consumer/cached_file_descriptor.cc
+++ b/payload_consumer/cached_file_descriptor.cc
@@ -26,7 +26,7 @@
namespace chromeos_update_engine {
-off64_t CachedFileDescriptor::Seek(off64_t offset, int whence) {
+off64_t CachedFileDescriptorBase::Seek(off64_t offset, int whence) {
// Only support SEEK_SET and SEEK_CUR. I think these two would be enough. If
// we want to support SEEK_END then we have to figure out the size of the
// underlying file descriptor each time and it may not be a very good idea.
@@ -40,7 +40,7 @@ off64_t CachedFileDescriptor::Seek(off64_t offset, int whence) {
return -1;
}
// Then we have to seek there.
- if (fd_->Seek(next_offset, SEEK_SET) < 0) {
+ if (GetFd()->Seek(next_offset, SEEK_SET) < 0) {
return -1;
}
offset_ = next_offset;
@@ -48,7 +48,7 @@ off64_t CachedFileDescriptor::Seek(off64_t offset, int whence) {
return offset_;
}
-ssize_t CachedFileDescriptor::Write(const void* buf, size_t count) {
+ssize_t CachedFileDescriptorBase::Write(const void* buf, size_t count) {
auto bytes = static_cast<const uint8_t*>(buf);
size_t total_bytes_wrote = 0;
while (total_bytes_wrote < count) {
@@ -72,19 +72,20 @@ ssize_t CachedFileDescriptor::Write(const void* buf, size_t count) {
return total_bytes_wrote;
}
-bool CachedFileDescriptor::Flush() {
- return FlushCache() && fd_->Flush();
+bool CachedFileDescriptorBase::Flush() {
+ return FlushCache() && GetFd()->Flush();
}
-bool CachedFileDescriptor::Close() {
+bool CachedFileDescriptorBase::Close() {
offset_ = 0;
- return FlushCache() && fd_->Close();
+ return FlushCache() && GetFd()->Close();
}
-bool CachedFileDescriptor::FlushCache() {
+bool CachedFileDescriptorBase::FlushCache() {
size_t begin = 0;
while (begin < bytes_cached_) {
- auto bytes_wrote = fd_->Write(cache_.data() + begin, bytes_cached_ - begin);
+ auto bytes_wrote =
+ GetFd()->Write(cache_.data() + begin, bytes_cached_ - begin);
if (bytes_wrote < 0) {
PLOG(ERROR) << "Failed to flush cached data!";
return false;
diff --git a/payload_consumer/cached_file_descriptor.h b/payload_consumer/cached_file_descriptor.h
index 28c48f70..1193455d 100644
--- a/payload_consumer/cached_file_descriptor.h
+++ b/payload_consumer/cached_file_descriptor.h
@@ -29,46 +29,66 @@
namespace chromeos_update_engine {
-class CachedFileDescriptor : public FileDescriptor {
+class CachedFileDescriptorBase : public FileDescriptor {
public:
- CachedFileDescriptor(FileDescriptorPtr fd, size_t cache_size) : fd_(fd) {
- cache_.resize(cache_size);
- }
- ~CachedFileDescriptor() override = default;
+ CachedFileDescriptorBase(size_t cache_size) : cache_(cache_size) {}
+ ~CachedFileDescriptorBase() override = default;
bool Open(const char* path, int flags, mode_t mode) override {
- return fd_->Open(path, flags, mode);
+ return GetFd()->Open(path, flags, mode);
}
bool Open(const char* path, int flags) override {
- return fd_->Open(path, flags);
+ return GetFd()->Open(path, flags);
}
ssize_t Read(void* buf, size_t count) override {
- return fd_->Read(buf, count);
+ return GetFd()->Read(buf, count);
}
ssize_t Write(const void* buf, size_t count) override;
off64_t Seek(off64_t offset, int whence) override;
- uint64_t BlockDevSize() override { return fd_->BlockDevSize(); }
+ uint64_t BlockDevSize() override { return GetFd()->BlockDevSize(); }
bool BlkIoctl(int request,
uint64_t start,
uint64_t length,
int* result) override {
- return fd_->BlkIoctl(request, start, length, result);
+ return GetFd()->BlkIoctl(request, start, length, result);
}
bool Flush() override;
bool Close() override;
- bool IsSettingErrno() override { return fd_->IsSettingErrno(); }
- bool IsOpen() override { return fd_->IsOpen(); }
+ bool IsSettingErrno() override { return GetFd()->IsSettingErrno(); }
+ bool IsOpen() override { return GetFd()->IsOpen(); }
+
+ protected:
+ virtual FileDescriptor* GetFd() = 0;
private:
// Internal flush without the need to call |fd_->Flush()|.
bool FlushCache();
- FileDescriptorPtr fd_;
brillo::Blob cache_;
size_t bytes_cached_{0};
off64_t offset_{0};
- DISALLOW_COPY_AND_ASSIGN(CachedFileDescriptor);
+ DISALLOW_COPY_AND_ASSIGN(CachedFileDescriptorBase);
+};
+
+class CachedFileDescriptor final : public CachedFileDescriptorBase {
+ public:
+ CachedFileDescriptor(FileDescriptorPtr fd, size_t cache_size)
+ : CachedFileDescriptorBase(cache_size), fd_(fd) {}
+
+ protected:
+ virtual FileDescriptor* GetFd() { return fd_.get(); }
+ FileDescriptorPtr fd_;
+};
+
+class UnownedCachedFileDescriptor final : public CachedFileDescriptorBase {
+ public:
+ UnownedCachedFileDescriptor(FileDescriptor* fd, size_t cache_size)
+ : CachedFileDescriptorBase(cache_size), fd_(fd) {}
+
+ protected:
+ virtual FileDescriptor* GetFd() { return fd_; }
+ FileDescriptor* fd_;
};
} // namespace chromeos_update_engine
diff --git a/payload_consumer/certificate_parser_android_unittest.cc b/payload_consumer/certificate_parser_android_unittest.cc
index e300414b..278f6263 100644
--- a/payload_consumer/certificate_parser_android_unittest.cc
+++ b/payload_consumer/certificate_parser_android_unittest.cc
@@ -23,13 +23,13 @@
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/test_utils.h"
+#include "update_engine/common/testing_constants.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/payload_verifier.h"
#include "update_engine/payload_generator/payload_signer.h"
namespace chromeos_update_engine {
-extern const char* kUnittestPrivateKeyPath;
const char* kUnittestOtacertsPath = "otacerts.zip";
TEST(CertificateParserAndroidTest, ParseZipArchive) {
diff --git a/payload_consumer/cow_writer_file_descriptor.cc b/payload_consumer/cow_writer_file_descriptor.cc
index 2de6664a..19fb545c 100644
--- a/payload_consumer/cow_writer_file_descriptor.cc
+++ b/payload_consumer/cow_writer_file_descriptor.cc
@@ -33,6 +33,14 @@ CowWriterFileDescriptor::CowWriterFileDescriptor(
CHECK_NE(cow_reader_, nullptr);
}
+CowWriterFileDescriptor::CowWriterFileDescriptor(
+ std::unique_ptr<android::snapshot::ISnapshotWriter> cow_writer,
+ std::unique_ptr<FileDescriptor> cow_reader)
+ : cow_writer_(std::move(cow_writer)), cow_reader_(std::move(cow_reader)) {
+ CHECK_NE(cow_writer_, nullptr);
+ CHECK_NE(cow_reader_, nullptr);
+}
+
bool CowWriterFileDescriptor::Open(const char* path, int flags, mode_t mode) {
LOG(ERROR) << "CowWriterFileDescriptor doesn't support Open()";
return false;
diff --git a/payload_consumer/cow_writer_file_descriptor.h b/payload_consumer/cow_writer_file_descriptor.h
index 5d9ffc64..fbf0a0da 100644
--- a/payload_consumer/cow_writer_file_descriptor.h
+++ b/payload_consumer/cow_writer_file_descriptor.h
@@ -30,6 +30,11 @@ class CowWriterFileDescriptor final : public FileDescriptor {
public:
explicit CowWriterFileDescriptor(
std::unique_ptr<android::snapshot::ISnapshotWriter> cow_writer);
+
+ // |cow_reader| should be obtained by calling |cow_writer->OpenReader()|
+ CowWriterFileDescriptor(
+ std::unique_ptr<android::snapshot::ISnapshotWriter> cow_writer,
+ std::unique_ptr<FileDescriptor> cow_reader);
~CowWriterFileDescriptor();
bool Open(const char* path, int flags, mode_t mode) override;
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index a57169b5..fc8858ff 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -32,8 +32,6 @@
#include <base/format_macros.h>
#include <base/metrics/histogram_macros.h>
#include <base/strings/string_number_conversions.h>
-#include <base/strings/string_util.h>
-#include <base/strings/stringprintf.h>
#include <base/time/time.h>
#include <brillo/data_encoding.h>
#include <bsdiff/bspatch.h>
@@ -249,8 +247,8 @@ bool DeltaPerformer::OpenCurrentPartition() {
IsDynamicPartition(install_part.name, install_plan_->target_slot));
// Open source fds if we have a delta payload, or for partitions in the
// partial update.
- bool source_may_exist = manifest_.partial_update() ||
- payload_->type == InstallPayloadType::kDelta;
+ const bool source_may_exist = manifest_.partial_update() ||
+ payload_->type == InstallPayloadType::kDelta;
const size_t partition_operation_num = GetPartitionOperationNum();
TEST_AND_RETURN_FALSE(partition_writer_->Init(
@@ -267,7 +265,7 @@ size_t DeltaPerformer::GetPartitionOperationNum() {
namespace {
void LogPartitionInfoHash(const PartitionInfo& info, const string& tag) {
- string sha256 = brillo::data_encoding::Base64Encode(info.hash());
+ string sha256 = HexEncode(info.hash());
LOG(INFO) << "PartitionInfo " << tag << " sha256: " << sha256
<< " size: " << info.size();
}
@@ -391,12 +389,13 @@ MetadataParseResult DeltaPerformer::ParsePayloadMetadata(
return MetadataParseResult::kSuccess;
}
-#define OP_DURATION_HISTOGRAM(_op_name, _start_time) \
- LOCAL_HISTOGRAM_CUSTOM_TIMES( \
- "UpdateEngine.DownloadAction.InstallOperation::" _op_name ".Duration", \
- (base::TimeTicks::Now() - _start_time), \
- base::TimeDelta::FromMilliseconds(10), \
- base::TimeDelta::FromMinutes(5), \
+#define OP_DURATION_HISTOGRAM(_op_name, _start_time) \
+ LOCAL_HISTOGRAM_CUSTOM_TIMES( \
+ "UpdateEngine.DownloadAction.InstallOperation::" + string(_op_name) + \
+ ".Duration", \
+ (base::TimeTicks::Now() - _start_time), \
+ base::TimeDelta::FromMilliseconds(10), \
+ base::TimeDelta::FromMinutes(5), \
20);
// Wrapper around write. Returns true if all requested bytes
@@ -499,7 +498,10 @@ bool DeltaPerformer::Write(const void* bytes, size_t count, ErrorCode* error) {
// |num_total_operations_| limit yet.
if (next_operation_num_ >= acc_num_operations_[current_partition_]) {
if (partition_writer_) {
- TEST_AND_RETURN_FALSE(partition_writer_->FinishedInstallOps());
+ if (!partition_writer_->FinishedInstallOps()) {
+ *error = ErrorCode::kDownloadWriteError;
+ return false;
+ }
}
CloseCurrentPartition();
// Skip until there are operations for current_partition_.
@@ -548,6 +550,7 @@ bool DeltaPerformer::Write(const void* bytes, size_t count, ErrorCode* error) {
base::TimeTicks op_start_time = base::TimeTicks::Now();
bool op_result;
+ const string op_name = InstallOperationTypeName(op.type());
switch (op.type()) {
case InstallOperation::REPLACE:
case InstallOperation::REPLACE_BZ:
@@ -566,17 +569,17 @@ bool DeltaPerformer::Write(const void* bytes, size_t count, ErrorCode* error) {
break;
case InstallOperation::SOURCE_BSDIFF:
case InstallOperation::BROTLI_BSDIFF:
- op_result = PerformSourceBsdiffOperation(op, error);
- OP_DURATION_HISTOGRAM("SOURCE_BSDIFF", op_start_time);
- break;
case InstallOperation::PUFFDIFF:
- op_result = PerformPuffDiffOperation(op, error);
- OP_DURATION_HISTOGRAM("PUFFDIFF", op_start_time);
+ case InstallOperation::ZUCCHINI:
+ case InstallOperation::LZ4DIFF_PUFFDIFF:
+ case InstallOperation::LZ4DIFF_BSDIFF:
+ op_result = PerformDiffOperation(op, error);
+ OP_DURATION_HISTOGRAM(op_name, op_start_time);
break;
default:
op_result = false;
}
- if (!HandleOpResult(op_result, InstallOperationTypeName(op.type()), error))
+ if (!HandleOpResult(op_result, op_name.c_str(), error))
return false;
next_operation_num_++;
@@ -626,10 +629,8 @@ bool DeltaPerformer::IsManifestValid() {
}
bool DeltaPerformer::ParseManifestPartitions(ErrorCode* error) {
- partitions_.clear();
- for (const PartitionUpdate& partition : manifest_.partitions()) {
- partitions_.push_back(partition);
- }
+ partitions_.assign(manifest_.partitions().begin(),
+ manifest_.partitions().end());
// For VAB and partial updates, the partition preparation will copy the
// dynamic partitions metadata to the target metadata slot, and rename the
@@ -687,87 +688,11 @@ bool DeltaPerformer::ParseManifestPartitions(ErrorCode* error) {
}
}
- // Fill in the InstallPlan::partitions based on the partitions from the
- // payload.
- for (const auto& partition : partitions_) {
- InstallPlan::Partition install_part;
- install_part.name = partition.partition_name();
- install_part.run_postinstall =
- partition.has_run_postinstall() && partition.run_postinstall();
- if (install_part.run_postinstall) {
- install_part.postinstall_path =
- (partition.has_postinstall_path() ? partition.postinstall_path()
- : kPostinstallDefaultScript);
- install_part.filesystem_type = partition.filesystem_type();
- install_part.postinstall_optional = partition.postinstall_optional();
- }
-
- if (partition.has_old_partition_info()) {
- const PartitionInfo& info = partition.old_partition_info();
- install_part.source_size = info.size();
- install_part.source_hash.assign(info.hash().begin(), info.hash().end());
- }
-
- if (!partition.has_new_partition_info()) {
- LOG(ERROR) << "Unable to get new partition hash info on partition "
- << install_part.name << ".";
- *error = ErrorCode::kDownloadNewPartitionInfoError;
- return false;
- }
- const PartitionInfo& info = partition.new_partition_info();
- install_part.target_size = info.size();
- install_part.target_hash.assign(info.hash().begin(), info.hash().end());
-
- install_part.block_size = block_size_;
- if (partition.has_hash_tree_extent()) {
- Extent extent = partition.hash_tree_data_extent();
- install_part.hash_tree_data_offset = extent.start_block() * block_size_;
- install_part.hash_tree_data_size = extent.num_blocks() * block_size_;
- extent = partition.hash_tree_extent();
- install_part.hash_tree_offset = extent.start_block() * block_size_;
- install_part.hash_tree_size = extent.num_blocks() * block_size_;
- uint64_t hash_tree_data_end =
- install_part.hash_tree_data_offset + install_part.hash_tree_data_size;
- if (install_part.hash_tree_offset < hash_tree_data_end) {
- LOG(ERROR) << "Invalid hash tree extents, hash tree data ends at "
- << hash_tree_data_end << ", but hash tree starts at "
- << install_part.hash_tree_offset;
- *error = ErrorCode::kDownloadNewPartitionInfoError;
- return false;
- }
- install_part.hash_tree_algorithm = partition.hash_tree_algorithm();
- install_part.hash_tree_salt.assign(partition.hash_tree_salt().begin(),
- partition.hash_tree_salt().end());
- }
- if (partition.has_fec_extent()) {
- Extent extent = partition.fec_data_extent();
- install_part.fec_data_offset = extent.start_block() * block_size_;
- install_part.fec_data_size = extent.num_blocks() * block_size_;
- extent = partition.fec_extent();
- install_part.fec_offset = extent.start_block() * block_size_;
- install_part.fec_size = extent.num_blocks() * block_size_;
- uint64_t fec_data_end =
- install_part.fec_data_offset + install_part.fec_data_size;
- if (install_part.fec_offset < fec_data_end) {
- LOG(ERROR) << "Invalid fec extents, fec data ends at " << fec_data_end
- << ", but fec starts at " << install_part.fec_offset;
- *error = ErrorCode::kDownloadNewPartitionInfoError;
- return false;
- }
- install_part.fec_roots = partition.fec_roots();
- }
-
- install_plan_->partitions.push_back(install_part);
- }
-
- // TODO(xunchang) only need to load the partitions for those in payload.
- // Because we have already loaded the other once when generating SOURCE_COPY
- // operations.
- if (!install_plan_->LoadPartitionsFromSlots(boot_control_)) {
- LOG(ERROR) << "Unable to determine all the partition devices.";
- *error = ErrorCode::kInstallDeviceOpenError;
+ if (!install_plan_->ParsePartitions(
+ partitions_, boot_control_, block_size_, error)) {
return false;
}
+
LogPartitionInfo(partitions_);
return true;
}
@@ -873,44 +798,6 @@ bool DeltaPerformer::PerformZeroOrDiscardOperation(
return partition_writer_->PerformZeroOrDiscardOperation(operation);
}
-bool PartitionWriter::ValidateSourceHash(const brillo::Blob& calculated_hash,
- const InstallOperation& operation,
- const FileDescriptorPtr source_fd,
- ErrorCode* error) {
- brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
- operation.src_sha256_hash().end());
- if (calculated_hash != expected_source_hash) {
- LOG(ERROR) << "The hash of the source data on disk for this operation "
- << "doesn't match the expected value. This could mean that the "
- << "delta update payload was targeted for another version, or "
- << "that the source partition was modified after it was "
- << "installed, for example, by mounting a filesystem.";
- LOG(ERROR) << "Expected: sha256|hex = "
- << base::HexEncode(expected_source_hash.data(),
- expected_source_hash.size());
- LOG(ERROR) << "Calculated: sha256|hex = "
- << base::HexEncode(calculated_hash.data(),
- calculated_hash.size());
-
- vector<string> source_extents;
- for (const Extent& ext : operation.src_extents()) {
- source_extents.push_back(
- base::StringPrintf("%" PRIu64 ":%" PRIu64,
- static_cast<uint64_t>(ext.start_block()),
- static_cast<uint64_t>(ext.num_blocks())));
- }
- LOG(ERROR) << "Operation source (offset:size) in blocks: "
- << base::JoinString(source_extents, ",");
-
- // Log remount history if this device is an ext4 partition.
- LogMountHistory(source_fd);
-
- *error = ErrorCode::kDownloadStateInitializationError;
- return false;
- }
- return true;
-}
-
bool DeltaPerformer::PerformSourceCopyOperation(
const InstallOperation& operation, ErrorCode* error) {
if (operation.has_src_length())
@@ -942,8 +829,8 @@ bool DeltaPerformer::ExtentsToBsdiffPositionsString(
return true;
}
-bool DeltaPerformer::PerformSourceBsdiffOperation(
- const InstallOperation& operation, ErrorCode* error) {
+bool DeltaPerformer::PerformDiffOperation(const InstallOperation& operation,
+ ErrorCode* error) {
// Since we delete data off the beginning of the buffer as we use it,
// the data we need should be exactly at the beginning of the buffer.
TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset());
@@ -953,19 +840,7 @@ bool DeltaPerformer::PerformSourceBsdiffOperation(
if (operation.has_dst_length())
TEST_AND_RETURN_FALSE(operation.dst_length() % block_size_ == 0);
- TEST_AND_RETURN_FALSE(partition_writer_->PerformSourceBsdiffOperation(
- operation, error, buffer_.data(), buffer_.size()));
- DiscardBuffer(true, buffer_.size());
- return true;
-}
-
-bool DeltaPerformer::PerformPuffDiffOperation(const InstallOperation& operation,
- ErrorCode* error) {
- // Since we delete data off the beginning of the buffer as we use it,
- // the data we need should be exactly at the beginning of the buffer.
- TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset());
- TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length());
- TEST_AND_RETURN_FALSE(partition_writer_->PerformPuffDiffOperation(
+ TEST_AND_RETURN_FALSE(partition_writer_->PerformDiffOperation(
operation, error, buffer_.data(), buffer_.size()));
DiscardBuffer(true, buffer_.size());
return true;
@@ -1022,6 +897,7 @@ DeltaPerformer::CreatePayloadVerifier() {
if (public_key.empty()) {
return {nullptr, false};
}
+ LOG(INFO) << "Verifing using public key: " << public_key;
return {PayloadVerifier::CreateInstance(public_key), true};
}
@@ -1241,11 +1117,11 @@ ErrorCode DeltaPerformer::ValidateOperationHash(
if (calculated_op_hash != expected_op_hash) {
LOG(ERROR) << "Hash verification failed for operation "
- << next_operation_num_ << ". Expected hash = ";
- utils::HexDumpVector(expected_op_hash);
+ << next_operation_num_
+ << ". Expected hash = " << HexEncode(expected_op_hash);
LOG(ERROR) << "Calculated hash over " << operation.data_length()
- << " bytes at offset: " << operation.data_offset() << " = ";
- utils::HexDumpVector(calculated_op_hash);
+ << " bytes at offset: " << operation.data_offset() << " = "
+ << HexEncode(calculated_op_hash);
return ErrorCode::kDownloadOperationHashMismatch;
}
@@ -1276,9 +1152,12 @@ ErrorCode DeltaPerformer::VerifyPayload(
// Verifies the payload hash.
TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadVerificationError,
!payload_hash_calculator_.raw_hash().empty());
- TEST_AND_RETURN_VAL(
- ErrorCode::kPayloadHashMismatchError,
- payload_hash_calculator_.raw_hash() == update_check_response_hash);
+ if (payload_hash_calculator_.raw_hash() != update_check_response_hash) {
+ LOG(ERROR) << "Actual hash: "
+ << HexEncode(payload_hash_calculator_.raw_hash())
+ << ", expected hash: " << HexEncode(update_check_response_hash);
+ return ErrorCode::kPayloadHashMismatchError;
+ }
// NOLINTNEXTLINE(whitespace/braces)
auto [payload_verifier, perform_verification] = CreatePayloadVerifier();
@@ -1531,7 +1410,7 @@ bool DeltaPerformer::IsDynamicPartition(const std::string& part_name,
part_name, slot);
}
-std::unique_ptr<PartitionWriter> DeltaPerformer::CreatePartitionWriter(
+std::unique_ptr<PartitionWriterInterface> DeltaPerformer::CreatePartitionWriter(
const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
DynamicPartitionControlInterface* dynamic_control,
diff --git a/payload_consumer/delta_performer.h b/payload_consumer/delta_performer.h
index c54316bd..dd714678 100644
--- a/payload_consumer/delta_performer.h
+++ b/payload_consumer/delta_performer.h
@@ -65,19 +65,22 @@ class DeltaPerformer : public FileWriter {
static const unsigned kProgressOperationsWeight;
static const uint64_t kCheckpointFrequencySeconds;
- DeltaPerformer(PrefsInterface* prefs,
- BootControlInterface* boot_control,
- HardwareInterface* hardware,
- DownloadActionDelegate* download_delegate,
- InstallPlan* install_plan,
- InstallPlan::Payload* payload,
- bool interactive)
+ DeltaPerformer(
+ PrefsInterface* prefs,
+ BootControlInterface* boot_control,
+ HardwareInterface* hardware,
+ DownloadActionDelegate* download_delegate,
+ InstallPlan* install_plan,
+ InstallPlan::Payload* payload,
+ bool interactive,
+ std::string update_certificates_path = constants::kUpdateCertificatesPath)
: prefs_(prefs),
boot_control_(boot_control),
hardware_(hardware),
download_delegate_(download_delegate),
install_plan_(install_plan),
payload_(payload),
+ update_certificates_path_(std::move(update_certificates_path)),
interactive_(interactive) {
CHECK(install_plan_);
}
@@ -162,11 +165,6 @@ class DeltaPerformer : public FileWriter {
public_key_path_ = public_key_path;
}
- void set_update_certificates_path(
- const std::string& update_certificates_path) {
- update_certificates_path_ = update_certificates_path;
- }
-
// Return true if header parsing is finished and no errors occurred.
bool IsHeaderParsed() const;
@@ -176,14 +174,6 @@ class DeltaPerformer : public FileWriter {
// Exposed for testing purposes.
bool CheckpointUpdateProgress(bool force);
- // Compare |calculated_hash| with source hash in |operation|, return false and
- // dump hash and set |error| if don't match.
- // |source_fd| is the file descriptor of the source partition.
- static bool ValidateSourceHash(const brillo::Blob& calculated_hash,
- const InstallOperation& operation,
- const FileDescriptorPtr source_fd,
- ErrorCode* error);
-
// Initialize partitions and allocate required space for an update with the
// given |manifest|. |update_check_response_hash| is used to check if the
// previous call to this function corresponds to the same payload.
@@ -204,7 +194,7 @@ class DeltaPerformer : public FileWriter {
protected:
// Exposed as virtual for testing purposes.
- virtual std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+ virtual std::unique_ptr<PartitionWriterInterface> CreatePartitionWriter(
const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
DynamicPartitionControlInterface* dynamic_control,
@@ -275,10 +265,8 @@ class DeltaPerformer : public FileWriter {
bool PerformZeroOrDiscardOperation(const InstallOperation& operation);
bool PerformSourceCopyOperation(const InstallOperation& operation,
ErrorCode* error);
- bool PerformSourceBsdiffOperation(const InstallOperation& operation,
- ErrorCode* error);
- bool PerformPuffDiffOperation(const InstallOperation& operation,
- ErrorCode* error);
+ bool PerformDiffOperation(const InstallOperation& operation,
+ ErrorCode* error);
// Extracts the payload signature message from the current |buffer_| if the
// offset matches the one specified by the manifest. Returns whether the
@@ -406,7 +394,7 @@ class DeltaPerformer : public FileWriter {
std::string public_key_path_{constants::kUpdatePayloadPublicKeyPath};
// The path to the zip file with X509 certificates.
- std::string update_certificates_path_{constants::kUpdateCertificatesPath};
+ const std::string update_certificates_path_;
// The number of bytes received so far, used for progress tracking.
size_t total_bytes_received_{0};
@@ -434,7 +422,7 @@ class DeltaPerformer : public FileWriter {
base::TimeDelta::FromSeconds(kCheckpointFrequencySeconds)};
base::TimeTicks update_checkpoint_time_;
- std::unique_ptr<PartitionWriter> partition_writer_;
+ std::unique_ptr<PartitionWriterInterface> partition_writer_;
DISALLOW_COPY_AND_ASSIGN(DeltaPerformer);
};
diff --git a/payload_consumer/delta_performer_integration_test.cc b/payload_consumer/delta_performer_integration_test.cc
index 4fab9751..de948fb8 100644
--- a/payload_consumer/delta_performer_integration_test.cc
+++ b/payload_consumer/delta_performer_integration_test.cc
@@ -41,6 +41,7 @@
#include "update_engine/common/mock_download_action.h"
#include "update_engine/common/mock_prefs.h"
#include "update_engine/common/test_utils.h"
+#include "update_engine/common/testing_constants.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/payload_consumer/payload_constants.h"
@@ -66,13 +67,6 @@ using testing::NiceMock;
using testing::Not;
using testing::Return;
-extern const char* kUnittestPrivateKeyPath;
-extern const char* kUnittestPublicKeyPath;
-extern const char* kUnittestPrivateKey2Path;
-extern const char* kUnittestPublicKey2Path;
-extern const char* kUnittestPrivateKeyECPath;
-extern const char* kUnittestPublicKeyECPath;
-
static const uint32_t kDefaultKernelSize = 4096; // Something small for a test
// clang-format off
static const uint8_t kNewData[] = {'T', 'h', 'i', 's', ' ', 'i', 's', ' ',
@@ -156,7 +150,7 @@ class DeltaPerformerIntegrationTest : public ::testing::Test {
performer.manifest_.CopyFrom(manifest);
performer.major_payload_version_ = major_version;
- EXPECT_EQ(expected, performer.ValidateManifest());
+ ASSERT_EQ(expected, performer.ValidateManifest());
}
void AddPartition(DeltaArchiveManifest* manifest,
string name,
@@ -171,19 +165,19 @@ class DeltaPerformerIntegrationTest : public ::testing::Test {
static void CompareFilesByBlock(const string& a_file,
const string& b_file,
size_t image_size) {
- EXPECT_EQ(0U, image_size % kBlockSize);
+ ASSERT_EQ(0U, image_size % kBlockSize);
brillo::Blob a_data, b_data;
- EXPECT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
- EXPECT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
+ ASSERT_TRUE(utils::ReadFile(a_file, &a_data)) << "file failed: " << a_file;
+ ASSERT_TRUE(utils::ReadFile(b_file, &b_data)) << "file failed: " << b_file;
EXPECT_GE(a_data.size(), image_size);
EXPECT_GE(b_data.size(), image_size);
for (size_t i = 0; i < image_size; i += kBlockSize) {
- EXPECT_EQ(0U, i % kBlockSize);
+ ASSERT_EQ(0U, i % kBlockSize);
brillo::Blob a_sub(&a_data[i], &a_data[i + kBlockSize]);
brillo::Blob b_sub(&b_data[i], &b_data[i + kBlockSize]);
- EXPECT_TRUE(a_sub == b_sub) << "Block " << (i / kBlockSize) << " differs";
+ ASSERT_EQ(a_sub, b_sub) << "Block " << (i / kBlockSize) << " differs";
}
if (::testing::Test::HasNonfatalFailure()) {
LOG(INFO) << "Compared filesystems with size " << image_size
@@ -207,8 +201,7 @@ static bool WriteByteAtOffset(const string& path, off_t offset) {
int fd = open(path.c_str(), O_CREAT | O_WRONLY, 0644);
TEST_AND_RETURN_FALSE_ERRNO(fd >= 0);
ScopedFdCloser fd_closer(&fd);
- EXPECT_TRUE(utils::PWriteAll(fd, "\0", 1, offset));
- return true;
+ return utils::PWriteAll(fd, "\0", 1, offset);
}
static bool InsertSignaturePlaceholder(size_t signature_size,
@@ -245,7 +238,7 @@ static void SignGeneratedPayload(const string& payload_path,
{metadata_signature},
payload_path,
out_metadata_size));
- EXPECT_TRUE(PayloadSigner::VerifySignedPayload(
+ ASSERT_TRUE(PayloadSigner::VerifySignedPayload(
payload_path, GetBuildArtifactsPath(kUnittestPublicKeyPath)));
}
@@ -359,12 +352,12 @@ static void SignGeneratedShellPayload(SignatureTest signature_test,
// openssl genrsa -out <private_key_path> 2048
RSA* rsa = RSA_new();
BIGNUM* e = BN_new();
- EXPECT_EQ(1, BN_set_word(e, RSA_F4));
- EXPECT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr));
+ ASSERT_EQ(1, BN_set_word(e, RSA_F4));
+ ASSERT_EQ(1, RSA_generate_key_ex(rsa, 2048, e, nullptr));
BN_free(e);
FILE* fprikey = fopen(private_key_path.c_str(), "w");
EXPECT_NE(nullptr, fprikey);
- EXPECT_EQ(1,
+ ASSERT_EQ(1,
PEM_write_RSAPrivateKey(
fprikey, rsa, nullptr, nullptr, 0, nullptr, nullptr));
fclose(fprikey);
@@ -405,7 +398,7 @@ static void GenerateDeltaFile(bool full_kernel,
// in-place on A, we apply it to a new image, result_img.
state->result_img.reset(new ScopedTempFile("result_img.XXXXXX"));
- EXPECT_TRUE(
+ ASSERT_TRUE(
base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
base::FilePath(state->a_img->path())));
@@ -422,28 +415,28 @@ static void GenerateDeltaFile(bool full_kernel,
std::begin(kRandomString),
std::end(kRandomString));
}
- EXPECT_TRUE(utils::WriteFile(
+ ASSERT_TRUE(utils::WriteFile(
base::StringPrintf("%s/hardtocompress", a_mnt.c_str()).c_str(),
hardtocompress.data(),
hardtocompress.size()));
brillo::Blob zeros(16 * 1024, 0);
- EXPECT_EQ(static_cast<int>(zeros.size()),
+ ASSERT_EQ(static_cast<int>(zeros.size()),
base::WriteFile(base::FilePath(base::StringPrintf(
"%s/move-to-sparse", a_mnt.c_str())),
reinterpret_cast<const char*>(zeros.data()),
zeros.size()));
- EXPECT_TRUE(WriteSparseFile(
+ ASSERT_TRUE(WriteSparseFile(
base::StringPrintf("%s/move-from-sparse", a_mnt.c_str()), 16 * 1024));
- EXPECT_TRUE(WriteByteAtOffset(
+ ASSERT_TRUE(WriteByteAtOffset(
base::StringPrintf("%s/move-semi-sparse", a_mnt.c_str()), 4096));
// Write 1 MiB of 0xff to try to catch the case where writing a bsdiff
// patch fails to zero out the final block.
brillo::Blob ones(1024 * 1024, 0xff);
- EXPECT_TRUE(
+ ASSERT_TRUE(
utils::WriteFile(base::StringPrintf("%s/ones", a_mnt.c_str()).c_str(),
ones.data(),
ones.size()));
@@ -451,12 +444,12 @@ static void GenerateDeltaFile(bool full_kernel,
// Create a result image with image_size bytes of garbage.
brillo::Blob ones(state->image_size, 0xff);
- EXPECT_TRUE(utils::WriteFile(
+ ASSERT_TRUE(utils::WriteFile(
state->result_img->path().c_str(), ones.data(), ones.size()));
- EXPECT_EQ(utils::FileSize(state->a_img->path()),
+ ASSERT_EQ(utils::FileSize(state->a_img->path()),
utils::FileSize(state->result_img->path()));
- EXPECT_TRUE(
+ ASSERT_TRUE(
base::CopyFile(GetBuildArtifactsPath().Append("gen/disk_ext2_4k.img"),
base::FilePath(state->b_img->path())));
{
@@ -465,45 +458,45 @@ static void GenerateDeltaFile(bool full_kernel,
ScopedLoopMounter b_mounter(state->b_img->path(), &b_mnt, 0);
base::FilePath mnt_path(b_mnt);
- EXPECT_TRUE(base::CopyFile(mnt_path.Append("regular-small"),
+ ASSERT_TRUE(base::CopyFile(mnt_path.Append("regular-small"),
mnt_path.Append("regular-small2")));
#if BASE_VER < 800000
- EXPECT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false));
+ ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small"), false));
#else
- EXPECT_TRUE(base::DeleteFile(mnt_path.Append("regular-small")));
+ ASSERT_TRUE(base::DeleteFile(mnt_path.Append("regular-small")));
#endif
- EXPECT_TRUE(base::Move(mnt_path.Append("regular-small2"),
+ ASSERT_TRUE(base::Move(mnt_path.Append("regular-small2"),
mnt_path.Append("regular-small")));
- EXPECT_TRUE(
+ ASSERT_TRUE(
test_utils::WriteFileString(mnt_path.Append("foo").value(), "foo"));
- EXPECT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0));
+ ASSERT_EQ(0, base::WriteFile(mnt_path.Append("emptyfile"), "", 0));
- EXPECT_TRUE(
+ ASSERT_TRUE(
WriteSparseFile(mnt_path.Append("fullsparse").value(), 1024 * 1024));
- EXPECT_TRUE(
+ ASSERT_TRUE(
WriteSparseFile(mnt_path.Append("move-to-sparse").value(), 16 * 1024));
brillo::Blob zeros(16 * 1024, 0);
- EXPECT_EQ(static_cast<int>(zeros.size()),
+ ASSERT_EQ(static_cast<int>(zeros.size()),
base::WriteFile(mnt_path.Append("move-from-sparse"),
reinterpret_cast<const char*>(zeros.data()),
zeros.size()));
- EXPECT_TRUE(
+ ASSERT_TRUE(
WriteByteAtOffset(mnt_path.Append("move-semi-sparse").value(), 4096));
- EXPECT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096));
+ ASSERT_TRUE(WriteByteAtOffset(mnt_path.Append("partsparse").value(), 4096));
- EXPECT_TRUE(
+ ASSERT_TRUE(
base::CopyFile(mnt_path.Append("regular-16k"), mnt_path.Append("tmp")));
- EXPECT_TRUE(base::Move(mnt_path.Append("tmp"),
+ ASSERT_TRUE(base::Move(mnt_path.Append("tmp"),
mnt_path.Append("link-hard-regular-16k")));
#if BASE_VER < 800000
- EXPECT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false));
+ ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink"), false));
#else
- EXPECT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink")));
+ ASSERT_TRUE(base::DeleteFile(mnt_path.Append("link-short_symlink")));
#endif
- EXPECT_TRUE(test_utils::WriteFileString(
+ ASSERT_TRUE(test_utils::WriteFileString(
mnt_path.Append("link-short_symlink").value(), "foobar"));
brillo::Blob hardtocompress;
@@ -512,7 +505,7 @@ static void GenerateDeltaFile(bool full_kernel,
std::begin(kRandomString),
std::end(kRandomString));
}
- EXPECT_TRUE(utils::WriteFile(
+ ASSERT_TRUE(utils::WriteFile(
base::StringPrintf("%s/hardtocompress", b_mnt.c_str()).c_str(),
hardtocompress.data(),
hardtocompress.size()));
@@ -534,13 +527,13 @@ static void GenerateDeltaFile(bool full_kernel,
std::begin(kNewData), std::end(kNewData), state->new_kernel_data.begin());
// Write kernels to disk
- EXPECT_TRUE(utils::WriteFile(state->old_kernel->path().c_str(),
+ ASSERT_TRUE(utils::WriteFile(state->old_kernel->path().c_str(),
state->old_kernel_data.data(),
state->old_kernel_data.size()));
- EXPECT_TRUE(utils::WriteFile(state->new_kernel->path().c_str(),
+ ASSERT_TRUE(utils::WriteFile(state->new_kernel->path().c_str(),
state->new_kernel_data.data(),
state->new_kernel_data.size()));
- EXPECT_TRUE(utils::WriteFile(state->result_kernel->path().c_str(),
+ ASSERT_TRUE(utils::WriteFile(state->result_kernel->path().c_str(),
state->result_kernel_data.data(),
state->result_kernel_data.size()));
@@ -564,9 +557,9 @@ static void GenerateDeltaFile(bool full_kernel,
if (!full_kernel)
payload_config.source.partitions.back().path =
state->old_kernel->path();
- EXPECT_TRUE(payload_config.source.LoadImageSize());
+ ASSERT_TRUE(payload_config.source.LoadImageSize());
for (PartitionConfig& part : payload_config.source.partitions)
- EXPECT_TRUE(part.OpenFilesystem());
+ ASSERT_TRUE(part.OpenFilesystem());
} else {
if (payload_config.hard_chunk_size == -1)
// Use 1 MiB chunk size for the full unittests.
@@ -576,26 +569,26 @@ static void GenerateDeltaFile(bool full_kernel,
payload_config.target.partitions.back().path = state->b_img->path();
payload_config.target.partitions.emplace_back(kPartitionNameKernel);
payload_config.target.partitions.back().path = state->new_kernel->path();
- EXPECT_TRUE(payload_config.target.LoadImageSize());
+ ASSERT_TRUE(payload_config.target.LoadImageSize());
for (PartitionConfig& part : payload_config.target.partitions)
- EXPECT_TRUE(part.OpenFilesystem());
+ ASSERT_TRUE(part.OpenFilesystem());
- EXPECT_TRUE(payload_config.Validate());
- EXPECT_TRUE(GenerateUpdatePayloadFile(payload_config,
+ ASSERT_TRUE(payload_config.Validate());
+ ASSERT_TRUE(GenerateUpdatePayloadFile(payload_config,
state->delta_file->path(),
private_key,
&state->metadata_size));
}
// Extend the "partitions" holding the file system a bit.
- EXPECT_EQ(0,
+ ASSERT_EQ(0,
HANDLE_EINTR(truncate(state->a_img->path().c_str(),
state->image_size + 1024 * 1024)));
- EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
+ ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
utils::FileSize(state->a_img->path()));
- EXPECT_EQ(0,
+ ASSERT_EQ(0,
HANDLE_EINTR(truncate(state->b_img->path().c_str(),
state->image_size + 1024 * 1024)));
- EXPECT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
+ ASSERT_EQ(static_cast<off_t>(state->image_size + 1024 * 1024),
utils::FileSize(state->b_img->path()));
if (signature_test == kSignatureGeneratedPlaceholder ||
@@ -643,9 +636,9 @@ static void ApplyDeltaFile(bool full_kernel,
uint32_t minor_version) {
// Check the metadata.
{
- EXPECT_TRUE(utils::ReadFile(state->delta_file->path(), &state->delta));
+ ASSERT_TRUE(utils::ReadFile(state->delta_file->path(), &state->delta));
PayloadMetadata payload_metadata;
- EXPECT_TRUE(payload_metadata.ParsePayloadHeader(state->delta));
+ ASSERT_TRUE(payload_metadata.ParsePayloadHeader(state->delta));
state->metadata_size = payload_metadata.GetMetadataSize();
LOG(INFO) << "Metadata size: " << state->metadata_size;
state->metadata_signature_size =
@@ -653,23 +646,23 @@ static void ApplyDeltaFile(bool full_kernel,
LOG(INFO) << "Metadata signature size: " << state->metadata_signature_size;
DeltaArchiveManifest manifest;
- EXPECT_TRUE(payload_metadata.GetManifest(state->delta, &manifest));
+ ASSERT_TRUE(payload_metadata.GetManifest(state->delta, &manifest));
if (signature_test == kSignatureNone) {
- EXPECT_FALSE(manifest.has_signatures_offset());
- EXPECT_FALSE(manifest.has_signatures_size());
+ ASSERT_FALSE(manifest.has_signatures_offset());
+ ASSERT_FALSE(manifest.has_signatures_size());
} else {
- EXPECT_TRUE(manifest.has_signatures_offset());
- EXPECT_TRUE(manifest.has_signatures_size());
+ ASSERT_TRUE(manifest.has_signatures_offset());
+ ASSERT_TRUE(manifest.has_signatures_size());
Signatures sigs_message;
- EXPECT_TRUE(sigs_message.ParseFromArray(
+ ASSERT_TRUE(sigs_message.ParseFromArray(
&state->delta[state->metadata_size + state->metadata_signature_size +
manifest.signatures_offset()],
manifest.signatures_size()));
if (signature_test == kSignatureGeneratedShellRotateCl1 ||
signature_test == kSignatureGeneratedShellRotateCl2)
- EXPECT_EQ(2, sigs_message.signatures_size());
+ ASSERT_EQ(2, sigs_message.signatures_size());
else
- EXPECT_EQ(1, sigs_message.signatures_size());
+ ASSERT_EQ(1, sigs_message.signatures_size());
const Signatures::Signature& signature = sigs_message.signatures(0);
vector<string> key_paths{GetBuildArtifactsPath(kUnittestPrivateKeyPath)};
@@ -680,10 +673,10 @@ static void ApplyDeltaFile(bool full_kernel,
key_paths.push_back(GetBuildArtifactsPath(kUnittestPrivateKey2Path));
}
uint64_t expected_sig_data_length = 0;
- EXPECT_TRUE(PayloadSigner::SignatureBlobLength(
+ ASSERT_TRUE(PayloadSigner::SignatureBlobLength(
key_paths, &expected_sig_data_length));
- EXPECT_EQ(expected_sig_data_length, manifest.signatures_size());
- EXPECT_FALSE(signature.data().empty());
+ ASSERT_EQ(expected_sig_data_length, manifest.signatures_size());
+ ASSERT_FALSE(signature.data().empty());
}
// TODO(ahassani): Make |DeltaState| into a partition list kind of struct
@@ -696,15 +689,15 @@ static void ApplyDeltaFile(bool full_kernel,
return partition.partition_name() == kPartitionNameKernel;
});
if (full_kernel) {
- EXPECT_FALSE(kernel_part.has_old_partition_info());
+ ASSERT_FALSE(kernel_part.has_old_partition_info());
} else {
- EXPECT_EQ(state->old_kernel_data.size(),
+ ASSERT_EQ(state->old_kernel_data.size(),
kernel_part.old_partition_info().size());
- EXPECT_FALSE(kernel_part.old_partition_info().hash().empty());
+ ASSERT_FALSE(kernel_part.old_partition_info().hash().empty());
}
- EXPECT_EQ(state->new_kernel_data.size(),
+ ASSERT_EQ(state->new_kernel_data.size(),
kernel_part.new_partition_info().size());
- EXPECT_FALSE(kernel_part.new_partition_info().hash().empty());
+ ASSERT_FALSE(kernel_part.new_partition_info().hash().empty());
const auto& rootfs_part =
*std::find_if(manifest.partitions().begin(),
@@ -713,11 +706,11 @@ static void ApplyDeltaFile(bool full_kernel,
return partition.partition_name() == kPartitionNameRoot;
});
if (full_rootfs) {
- EXPECT_FALSE(rootfs_part.has_old_partition_info());
+ ASSERT_FALSE(rootfs_part.has_old_partition_info());
} else {
- EXPECT_FALSE(rootfs_part.old_partition_info().hash().empty());
+ ASSERT_FALSE(rootfs_part.old_partition_info().hash().empty());
}
- EXPECT_FALSE(rootfs_part.new_partition_info().hash().empty());
+ ASSERT_FALSE(rootfs_part.new_partition_info().hash().empty());
}
NiceMock<MockPrefs> prefs;
@@ -798,7 +791,7 @@ static void ApplyDeltaFile(bool full_kernel,
? GetBuildArtifactsPath(kUnittestPrivateKeyECPath)
: GetBuildArtifactsPath(kUnittestPrivateKeyPath),
&install_plan->payloads[0].metadata_signature));
- EXPECT_FALSE(install_plan->payloads[0].metadata_signature.empty());
+ ASSERT_FALSE(install_plan->payloads[0].metadata_signature.empty());
*performer = new DeltaPerformer(&prefs,
&state->fake_boot_control_,
@@ -806,19 +799,19 @@ static void ApplyDeltaFile(bool full_kernel,
&state->mock_delegate_,
install_plan,
&install_plan->payloads[0],
- false /* interactive */);
+ false /* interactive */,
+ "");
string public_key_path = signature_test == kSignatureGeneratedShellECKey
? GetBuildArtifactsPath(kUnittestPublicKeyECPath)
: GetBuildArtifactsPath(kUnittestPublicKeyPath);
- EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
+ ASSERT_TRUE(utils::FileExists(public_key_path.c_str()));
(*performer)->set_public_key_path(public_key_path);
- (*performer)->set_update_certificates_path("");
- EXPECT_EQ(
+ ASSERT_EQ(
static_cast<off_t>(state->image_size),
HashCalculator::RawHashOfFile(
state->a_img->path(), state->image_size, &root_part.source_hash));
- EXPECT_TRUE(HashCalculator::RawHashOfData(state->old_kernel_data,
+ ASSERT_TRUE(HashCalculator::RawHashOfData(state->old_kernel_data,
&kernel_part.source_hash));
// The partitions should be empty before DeltaPerformer.
@@ -872,23 +865,23 @@ static void ApplyDeltaFile(bool full_kernel,
// we cannot proceed applying the delta.
if (!write_succeeded) {
LOG(INFO) << "Write failed. Checking if it failed with expected error";
- EXPECT_EQ(expected_error, actual_error);
+ ASSERT_EQ(expected_error, actual_error);
if (!continue_writing) {
LOG(INFO) << "Cannot continue writing. Bailing out.";
break;
}
}
- EXPECT_EQ(ErrorCode::kSuccess, actual_error);
+ ASSERT_EQ(ErrorCode::kSuccess, actual_error);
}
// If we had continued all the way through, Close should succeed.
// Otherwise, it should fail. Check appropriately.
bool close_result = (*performer)->Close();
if (continue_writing)
- EXPECT_EQ(0, close_result);
+ ASSERT_EQ(0, close_result);
else
- EXPECT_LE(0, close_result);
+ ASSERT_LE(0, close_result);
}
void VerifyPayloadResult(DeltaPerformer* performer,
@@ -896,14 +889,14 @@ void VerifyPayloadResult(DeltaPerformer* performer,
ErrorCode expected_result,
uint32_t minor_version) {
if (!performer) {
- EXPECT_TRUE(!"Skipping payload verification since performer is null.");
+ ASSERT_TRUE(!"Skipping payload verification since performer is null.");
return;
}
LOG(INFO) << "Verifying payload for expected result " << expected_result;
brillo::Blob expected_hash;
HashCalculator::RawHashOfData(state->delta, &expected_hash);
- EXPECT_EQ(expected_result,
+ ASSERT_EQ(expected_result,
performer->VerifyPayload(expected_hash, state->delta.size()));
LOG(INFO) << "Verified payload.";
@@ -919,31 +912,31 @@ void VerifyPayloadResult(DeltaPerformer* performer,
state->result_img->path(), state->b_img->path(), state->image_size);
brillo::Blob updated_kernel_partition;
- EXPECT_TRUE(
+ ASSERT_TRUE(
utils::ReadFile(state->result_kernel->path(), &updated_kernel_partition));
ASSERT_GE(updated_kernel_partition.size(), base::size(kNewData));
- EXPECT_TRUE(std::equal(std::begin(kNewData),
+ ASSERT_TRUE(std::equal(std::begin(kNewData),
std::end(kNewData),
updated_kernel_partition.begin()));
const auto& partitions = state->install_plan.partitions;
- EXPECT_EQ(2U, partitions.size());
- EXPECT_EQ(kPartitionNameRoot, partitions[0].name);
- EXPECT_EQ(kPartitionNameKernel, partitions[1].name);
+ ASSERT_EQ(2U, partitions.size());
+ ASSERT_EQ(kPartitionNameRoot, partitions[0].name);
+ ASSERT_EQ(kPartitionNameKernel, partitions[1].name);
- EXPECT_EQ(kDefaultKernelSize, partitions[1].target_size);
+ ASSERT_EQ(kDefaultKernelSize, partitions[1].target_size);
brillo::Blob expected_new_kernel_hash;
- EXPECT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
+ ASSERT_TRUE(HashCalculator::RawHashOfData(state->new_kernel_data,
&expected_new_kernel_hash));
- EXPECT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
+ ASSERT_EQ(expected_new_kernel_hash, partitions[1].target_hash);
- EXPECT_EQ(state->image_size, partitions[0].target_size);
+ ASSERT_EQ(state->image_size, partitions[0].target_size);
brillo::Blob expected_new_rootfs_hash;
- EXPECT_EQ(
+ ASSERT_EQ(
static_cast<off_t>(state->image_size),
HashCalculator::RawHashOfFile(
state->b_img->path(), state->image_size, &expected_new_rootfs_hash));
- EXPECT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
+ ASSERT_EQ(expected_new_rootfs_hash, partitions[0].target_hash);
}
void VerifyPayload(DeltaPerformer* performer,
diff --git a/payload_consumer/delta_performer_unittest.cc b/payload_consumer/delta_performer_unittest.cc
index 840ecf6c..effc8f39 100644
--- a/payload_consumer/delta_performer_unittest.cc
+++ b/payload_consumer/delta_performer_unittest.cc
@@ -47,6 +47,7 @@
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/mock_download_action.h"
#include "update_engine/common/test_utils.h"
+#include "update_engine/common/testing_constants.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/fake_file_descriptor.h"
#include "update_engine/payload_consumer/mock_partition_writer.h"
@@ -68,9 +69,6 @@ using testing::_;
using testing::Return;
using ::testing::Sequence;
-extern const char* kUnittestPrivateKeyPath;
-extern const char* kUnittestPublicKeyPath;
-
namespace {
const char kBogusMetadataSignature1[] =
@@ -169,7 +167,6 @@ class DeltaPerformerTest : public ::testing::Test {
install_plan_.target_slot = 1;
EXPECT_CALL(mock_delegate_, ShouldCancel(_))
.WillRepeatedly(testing::Return(false));
- performer_.set_update_certificates_path("");
// Set the public key corresponding to the unittest private key.
string public_key_path = GetBuildArtifactsPath(kUnittestPublicKeyPath);
EXPECT_TRUE(utils::FileExists(public_key_path.c_str()));
@@ -445,7 +442,8 @@ class DeltaPerformerTest : public ::testing::Test {
&mock_delegate_,
&install_plan_,
&payload_,
- false /* interactive*/};
+ false /* interactive */,
+ "" /* Update certs path */};
};
TEST_F(DeltaPerformerTest, FullPayloadWriteTest) {
@@ -654,7 +652,9 @@ TEST_F(DeltaPerformerTest, SourceHashMismatchTest) {
brillo::Blob payload_data =
GeneratePayload(brillo::Blob(), {aop}, false, &old_part);
- EXPECT_EQ(actual_data, ApplyPayload(payload_data, source.path(), false));
+ // When source hash mismatches, PartitionWriter will refuse to write anything.
+ // Therefore we should expect an empty blob.
+ EXPECT_EQ(brillo::Blob{}, ApplyPayload(payload_data, source.path(), false));
}
TEST_F(DeltaPerformerTest, ExtentsToByteStringTest) {
@@ -1068,7 +1068,8 @@ TEST_F(DeltaPerformerTest, UsePublicKeyFromResponse) {
EXPECT_FALSE(performer_.GetPublicKey(&public_key));
}
-TEST_F(DeltaPerformerTest, ConfVersionsMatch) {
+// TODO(197361113) re-enable the test after we bump the version in config.
+TEST(DISABLED_ConfVersionTest, ConfVersionsMatch) {
// Test that the versions in update_engine.conf that is installed to the
// image match the maximum supported delta versions in the update engine.
uint32_t minor_version;
@@ -1114,7 +1115,7 @@ class TestDeltaPerformer : public DeltaPerformer {
public:
using DeltaPerformer::DeltaPerformer;
- std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+ std::unique_ptr<PartitionWriterInterface> CreatePartitionWriter(
const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
DynamicPartitionControlInterface* dynamic_control,
diff --git a/payload_consumer/extent_map.h b/payload_consumer/extent_map.h
new file mode 100644
index 00000000..a985cb52
--- /dev/null
+++ b/payload_consumer/extent_map.h
@@ -0,0 +1,97 @@
+//
+// Copyright (C) 2021 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_PAYLOAD_CONSUMER_EXTENT_MAP_H_
+#define UPDATE_ENGINE_PAYLOAD_CONSUMER_EXTENT_MAP_H_
+
+#include <functional>
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+// Data structure for storing a disjoint set of extents.
+// Currently the only usecase is for VABCPartitionWriter to keep track of which
+// block belongs to which merge operation. Therefore this class only contains
+// the minimal set of functions needed.
+template <typename T, typename Comparator = ExtentLess>
+class ExtentMap {
+ public:
+ bool AddExtent(const Extent& extent, T&& value) {
+ if (set_.OverlapsWithExtent(extent)) {
+ return false;
+ }
+ const auto& [it, inserted] = map_.insert({extent, std::forward<T>(value)});
+ if (inserted) {
+ set_.AddExtent(extent);
+ }
+ return inserted;
+ }
+
+ size_t size() const { return map_.size(); }
+
+ // Return a pointer to entry which is intersecting |extent|. If T is already
+ // a pointer type, return T on success. This function always return
+ // |nullptr| on failure. Therefore you cannot store nullptr as an entry.
+ std::optional<T> Get(const Extent& extent) const {
+ const auto it = map_.find(extent);
+ if (it == map_.end()) {
+ for (const auto& ext : set_.GetCandidateRange(extent)) {
+ if (ExtentRanges::ExtentsOverlap(ext, extent)) {
+ LOG(WARNING) << "Looking up a partially intersecting extent isn't "
+ "supported by "
+ "this data structure. Querying extent: "
+ << extent << ", partial match in map: " << ext;
+ }
+ }
+ return {};
+ }
+ return {it->second};
+ }
+
+ // Return a set of extents that are contained in this extent map.
+ // If |extent| is completely covered by this extent map, a vector of itself
+ // will be returned.
+ // If only a subset of |extent| is covered by this extent map, a vector of
+ // parts in this map will be returned.
+ // If |extent| has no intersection with this map, an empty vector will be
+ // returned.
+ // E.g. extent map contains [0,5] and [10,15], GetIntersectingExtents([3, 12])
+ // would return [3,5] and [10,12]
+ std::vector<Extent> GetIntersectingExtents(const Extent& extent) const {
+ return set_.GetIntersectingExtents(extent);
+ }
+
+ // Complement of |GetIntersectingExtents|, return vector of extents which are
+ // part of |extent| but not covered by this map.
+ std::vector<Extent> GetNonIntersectingExtents(const Extent& extent) const {
+ return FilterExtentRanges({extent}, set_);
+ }
+
+ private:
+ // Get a range of exents that potentially intersect with parameter |extent|
+ std::map<Extent, T, Comparator> map_;
+ ExtentRanges set_{false};
+};
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_PAYLOAD_CONSUMER_EXTENT_MAP_H_
diff --git a/payload_consumer/extent_map_unittest.cc b/payload_consumer/extent_map_unittest.cc
new file mode 100644
index 00000000..d8137a0c
--- /dev/null
+++ b/payload_consumer/extent_map_unittest.cc
@@ -0,0 +1,151 @@
+//
+// Copyright (C) 2021 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 <gtest/gtest.h>
+#include <optional>
+#include <vector>
+
+#include "update_engine/payload_consumer/extent_map.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+namespace chromeos_update_engine {
+
+class ExtentMapTest : public ::testing::Test {
+ public:
+ ExtentMap<int> map_;
+};
+
+TEST_F(ExtentMapTest, QueryExactExtent) {
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(0, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(10, 5), 1));
+ auto ret = map_.Get(ExtentForRange(0, 5));
+ ASSERT_NE(ret, std::nullopt);
+ ASSERT_EQ(*ret, 7);
+}
+
+TEST_F(ExtentMapTest, QuerySubset) {
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(0, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(10, 5), 1));
+ auto ret = map_.Get(ExtentForRange(1, 2));
+ ASSERT_EQ(ret, std::nullopt);
+}
+
+TEST_F(ExtentMapTest, QueryTouching) {
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(0, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(10, 5), 1));
+ auto ret = map_.Get(ExtentForRange(3, 2));
+ ASSERT_EQ(ret, std::nullopt);
+ ret = map_.Get(ExtentForRange(4, 1));
+ ASSERT_EQ(ret, std::nullopt);
+ ret = map_.Get(ExtentForRange(5, 5));
+ ASSERT_EQ(ret, std::nullopt);
+ ret = map_.Get(ExtentForRange(5, 6));
+ ASSERT_EQ(ret, std::nullopt);
+}
+
+TEST_F(ExtentMapTest, GetIntersectingExtents) {
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(0, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(10, 5), 7));
+ auto ret = std::vector<Extent>{};
+ ret = map_.GetIntersectingExtents(ExtentForRange(2, 10));
+ ASSERT_EQ(ret.size(), 2U);
+ ASSERT_EQ(ret[0].start_block(), 2U);
+ ASSERT_EQ(ret[0].num_blocks(), 3U);
+
+ ASSERT_EQ(ret[1].start_block(), 10U);
+ ASSERT_EQ(ret[1].num_blocks(), 2U);
+
+ ret = map_.GetIntersectingExtents(ExtentForRange(2, 17));
+ ASSERT_EQ(ret.size(), 2U);
+ ASSERT_EQ(ret[0].start_block(), 2U);
+ ASSERT_EQ(ret[0].num_blocks(), 3U);
+
+ ASSERT_EQ(ret[1].start_block(), 10U);
+ ASSERT_EQ(ret[1].num_blocks(), 5U);
+
+ ret = map_.GetIntersectingExtents(ExtentForRange(2, 2));
+ ASSERT_EQ(ret, std::vector<Extent>{ExtentForRange(2, 2)});
+
+ ret = map_.GetIntersectingExtents(ExtentForRange(10, 5));
+ ASSERT_EQ(ret, std::vector<Extent>{ExtentForRange(10, 5)});
+
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(20, 5), 7));
+ ret = map_.GetIntersectingExtents(ExtentForRange(0, 30));
+ ASSERT_EQ(ret.size(), 3U);
+ ASSERT_EQ(ret[0].start_block(), 0U);
+ ASSERT_EQ(ret[0].num_blocks(), 5U);
+
+ ASSERT_EQ(ret[1].start_block(), 10U);
+ ASSERT_EQ(ret[1].num_blocks(), 5U);
+
+ ASSERT_EQ(ret[2].start_block(), 20U);
+ ASSERT_EQ(ret[2].num_blocks(), 5U);
+}
+
+TEST_F(ExtentMapTest, GetNonIntersectingExtents) {
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(0, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(10, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(20, 5), 7));
+
+ auto ret = std::vector<Extent>{};
+ ret = map_.GetNonIntersectingExtents(ExtentForRange(2, 13));
+
+ ASSERT_EQ(ret.size(), 1U);
+ ASSERT_EQ(ret[0].start_block(), 5U);
+ ASSERT_EQ(ret[0].num_blocks(), 5U);
+
+ ret = map_.GetNonIntersectingExtents(ExtentForRange(7, 20));
+ ASSERT_EQ(ret.size(), 3U);
+ ASSERT_EQ(ret[0].start_block(), 7U);
+ ASSERT_EQ(ret[0].num_blocks(), 3U);
+
+ ASSERT_EQ(ret[1].start_block(), 15U);
+ ASSERT_EQ(ret[1].num_blocks(), 5U);
+
+ ASSERT_EQ(ret[2].start_block(), 25U);
+ ASSERT_EQ(ret[2].num_blocks(), 2U);
+}
+
+TEST_F(ExtentMapTest, GetSameStartBlock) {
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(0, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(10, 5), 12));
+
+ const auto ret = map_.Get(ExtentForRange(0, 10));
+ // ASSERT_FALSE(ret.has_value()) << ret.value() won't work, because when |ret|
+ // doesn't have value, the part after '<<' after still evaluated, resulting in
+ // undefined behavior.
+ if (ret.has_value()) {
+ FAIL() << ret.value();
+ }
+}
+
+TEST_F(ExtentMapTest, GetTouchingExtents) {
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(5, 5), 7));
+ ASSERT_TRUE(map_.AddExtent(ExtentForRange(10, 5), 12));
+ const auto ret = map_.Get(ExtentForRange(5, 10));
+ if (ret.has_value()) {
+ ASSERT_FALSE(ret.has_value()) << ret.value();
+ }
+ const auto extents = map_.GetIntersectingExtents(ExtentForRange(0, 20));
+ ASSERT_GT(extents.size(), 0UL);
+ ASSERT_EQ(extents.size(), 2UL)
+ << "Expecting unmerged extents [5-9] and [10-14], actual: " << extents;
+ ASSERT_EQ(extents[0], ExtentForRange(5, 5));
+ ASSERT_EQ(extents[1], ExtentForRange(10, 5));
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/file_descriptor_utils.cc b/payload_consumer/file_descriptor_utils.cc
index 9a6a601e..91b56737 100644
--- a/payload_consumer/file_descriptor_utils.cc
+++ b/payload_consumer/file_descriptor_utils.cc
@@ -35,9 +35,12 @@ namespace {
// Size of the buffer used to copy blocks.
const uint64_t kMaxCopyBufferSize = 1024 * 1024;
+} // namespace
+namespace fd_utils {
+
bool CommonHashExtents(FileDescriptorPtr source,
const RepeatedPtrField<Extent>& src_extents,
- DirectExtentWriter* writer,
+ ExtentWriter* writer,
uint64_t block_size,
brillo::Blob* hash_out) {
auto total_blocks = utils::BlocksInExtents(src_extents);
@@ -72,10 +75,6 @@ bool CommonHashExtents(FileDescriptorPtr source,
return true;
}
-} // namespace
-
-namespace fd_utils {
-
bool CopyAndHashExtents(FileDescriptorPtr source,
const RepeatedPtrField<Extent>& src_extents,
FileDescriptorPtr target,
diff --git a/payload_consumer/file_descriptor_utils.h b/payload_consumer/file_descriptor_utils.h
index 68fb0019..3a4027d4 100644
--- a/payload_consumer/file_descriptor_utils.h
+++ b/payload_consumer/file_descriptor_utils.h
@@ -19,12 +19,20 @@
#include <brillo/secure_blob.h>
+#include "update_engine/payload_consumer/extent_writer.h"
#include "update_engine/payload_consumer/file_descriptor.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
namespace fd_utils {
+bool CommonHashExtents(
+ FileDescriptorPtr source,
+ const google::protobuf::RepeatedPtrField<Extent>& src_extents,
+ ExtentWriter* writer,
+ uint64_t block_size,
+ brillo::Blob* hash_out);
+
// Copy blocks from the |source| file to the |target| file and hashes the
// contents. The blocks to copy from the |source| to the |target| files are
// specified by the |src_extents| and |tgt_extents| list of Extents, which
diff --git a/payload_consumer/file_writer.h b/payload_consumer/file_writer.h
index cdc9fa0e..ec391a30 100644
--- a/payload_consumer/file_writer.h
+++ b/payload_consumer/file_writer.h
@@ -22,6 +22,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <android-base/strings.h>
#include <base/logging.h>
#include "update_engine/common/error_code.h"
@@ -88,7 +89,7 @@ class ScopedFileWriterCloser {
int err = writer_->Close();
if (err)
LOG(ERROR) << "FileWriter::Close failed: "
- << utils::ErrnoNumberAsString(-err);
+ << android::base::ErrnoNumberAsString(-err);
}
private:
diff --git a/payload_consumer/filesystem_verifier_action.cc b/payload_consumer/filesystem_verifier_action.cc
index 8b39f6d0..2770aff3 100644
--- a/payload_consumer/filesystem_verifier_action.cc
+++ b/payload_consumer/filesystem_verifier_action.cc
@@ -36,7 +36,6 @@
#include <brillo/streams/file_stream.h>
#include "common/error_code.h"
-#include "payload_generator/delta_diff_generator.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/file_descriptor.h"
@@ -183,7 +182,7 @@ bool FilesystemVerifierAction::InitializeFdVABC(bool should_write_verity) {
}
bool FilesystemVerifierAction::InitializeFd(const std::string& part_path) {
- partition_fd_ = FileDescriptorPtr(new EintrSafeFileDescriptor());
+ partition_fd_ = std::make_unique<EintrSafeFileDescriptor>();
const bool write_verity = ShouldWriteVerity();
int flags = write_verity ? O_RDWR : O_RDONLY;
if (!utils::SetBlockDeviceReadOnly(part_path, !write_verity)) {
@@ -198,11 +197,12 @@ bool FilesystemVerifierAction::InitializeFd(const std::string& part_path) {
}
void FilesystemVerifierAction::WriteVerityAndHashPartition(
- FileDescriptorPtr fd,
const off64_t start_offset,
const off64_t end_offset,
void* buffer,
const size_t buffer_size) {
+ auto fd = partition_fd_.get();
+ TEST_AND_RETURN(fd != nullptr);
if (start_offset >= end_offset) {
LOG_IF(WARNING, start_offset > end_offset)
<< "start_offset is greater than end_offset : " << start_offset << " > "
@@ -220,7 +220,7 @@ void FilesystemVerifierAction::WriteVerityAndHashPartition(
return;
}
}
- HashPartition(partition_fd_, 0, partition_size_, buffer, buffer_size);
+ HashPartition(0, partition_size_, buffer, buffer_size);
return;
}
const auto cur_offset = fd->Seek(start_offset, SEEK_SET);
@@ -250,18 +250,18 @@ void FilesystemVerifierAction::WriteVerityAndHashPartition(
FROM_HERE,
base::BindOnce(&FilesystemVerifierAction::WriteVerityAndHashPartition,
base::Unretained(this),
- fd,
start_offset + bytes_read,
end_offset,
buffer,
buffer_size)));
}
-void FilesystemVerifierAction::HashPartition(FileDescriptorPtr fd,
- const off64_t start_offset,
+void FilesystemVerifierAction::HashPartition(const off64_t start_offset,
const off64_t end_offset,
void* buffer,
const size_t buffer_size) {
+ auto fd = partition_fd_.get();
+ TEST_AND_RETURN(fd != nullptr);
if (start_offset >= end_offset) {
LOG_IF(WARNING, start_offset > end_offset)
<< "start_offset is greater than end_offset : " << start_offset << " > "
@@ -296,7 +296,6 @@ void FilesystemVerifierAction::HashPartition(FileDescriptorPtr fd,
FROM_HERE,
base::BindOnce(&FilesystemVerifierAction::HashPartition,
base::Unretained(this),
- fd,
start_offset + bytes_read,
end_offset,
buffer,
@@ -362,6 +361,7 @@ void FilesystemVerifierAction::StartPartitionHashing() {
CHECK_LE(partition.hash_tree_offset, partition.fec_offset)
<< " Hash tree is expected to come before FEC data";
}
+ CHECK_NE(partition_fd_, nullptr);
if (partition.hash_tree_offset != 0) {
filesystem_data_end_ = partition.hash_tree_offset;
} else if (partition.fec_offset != 0) {
@@ -375,11 +375,10 @@ void FilesystemVerifierAction::StartPartitionHashing() {
return;
}
WriteVerityAndHashPartition(
- partition_fd_, 0, filesystem_data_end_, buffer_.data(), buffer_.size());
+ 0, filesystem_data_end_, buffer_.data(), buffer_.size());
} else {
LOG(INFO) << "Verity writes disabled on partition " << partition.name;
- HashPartition(
- partition_fd_, 0, partition_size_, buffer_.data(), buffer_.size());
+ HashPartition(0, partition_size_, buffer_.data(), buffer_.size());
}
}
@@ -431,10 +430,10 @@ void FilesystemVerifierAction::FinishPartitionHashing() {
Cleanup(ErrorCode::kError);
return;
}
- InstallPlan::Partition& partition =
+ const InstallPlan::Partition& partition =
install_plan_.partitions[partition_index_];
LOG(INFO) << "Hash of " << partition.name << ": "
- << Base64Encode(hasher_->raw_hash());
+ << HexEncode(hasher_->raw_hash());
switch (verifier_step_) {
case VerifierStep::kVerifyTargetHash:
@@ -493,7 +492,6 @@ void FilesystemVerifierAction::FinishPartitionHashing() {
return;
}
// Start hashing the next partition, if any.
- hasher_.reset();
buffer_.clear();
if (partition_fd_) {
partition_fd_->Close();
diff --git a/payload_consumer/filesystem_verifier_action.h b/payload_consumer/filesystem_verifier_action.h
index 850abdad..edc8e53c 100644
--- a/payload_consumer/filesystem_verifier_action.h
+++ b/payload_consumer/filesystem_verifier_action.h
@@ -86,13 +86,11 @@ class FilesystemVerifierAction : public InstallPlanAction {
private:
friend class FilesystemVerifierActionTestDelegate;
- void WriteVerityAndHashPartition(FileDescriptorPtr fd,
- const off64_t start_offset,
+ void WriteVerityAndHashPartition(const off64_t start_offset,
const off64_t end_offset,
void* buffer,
const size_t buffer_size);
- void HashPartition(FileDescriptorPtr fd,
- const off64_t start_offset,
+ void HashPartition(const off64_t start_offset,
const off64_t end_offset,
void* buffer,
const size_t buffer_size);
@@ -138,7 +136,7 @@ class FilesystemVerifierAction : public InstallPlanAction {
// If not null, the FileDescriptor used to read from the device.
// verity writer might attempt to write to this fd, if verity is enabled.
- FileDescriptorPtr partition_fd_;
+ std::unique_ptr<FileDescriptor> partition_fd_;
// Buffer for storing data we read.
brillo::Blob buffer_;
diff --git a/payload_consumer/filesystem_verifier_action_unittest.cc b/payload_consumer/filesystem_verifier_action_unittest.cc
index f2f29547..533292aa 100644
--- a/payload_consumer/filesystem_verifier_action_unittest.cc
+++ b/payload_consumer/filesystem_verifier_action_unittest.cc
@@ -170,7 +170,7 @@ class FilesystemVerifierActionTest : public ::testing::Test {
bytes_to_read -= bytes_read;
offset += bytes_read;
}
- ASSERT_TRUE(verity_writer.Finalize(fd, fd));
+ ASSERT_TRUE(verity_writer.Finalize(fd.get(), fd.get()));
ASSERT_TRUE(fd->IsOpen());
ASSERT_TRUE(HashCalculator::RawHashOfFile(target_part_.path(),
&partition->target_hash));
@@ -565,7 +565,7 @@ void FilesystemVerifierActionTest::DoTestVABC(bool clear_target_hash,
EnableVABC(&dynamic_control, part.name);
auto open_cow = [part]() {
- auto cow_fd = std::make_shared<EintrSafeFileDescriptor>();
+ auto cow_fd = std::make_unique<EintrSafeFileDescriptor>();
EXPECT_TRUE(cow_fd->Open(part.readonly_target_path.c_str(), O_RDWR))
<< "Failed to open part " << part.readonly_target_path
<< strerror(errno);
@@ -618,14 +618,14 @@ void FilesystemVerifierActionTest::DoTestVABC(bool clear_target_hash,
if (enable_verity) {
std::vector<unsigned char> actual_fec(fec_size);
ssize_t bytes_read = 0;
- ASSERT_TRUE(utils::PReadAll(cow_fd,
+ ASSERT_TRUE(utils::PReadAll(cow_fd.get(),
actual_fec.data(),
actual_fec.size(),
fec_start_offset,
&bytes_read));
ASSERT_EQ(actual_fec, fec_data_);
std::vector<unsigned char> actual_hash_tree(hash_tree_size);
- ASSERT_TRUE(utils::PReadAll(cow_fd,
+ ASSERT_TRUE(utils::PReadAll(cow_fd.get(),
actual_hash_tree.data(),
actual_hash_tree.size(),
HASH_TREE_START_OFFSET,
diff --git a/payload_consumer/install_operation_executor.cc b/payload_consumer/install_operation_executor.cc
new file mode 100644
index 00000000..cd6546f4
--- /dev/null
+++ b/payload_consumer/install_operation_executor.cc
@@ -0,0 +1,385 @@
+//
+// Copyright (C) 2021 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/payload_consumer/install_operation_executor.h"
+
+#include <fcntl.h>
+#include <glob.h>
+#include <linux/fs.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <base/files/memory_mapped_file.h>
+#include <base/files/file_util.h>
+#include <bsdiff/bspatch.h>
+#include <puffin/brotli_util.h>
+#include <puffin/puffpatch.h>
+#include <zucchini/patch_reader.h>
+#include <zucchini/zucchini.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/lz4diff/lz4patch.h"
+#include "update_engine/lz4diff/lz4diff_compress.h"
+#include "update_engine/payload_consumer/bzip_extent_writer.h"
+#include "update_engine/payload_consumer/cached_file_descriptor.h"
+#include "update_engine/payload_consumer/extent_reader.h"
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/file_descriptor_utils.h"
+#include "update_engine/payload_consumer/xz_extent_writer.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+class BsdiffExtentFile : public bsdiff::FileInterface {
+ public:
+ BsdiffExtentFile(std::unique_ptr<ExtentReader> reader, size_t size)
+ : BsdiffExtentFile(std::move(reader), nullptr, size) {}
+ BsdiffExtentFile(std::unique_ptr<ExtentWriter> writer, size_t size)
+ : BsdiffExtentFile(nullptr, std::move(writer), size) {}
+
+ ~BsdiffExtentFile() override = default;
+
+ bool Read(void* buf, size_t count, size_t* bytes_read) override {
+ TEST_AND_RETURN_FALSE(reader_->Read(buf, count));
+ *bytes_read = count;
+ offset_ += count;
+ return true;
+ }
+
+ bool Write(const void* buf, size_t count, size_t* bytes_written) override {
+ TEST_AND_RETURN_FALSE(writer_->Write(buf, count));
+ *bytes_written = count;
+ offset_ += count;
+ return true;
+ }
+
+ bool Seek(off_t pos) override {
+ if (reader_ != nullptr) {
+ TEST_AND_RETURN_FALSE(reader_->Seek(pos));
+ offset_ = pos;
+ } else {
+ // For writes technically there should be no change of position, or it
+ // should be equivalent of current offset.
+ TEST_AND_RETURN_FALSE(offset_ == static_cast<uint64_t>(pos));
+ }
+ return true;
+ }
+
+ bool Close() override { return true; }
+
+ bool GetSize(uint64_t* size) override {
+ *size = size_;
+ return true;
+ }
+
+ private:
+ BsdiffExtentFile(std::unique_ptr<ExtentReader> reader,
+ std::unique_ptr<ExtentWriter> writer,
+ size_t size)
+ : reader_(std::move(reader)),
+ writer_(std::move(writer)),
+ size_(size),
+ offset_(0) {}
+
+ std::unique_ptr<ExtentReader> reader_;
+ std::unique_ptr<ExtentWriter> writer_;
+ uint64_t size_;
+ uint64_t offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(BsdiffExtentFile);
+};
+// A class to be passed to |puffpatch| for reading from |source_fd_| and writing
+// into |target_fd_|.
+class PuffinExtentStream : public puffin::StreamInterface {
+ public:
+ // Constructor for creating a stream for reading from an |ExtentReader|.
+ PuffinExtentStream(std::unique_ptr<ExtentReader> reader, uint64_t size)
+ : PuffinExtentStream(std::move(reader), nullptr, size) {}
+
+ // Constructor for creating a stream for writing to an |ExtentWriter|.
+ PuffinExtentStream(std::unique_ptr<ExtentWriter> writer, uint64_t size)
+ : PuffinExtentStream(nullptr, std::move(writer), size) {}
+
+ ~PuffinExtentStream() override = default;
+
+ bool GetSize(uint64_t* size) const override {
+ *size = size_;
+ return true;
+ }
+
+ bool GetOffset(uint64_t* offset) const override {
+ *offset = offset_;
+ return true;
+ }
+
+ bool Seek(uint64_t offset) override {
+ if (is_read_) {
+ TEST_AND_RETURN_FALSE(reader_->Seek(offset));
+ offset_ = offset;
+ } else {
+ // For writes technically there should be no change of position, or it
+ // should equivalent of current offset.
+ TEST_AND_RETURN_FALSE(offset_ == offset);
+ }
+ return true;
+ }
+
+ bool Read(void* buffer, size_t count) override {
+ TEST_AND_RETURN_FALSE(is_read_);
+ TEST_AND_RETURN_FALSE(reader_->Read(buffer, count));
+ offset_ += count;
+ return true;
+ }
+
+ bool Write(const void* buffer, size_t count) override {
+ TEST_AND_RETURN_FALSE(!is_read_);
+ TEST_AND_RETURN_FALSE(writer_->Write(buffer, count));
+ offset_ += count;
+ return true;
+ }
+
+ bool Close() override { return true; }
+
+ private:
+ PuffinExtentStream(std::unique_ptr<ExtentReader> reader,
+ std::unique_ptr<ExtentWriter> writer,
+ uint64_t size)
+ : reader_(std::move(reader)),
+ writer_(std::move(writer)),
+ size_(size),
+ offset_(0),
+ is_read_(reader_ ? true : false) {}
+
+ std::unique_ptr<ExtentReader> reader_;
+ std::unique_ptr<ExtentWriter> writer_;
+ uint64_t size_;
+ uint64_t offset_;
+ bool is_read_;
+
+ DISALLOW_COPY_AND_ASSIGN(PuffinExtentStream);
+};
+
+bool InstallOperationExecutor::ExecuteReplaceOperation(
+ const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ const void* data,
+ size_t count) {
+ TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::REPLACE ||
+ operation.type() == InstallOperation::REPLACE_BZ ||
+ operation.type() == InstallOperation::REPLACE_XZ);
+ // Setup the ExtentWriter stack based on the operation type.
+ if (operation.type() == InstallOperation::REPLACE_BZ) {
+ writer.reset(new BzipExtentWriter(std::move(writer)));
+ } else if (operation.type() == InstallOperation::REPLACE_XZ) {
+ writer.reset(new XzExtentWriter(std::move(writer)));
+ }
+ TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
+ TEST_AND_RETURN_FALSE(writer->Write(data, operation.data_length()));
+
+ return true;
+}
+
+bool InstallOperationExecutor::ExecuteZeroOrDiscardOperation(
+ const InstallOperation& operation, std::unique_ptr<ExtentWriter> writer) {
+ TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::ZERO ||
+ operation.type() == InstallOperation::DISCARD);
+ using base::MemoryMappedFile;
+ using Access = base::MemoryMappedFile::Access;
+ using Region = base::MemoryMappedFile::Region;
+ writer->Init(operation.dst_extents(), block_size_);
+ // Mmap a region of /dev/zero, as we don't need any actual memory to store
+ // these 0s, so mmap a region of "free memory".
+ base::File dev_zero(base::FilePath("/dev/zero"),
+ base::File::FLAG_OPEN | base::File::FLAG_READ);
+ MemoryMappedFile buffer;
+ TEST_AND_RETURN_FALSE_ERRNO(buffer.Initialize(
+ std::move(dev_zero),
+ Region{
+ 0,
+ static_cast<size_t>(utils::BlocksInExtents(operation.dst_extents()) *
+ block_size_)},
+ Access::READ_ONLY));
+ writer->Write(buffer.data(), buffer.length());
+ return true;
+}
+
+bool InstallOperationExecutor::ExecuteSourceCopyOperation(
+ const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd) {
+ TEST_AND_RETURN_FALSE(operation.type() == InstallOperation::SOURCE_COPY);
+ TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
+ return fd_utils::CommonHashExtents(
+ source_fd, operation.src_extents(), writer.get(), block_size_, nullptr);
+}
+
+bool InstallOperationExecutor::ExecuteDiffOperation(
+ const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count) {
+ TEST_AND_RETURN_FALSE(source_fd != nullptr);
+ TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
+ switch (operation.type()) {
+ case InstallOperation::SOURCE_BSDIFF:
+ case InstallOperation::BSDIFF:
+ case InstallOperation::BROTLI_BSDIFF:
+ return ExecuteSourceBsdiffOperation(
+ operation, std::move(writer), source_fd, data, count);
+ case InstallOperation::PUFFDIFF:
+ return ExecutePuffDiffOperation(
+ operation, std::move(writer), source_fd, data, count);
+ case InstallOperation::ZUCCHINI:
+ return ExecuteZucchiniOperation(
+ operation, std::move(writer), source_fd, data, count);
+ case InstallOperation::LZ4DIFF_BSDIFF:
+ case InstallOperation::LZ4DIFF_PUFFDIFF:
+ return ExecuteLz4diffOperation(
+ operation, std::move(writer), source_fd, data, count);
+ default:
+ LOG(ERROR) << "Unexpected operation type when executing diff ops "
+ << operation.type() << " "
+ << operation.Type_Name(operation.type());
+ return false;
+ }
+}
+
+bool InstallOperationExecutor::ExecuteLz4diffOperation(
+ const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count) {
+ brillo::Blob src_data;
+
+ TEST_AND_RETURN_FALSE(utils::ReadExtents(
+ source_fd, operation.src_extents(), &src_data, block_size_));
+ TEST_AND_RETURN_FALSE(Lz4Patch(
+ ToStringView(src_data),
+ ToStringView(data, count),
+ [writer(writer.get())](const uint8_t* data, size_t size) -> size_t {
+ if (!writer->Write(data, size)) {
+ return 0;
+ }
+ return size;
+ }));
+ return true;
+}
+
+bool InstallOperationExecutor::ExecuteSourceBsdiffOperation(
+ const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count) {
+ auto reader = std::make_unique<DirectExtentReader>();
+ TEST_AND_RETURN_FALSE(
+ reader->Init(source_fd, operation.src_extents(), block_size_));
+ auto src_file = std::make_unique<BsdiffExtentFile>(
+ std::move(reader),
+ utils::BlocksInExtents(operation.src_extents()) * block_size_);
+
+ auto dst_file = std::make_unique<BsdiffExtentFile>(
+ std::move(writer),
+ utils::BlocksInExtents(operation.dst_extents()) * block_size_);
+
+ TEST_AND_RETURN_FALSE(bsdiff::bspatch(std::move(src_file),
+ std::move(dst_file),
+ reinterpret_cast<const uint8_t*>(data),
+ count) == 0);
+ return true;
+}
+
+bool InstallOperationExecutor::ExecutePuffDiffOperation(
+ const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count) {
+ auto reader = std::make_unique<DirectExtentReader>();
+ TEST_AND_RETURN_FALSE(
+ reader->Init(source_fd, operation.src_extents(), block_size_));
+ puffin::UniqueStreamPtr src_stream(new PuffinExtentStream(
+ std::move(reader),
+ utils::BlocksInExtents(operation.src_extents()) * block_size_));
+
+ puffin::UniqueStreamPtr dst_stream(new PuffinExtentStream(
+ std::move(writer),
+ utils::BlocksInExtents(operation.dst_extents()) * block_size_));
+
+ constexpr size_t kMaxCacheSize = 5 * 1024 * 1024; // Total 5MB cache.
+ TEST_AND_RETURN_FALSE(
+ puffin::PuffPatch(std::move(src_stream),
+ std::move(dst_stream),
+ reinterpret_cast<const uint8_t*>(data),
+ count,
+ kMaxCacheSize));
+ return true;
+}
+
+bool InstallOperationExecutor::ExecuteZucchiniOperation(
+ const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count) {
+ uint64_t src_size =
+ utils::BlocksInExtents(operation.src_extents()) * block_size_;
+ brillo::Blob source_bytes(src_size);
+
+ // TODO(197361113) either make zucchini stream the read, or use memory mapped
+ // files.
+ auto reader = std::make_unique<DirectExtentReader>();
+ TEST_AND_RETURN_FALSE(
+ reader->Init(source_fd, operation.src_extents(), block_size_));
+ TEST_AND_RETURN_FALSE(reader->Seek(0));
+ TEST_AND_RETURN_FALSE(reader->Read(source_bytes.data(), src_size));
+
+ brillo::Blob zucchini_patch;
+ TEST_AND_RETURN_FALSE(puffin::BrotliDecode(
+ static_cast<const uint8_t*>(data), count, &zucchini_patch));
+ auto patch_reader = zucchini::EnsemblePatchReader::Create(
+ {zucchini_patch.data(), zucchini_patch.size()});
+ if (!patch_reader.has_value()) {
+ LOG(ERROR) << "Failed to parse the zucchini patch.";
+ return false;
+ }
+
+ auto dst_size = patch_reader->header().new_size;
+ TEST_AND_RETURN_FALSE(dst_size ==
+ utils::BlocksInExtents(operation.dst_extents()) *
+ block_size_);
+
+ brillo::Blob patched_data(dst_size);
+ auto status =
+ zucchini::ApplyBuffer({source_bytes.data(), source_bytes.size()},
+ *patch_reader,
+ {patched_data.data(), patched_data.size()});
+ if (status != zucchini::status::kStatusSuccess) {
+ LOG(ERROR) << "Failed to apply the zucchini patch: " << status;
+ return false;
+ }
+
+ TEST_AND_RETURN_FALSE(
+ writer->Write(patched_data.data(), patched_data.size()));
+ return true;
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/install_operation_executor.h b/payload_consumer/install_operation_executor.h
new file mode 100644
index 00000000..6c84fafa
--- /dev/null
+++ b/payload_consumer/install_operation_executor.h
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2021 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_INSTALL_OPERATION_EXECUTOR_H
+#define UPDATE_ENGINE_INSTALL_OPERATION_EXECUTOR_H
+
+#include <memory>
+
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+class InstallOperationExecutor {
+ public:
+ explicit InstallOperationExecutor(size_t block_size)
+ : block_size_(block_size) {}
+
+ bool ExecuteReplaceOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ const void* data,
+ size_t count);
+ bool ExecuteZeroOrDiscardOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer);
+ bool ExecuteSourceCopyOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd);
+
+ bool ExecuteDiffOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count);
+
+ private:
+ bool ExecuteSourceBsdiffOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count);
+ bool ExecutePuffDiffOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count);
+ bool ExecuteZucchiniOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count);
+ bool ExecuteLz4diffOperation(const InstallOperation& operation,
+ std::unique_ptr<ExtentWriter> writer,
+ FileDescriptorPtr source_fd,
+ const void* data,
+ size_t count);
+
+ size_t block_size_;
+};
+
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/install_operation_executor_unittest.cc b/payload_consumer/install_operation_executor_unittest.cc
new file mode 100644
index 00000000..705d8f84
--- /dev/null
+++ b/payload_consumer/install_operation_executor_unittest.cc
@@ -0,0 +1,283 @@
+//
+// Copyright (C) 2021 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/payload_consumer/install_operation_executor.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <algorithm>
+#include <array>
+#include <cstring>
+#include <limits>
+#include <memory>
+#include <ostream>
+#include <utility>
+#include <vector>
+
+#include <brillo/secure_blob.h>
+#include <gtest/gtest.h>
+#include <update_engine/update_metadata.pb.h>
+#include <zucchini/buffer_view.h>
+#include <zucchini/patch_writer.h>
+#include <zucchini/zucchini.h>
+#include <puffin/brotli_util.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/fake_extent_writer.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_generator/delta_diff_utils.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+namespace chromeos_update_engine {
+
+std::ostream& operator<<(std::ostream& out,
+ const chromeos_update_engine::InstallOperation& op) {
+ out << InstallOperationTypeName(op.type())
+ << " SRC: " << ExtentsToString(op.src_extents())
+ << " DST: " << ExtentsToString(op.dst_extents());
+ return out;
+}
+
+namespace {} // namespace
+
+class InstallOperationExecutorTest : public ::testing::Test {
+ public:
+ static constexpr size_t NUM_BLOCKS = 10;
+ static constexpr size_t BLOCK_SIZE = 4096;
+ void SetUp() override {
+ // Fill source partition with arbitrary data.
+ source_data_.resize(NUM_BLOCKS * BLOCK_SIZE);
+ target_data_.resize(NUM_BLOCKS * BLOCK_SIZE);
+ for (size_t i = 0; i < NUM_BLOCKS; i++) {
+ // Fill block with arbitrary data. We don't care about what data is being
+ // written to source partition, so as long as each block is slightly
+ // different.
+ uint32_t offset = i * BLOCK_SIZE;
+ std::fill(source_data_.begin() + offset,
+ source_data_.begin() + offset + BLOCK_SIZE,
+ i);
+ std::fill(target_data_.begin() + offset,
+ target_data_.begin() + offset + BLOCK_SIZE,
+ NUM_BLOCKS + i);
+ }
+
+ ASSERT_TRUE(
+ utils::WriteAll(source_.fd(), source_data_.data(), source_data_.size()))
+ << "Failed to write to source partition file: " << strerror(errno);
+ ASSERT_TRUE(
+ utils::WriteAll(target_.fd(), target_data_.data(), target_data_.size()))
+ << "Failed to write to target partition file: " << strerror(errno);
+ fsync(source_.fd());
+ fsync(target_.fd());
+
+ // set target partition to have same size as source partition.
+ // update_engine mostly assumes that target partition have the desired
+ // size, so we mock that.
+ ASSERT_GE(ftruncate64(target_.fd(), NUM_BLOCKS * BLOCK_SIZE), 0)
+ << strerror(errno) << " failed to set target partition size to "
+ << NUM_BLOCKS * BLOCK_SIZE;
+
+ source_fd_->Open(source_.path().c_str(), O_RDONLY);
+ target_fd_->Open(target_.path().c_str(), O_RDWR);
+ }
+
+ void VerityUntouchedExtents(const InstallOperation& op) {
+ ExtentRanges extent_set;
+ extent_set.AddExtent(ExtentForRange(0, 10));
+ extent_set.SubtractRepeatedExtents(op.dst_extents());
+ std::vector<Extent> untouched_extents{extent_set.extent_set().begin(),
+ extent_set.extent_set().end()};
+ brillo::Blob actual_data;
+ ASSERT_TRUE(utils::ReadExtents(target_.path(),
+ untouched_extents,
+ &actual_data,
+ extent_set.blocks() * BLOCK_SIZE,
+ BLOCK_SIZE));
+ const auto untouched_blocks = ExpandExtents(untouched_extents);
+ for (size_t i = 0; i < actual_data.size(); i++) {
+ const auto block_offset = i / BLOCK_SIZE;
+ const auto offset = i % BLOCK_SIZE;
+ ASSERT_EQ(
+ actual_data[i],
+ static_cast<uint8_t>(NUM_BLOCKS + untouched_blocks[block_offset]))
+ << "After performing op " << op << ", offset " << offset
+ << " in block " << GetNthBlock(untouched_extents, block_offset)
+ << " is modified but it shouldn't.";
+ }
+ }
+ ScopedTempFile source_{"source_partition.XXXXXXXX", true};
+ ScopedTempFile target_{"target_partition.XXXXXXXX", true};
+ FileDescriptorPtr source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
+ FileDescriptorPtr target_fd_ = std::make_shared<EintrSafeFileDescriptor>();
+ std::vector<uint8_t> source_data_;
+ std::vector<uint8_t> target_data_;
+
+ InstallOperationExecutor executor_{BLOCK_SIZE};
+};
+
+TEST_F(InstallOperationExecutorTest, ReplaceOpTest) {
+ InstallOperation op;
+ op.set_type(InstallOperation::REPLACE);
+ *op.mutable_dst_extents()->Add() = ExtentForRange(2, 2);
+ *op.mutable_dst_extents()->Add() = ExtentForRange(6, 2);
+ op.set_data_length(BLOCK_SIZE * 4);
+ brillo::Blob expected_data;
+ expected_data.resize(BLOCK_SIZE * 4);
+ // Fill buffer with arbitrary data. Doesn't matter what it is. Each block
+ // needs to be different so that we can ensure the InstallOperationExecutor
+ // is reading data from the correct offset.
+ for (int i = 0; i < 4; i++) {
+ std::fill(&expected_data[i * BLOCK_SIZE],
+ &expected_data[(i + 1) * BLOCK_SIZE],
+ i + 99);
+ }
+ auto writer = std::make_unique<DirectExtentWriter>(target_fd_);
+ ASSERT_TRUE(executor_.ExecuteReplaceOperation(
+ op, std::move(writer), expected_data.data(), expected_data.size()));
+
+ brillo::Blob actual_data;
+ utils::ReadExtents(
+ target_.path(),
+ std::vector<Extent>{op.dst_extents().begin(), op.dst_extents().end()},
+ &actual_data,
+ BLOCK_SIZE * 4,
+ BLOCK_SIZE);
+ ASSERT_EQ(actual_data, expected_data);
+ VerityUntouchedExtents(op);
+}
+
+TEST_F(InstallOperationExecutorTest, ZeroOrDiscardeOpTest) {
+ InstallOperation op;
+ op.set_type(InstallOperation::ZERO);
+ *op.mutable_dst_extents()->Add() = ExtentForRange(2, 2);
+ *op.mutable_dst_extents()->Add() = ExtentForRange(6, 2);
+ auto writer = std::make_unique<DirectExtentWriter>(target_fd_);
+ ASSERT_TRUE(executor_.ExecuteZeroOrDiscardOperation(op, std::move(writer)));
+ brillo::Blob actual_data;
+ utils::ReadExtents(
+ target_.path(),
+ std::vector<Extent>{op.dst_extents().begin(), op.dst_extents().end()},
+ &actual_data,
+ BLOCK_SIZE * 4,
+ BLOCK_SIZE);
+ for (size_t i = 0; i < actual_data.size(); i++) {
+ ASSERT_EQ(actual_data[i], 0U) << "position " << i << " isn't zeroed!";
+ }
+ VerityUntouchedExtents(op);
+}
+
+TEST_F(InstallOperationExecutorTest, SourceCopyOpTest) {
+ InstallOperation op;
+ op.set_type(InstallOperation::SOURCE_COPY);
+ *op.mutable_src_extents()->Add() = ExtentForRange(1, 2);
+ *op.mutable_src_extents()->Add() = ExtentForRange(5, 1);
+ *op.mutable_src_extents()->Add() = ExtentForRange(7, 1);
+
+ *op.mutable_dst_extents()->Add() = ExtentForRange(2, 2);
+ *op.mutable_dst_extents()->Add() = ExtentForRange(6, 2);
+
+ auto writer = std::make_unique<DirectExtentWriter>(target_fd_);
+ ASSERT_TRUE(
+ executor_.ExecuteSourceCopyOperation(op, std::move(writer), source_fd_));
+ brillo::Blob actual_data;
+ utils::ReadExtents(
+ target_.path(),
+ std::vector<Extent>{op.dst_extents().begin(), op.dst_extents().end()},
+ &actual_data,
+ BLOCK_SIZE * 4,
+ BLOCK_SIZE);
+ brillo::Blob expected_data;
+ utils::ReadExtents(
+ source_.path(),
+ std::vector<Extent>{op.src_extents().begin(), op.src_extents().end()},
+ &expected_data,
+ BLOCK_SIZE * 4,
+ BLOCK_SIZE);
+
+ ASSERT_EQ(expected_data.size(), actual_data.size());
+ for (size_t i = 0; i < actual_data.size(); i++) {
+ const auto block_offset = i / BLOCK_SIZE;
+ const auto offset = i % BLOCK_SIZE;
+ ASSERT_EQ(actual_data[i], expected_data[i])
+ << "After performing op " << op << ", offset " << offset << " in ["
+ << GetNthBlock(op.src_extents(), block_offset) << " -> "
+ << GetNthBlock(op.dst_extents(), block_offset) << "]"
+ << " is not copied correctly";
+ }
+ VerityUntouchedExtents(op);
+}
+
+TEST_F(InstallOperationExecutorTest, ZucchiniOpTest) {
+ InstallOperation op;
+ op.set_type(InstallOperation::ZUCCHINI);
+ *op.mutable_src_extents()->Add() = ExtentForRange(0, NUM_BLOCKS);
+ *op.mutable_dst_extents()->Add() = ExtentForRange(0, NUM_BLOCKS);
+
+ // Make a zucchini patch
+ std::vector<Extent> src_extents{ExtentForRange(0, NUM_BLOCKS)};
+ std::vector<Extent> dst_extents{ExtentForRange(0, NUM_BLOCKS)};
+ PayloadGenerationConfig config{
+ .version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kZucchiniMinorPayloadVersion)};
+ const FilesystemInterface::File empty;
+ diff_utils::BestDiffGenerator best_diff_generator(
+ source_data_, target_data_, src_extents, dst_extents, empty, empty, config);
+ std::vector<uint8_t> patch_data = target_data_; // Fake the full operation
+ AnnotatedOperation aop;
+ // Zucchini is enabled only on files with certain extensions
+ aop.name = "test.so";
+ ASSERT_TRUE(best_diff_generator.GenerateBestDiffOperation(
+ {{InstallOperation::ZUCCHINI, 1024 * BLOCK_SIZE}}, &aop, &patch_data));
+ ASSERT_EQ(InstallOperation::ZUCCHINI, aop.op.type());
+
+ // Call the executor
+ ScopedTempFile patched{"patched.XXXXXXXX", true};
+ FileDescriptorPtr patched_fd = std::make_shared<EintrSafeFileDescriptor>();
+ patched_fd->Open(patched.path().c_str(), O_RDWR);
+ std::unique_ptr<ExtentWriter> writer(new DirectExtentWriter(patched_fd));
+ writer->Init(op.dst_extents(), BLOCK_SIZE);
+ ASSERT_TRUE(executor_.ExecuteDiffOperation(
+ op, std::move(writer), source_fd_, patch_data.data(), patch_data.size()));
+
+ // Compare the result
+ std::vector<uint8_t> patched_data;
+ ASSERT_TRUE(utils::ReadFile(patched.path(), &patched_data));
+ ASSERT_EQ(NUM_BLOCKS * BLOCK_SIZE, patched_data.size());
+ ASSERT_EQ(target_data_, patched_data);
+}
+
+TEST_F(InstallOperationExecutorTest, GetNthBlockTest) {
+ std::vector<Extent> extents;
+ extents.emplace_back(ExtentForRange(10, 3));
+ extents.emplace_back(ExtentForRange(20, 2));
+ extents.emplace_back(ExtentForRange(30, 1));
+ extents.emplace_back(ExtentForRange(40, 4));
+
+ ASSERT_EQ(GetNthBlock(extents, 0), 10U);
+ ASSERT_EQ(GetNthBlock(extents, 2), 12U);
+ ASSERT_EQ(GetNthBlock(extents, 3), 20U);
+ ASSERT_EQ(GetNthBlock(extents, 4), 21U);
+ ASSERT_EQ(GetNthBlock(extents, 5), 30U);
+ ASSERT_EQ(GetNthBlock(extents, 6), 40U);
+ ASSERT_EQ(GetNthBlock(extents, 7), 41U);
+ ASSERT_EQ(GetNthBlock(extents, 8), 42U);
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/install_plan.cc b/payload_consumer/install_plan.cc
index 06b7dd8c..91eb53b3 100644
--- a/payload_consumer/install_plan.cc
+++ b/payload_consumer/install_plan.cc
@@ -27,6 +27,7 @@
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/update_metadata.pb.h"
using std::string;
using std::vector;
@@ -186,4 +187,120 @@ bool InstallPlan::Partition::operator==(
postinstall_optional == that.postinstall_optional);
}
+bool InstallPlan::Partition::ParseVerityConfig(
+ const PartitionUpdate& partition) {
+ if (partition.has_hash_tree_extent()) {
+ Extent extent = partition.hash_tree_data_extent();
+ hash_tree_data_offset = extent.start_block() * block_size;
+ hash_tree_data_size = extent.num_blocks() * block_size;
+ extent = partition.hash_tree_extent();
+ hash_tree_offset = extent.start_block() * block_size;
+ hash_tree_size = extent.num_blocks() * block_size;
+ uint64_t hash_tree_data_end = hash_tree_data_offset + hash_tree_data_size;
+ if (hash_tree_offset < hash_tree_data_end) {
+ LOG(ERROR) << "Invalid hash tree extents, hash tree data ends at "
+ << hash_tree_data_end << ", but hash tree starts at "
+ << hash_tree_offset;
+ return false;
+ }
+ hash_tree_algorithm = partition.hash_tree_algorithm();
+ hash_tree_salt.assign(partition.hash_tree_salt().begin(),
+ partition.hash_tree_salt().end());
+ }
+ if (partition.has_fec_extent()) {
+ Extent extent = partition.fec_data_extent();
+ fec_data_offset = extent.start_block() * block_size;
+ fec_data_size = extent.num_blocks() * block_size;
+ extent = partition.fec_extent();
+ fec_offset = extent.start_block() * block_size;
+ fec_size = extent.num_blocks() * block_size;
+ uint64_t fec_data_end = fec_data_offset + fec_data_size;
+ if (fec_offset < fec_data_end) {
+ LOG(ERROR) << "Invalid fec extents, fec data ends at " << fec_data_end
+ << ", but fec starts at " << fec_offset;
+ return false;
+ }
+ fec_roots = partition.fec_roots();
+ }
+ return true;
+}
+
+template <typename PartitinoUpdateArray>
+bool InstallPlan::ParseManifestToInstallPlan(
+ const PartitinoUpdateArray& partitions,
+ BootControlInterface* boot_control,
+ size_t block_size,
+ InstallPlan* install_plan,
+ ErrorCode* error) {
+ // Fill in the InstallPlan::partitions based on the partitions from the
+ // payload.
+ for (const PartitionUpdate& partition : partitions) {
+ InstallPlan::Partition install_part;
+ install_part.name = partition.partition_name();
+ install_part.run_postinstall =
+ partition.has_run_postinstall() && partition.run_postinstall();
+ if (install_part.run_postinstall) {
+ install_part.postinstall_path =
+ (partition.has_postinstall_path() ? partition.postinstall_path()
+ : kPostinstallDefaultScript);
+ install_part.filesystem_type = partition.filesystem_type();
+ install_part.postinstall_optional = partition.postinstall_optional();
+ }
+
+ if (partition.has_old_partition_info()) {
+ const PartitionInfo& info = partition.old_partition_info();
+ install_part.source_size = info.size();
+ install_part.source_hash.assign(info.hash().begin(), info.hash().end());
+ }
+
+ if (!partition.has_new_partition_info()) {
+ LOG(ERROR) << "Unable to get new partition hash info on partition "
+ << install_part.name << ".";
+ *error = ErrorCode::kDownloadNewPartitionInfoError;
+ return false;
+ }
+ const PartitionInfo& info = partition.new_partition_info();
+ install_part.target_size = info.size();
+ install_part.target_hash.assign(info.hash().begin(), info.hash().end());
+
+ install_part.block_size = block_size;
+ if (!install_part.ParseVerityConfig(partition)) {
+ *error = ErrorCode::kDownloadNewPartitionInfoError;
+ LOG(INFO) << "Failed to parse partition `" << partition.partition_name()
+ << "` verity configs";
+ return false;
+ }
+
+ install_plan->partitions.push_back(install_part);
+ }
+
+ // TODO(xunchang) only need to load the partitions for those in payload.
+ // Because we have already loaded the other once when generating SOURCE_COPY
+ // operations.
+ if (!install_plan->LoadPartitionsFromSlots(boot_control)) {
+ LOG(ERROR) << "Unable to determine all the partition devices.";
+ *error = ErrorCode::kInstallDeviceOpenError;
+ return false;
+ }
+ return true;
+}
+
+bool InstallPlan::ParsePartitions(
+ const std::vector<PartitionUpdate>& partitions,
+ BootControlInterface* boot_control,
+ size_t block_size,
+ ErrorCode* error) {
+ return ParseManifestToInstallPlan(
+ partitions, boot_control, block_size, this, error);
+}
+
+bool InstallPlan::ParsePartitions(
+ const google::protobuf::RepeatedPtrField<PartitionUpdate>& partitions,
+ BootControlInterface* boot_control,
+ size_t block_size,
+ ErrorCode* error) {
+ return ParseManifestToInstallPlan(
+ partitions, boot_control, block_size, this, error);
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_consumer/install_plan.h b/payload_consumer/install_plan.h
index 7c77789b..883aa60c 100644
--- a/payload_consumer/install_plan.h
+++ b/payload_consumer/install_plan.h
@@ -47,10 +47,30 @@ struct InstallPlan {
void Dump() const;
std::string ToString() const;
+ private:
// Loads the |source_path| and |target_path| of all |partitions| based on the
// |source_slot| and |target_slot| if available. Returns whether it succeeded
// to load all the partitions for the valid slots.
bool LoadPartitionsFromSlots(BootControlInterface* boot_control);
+ template <typename PartitinoUpdateArray>
+ static bool ParseManifestToInstallPlan(const PartitinoUpdateArray& partitions,
+ BootControlInterface* boot_control,
+ size_t block_size,
+ InstallPlan* install_plan,
+ ErrorCode* error);
+
+ public:
+ // Load all partitions in |partitions| into this install plan, will also
+ // populate |source_path|, |target_pathh|, fec information, partition sizes.
+ bool ParsePartitions(const std::vector<PartitionUpdate>& partitions,
+ BootControlInterface* boot_control,
+ size_t block_size,
+ ErrorCode* error);
+ bool ParsePartitions(
+ const google::protobuf::RepeatedPtrField<PartitionUpdate>& partitions,
+ BootControlInterface* boot_control,
+ size_t block_size,
+ ErrorCode* error);
bool is_resume{false};
std::string download_url; // url to download from
@@ -136,6 +156,8 @@ struct InstallPlan {
uint64_t fec_offset{0};
uint64_t fec_size{0};
uint32_t fec_roots{0};
+
+ bool ParseVerityConfig(const PartitionUpdate&);
};
std::vector<Partition> partitions;
diff --git a/payload_consumer/mock_partition_writer.h b/payload_consumer/mock_partition_writer.h
index b056010d..0f213372 100644
--- a/payload_consumer/mock_partition_writer.h
+++ b/payload_consumer/mock_partition_writer.h
@@ -54,11 +54,7 @@ class MockPartitionWriter : public PartitionWriter {
(const InstallOperation&, ErrorCode*),
(override));
MOCK_METHOD(bool,
- PerformSourceBsdiffOperation,
- (const InstallOperation&, ErrorCode*, const void*, size_t),
- (override));
- MOCK_METHOD(bool,
- PerformPuffDiffOperation,
+ PerformDiffOperation,
(const InstallOperation&, ErrorCode*, const void*, size_t),
(override));
};
diff --git a/payload_consumer/mount_history.cc b/payload_consumer/mount_history.cc
index d699ad92..7fe48501 100644
--- a/payload_consumer/mount_history.cc
+++ b/payload_consumer/mount_history.cc
@@ -72,7 +72,7 @@ void LogMountHistory(const FileDescriptorPtr blockdevice_fd) {
if (magic == 0xEF53) {
// Timestamps can be updated by fsck without updating mount count,
// log if any timestamp differ
- if (! (write_time == created_time && check_time == created_time)) {
+ if (!(write_time == created_time && check_time == created_time)) {
LOG(WARNING) << "Device have been modified after being created. "
<< "Filesystem created on "
<< base::Time::FromTimeT(created_time) << ", "
diff --git a/payload_consumer/partition_writer.cc b/payload_consumer/partition_writer.cc
index 6f98ba36..1fb929ea 100644
--- a/payload_consumer/partition_writer.cc
+++ b/payload_consumer/partition_writer.cc
@@ -17,18 +17,20 @@
#include <fcntl.h>
#include <linux/fs.h>
+#include <sys/mman.h>
+
+#include <inttypes.h>
#include <algorithm>
#include <initializer_list>
#include <memory>
+#include <string>
#include <utility>
#include <vector>
#include <base/strings/string_number_conversions.h>
-#include <bsdiff/bspatch.h>
-#include <puffin/puffpatch.h>
-#include <bsdiff/file_interface.h>
-#include <puffin/stream.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
#include "update_engine/common/terminator.h"
#include "update_engine/common/utils.h"
@@ -36,12 +38,13 @@
#include "update_engine/payload_consumer/cached_file_descriptor.h"
#include "update_engine/payload_consumer/extent_reader.h"
#include "update_engine/payload_consumer/extent_writer.h"
-#include "update_engine/payload_consumer/fec_file_descriptor.h"
#include "update_engine/payload_consumer/file_descriptor_utils.h"
+#include "update_engine/payload_consumer/install_operation_executor.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/payload_consumer/mount_history.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_consumer/xz_extent_writer.h"
+#include "update_engine/payload_generator/extent_utils.h"
namespace chromeos_update_engine {
@@ -108,135 +111,6 @@ FileDescriptorPtr OpenFile(const char* path,
return fd;
}
-class BsdiffExtentFile : public bsdiff::FileInterface {
- public:
- BsdiffExtentFile(std::unique_ptr<ExtentReader> reader, size_t size)
- : BsdiffExtentFile(std::move(reader), nullptr, size) {}
- BsdiffExtentFile(std::unique_ptr<ExtentWriter> writer, size_t size)
- : BsdiffExtentFile(nullptr, std::move(writer), size) {}
-
- ~BsdiffExtentFile() override = default;
-
- bool Read(void* buf, size_t count, size_t* bytes_read) override {
- TEST_AND_RETURN_FALSE(reader_->Read(buf, count));
- *bytes_read = count;
- offset_ += count;
- return true;
- }
-
- bool Write(const void* buf, size_t count, size_t* bytes_written) override {
- TEST_AND_RETURN_FALSE(writer_->Write(buf, count));
- *bytes_written = count;
- offset_ += count;
- return true;
- }
-
- bool Seek(off_t pos) override {
- if (reader_ != nullptr) {
- TEST_AND_RETURN_FALSE(reader_->Seek(pos));
- offset_ = pos;
- } else {
- // For writes technically there should be no change of position, or it
- // should be equivalent of current offset.
- TEST_AND_RETURN_FALSE(offset_ == static_cast<uint64_t>(pos));
- }
- return true;
- }
-
- bool Close() override { return true; }
-
- bool GetSize(uint64_t* size) override {
- *size = size_;
- return true;
- }
-
- private:
- BsdiffExtentFile(std::unique_ptr<ExtentReader> reader,
- std::unique_ptr<ExtentWriter> writer,
- size_t size)
- : reader_(std::move(reader)),
- writer_(std::move(writer)),
- size_(size),
- offset_(0) {}
-
- std::unique_ptr<ExtentReader> reader_;
- std::unique_ptr<ExtentWriter> writer_;
- uint64_t size_;
- uint64_t offset_;
-
- DISALLOW_COPY_AND_ASSIGN(BsdiffExtentFile);
-};
-// A class to be passed to |puffpatch| for reading from |source_fd_| and writing
-// into |target_fd_|.
-class PuffinExtentStream : public puffin::StreamInterface {
- public:
- // Constructor for creating a stream for reading from an |ExtentReader|.
- PuffinExtentStream(std::unique_ptr<ExtentReader> reader, uint64_t size)
- : PuffinExtentStream(std::move(reader), nullptr, size) {}
-
- // Constructor for creating a stream for writing to an |ExtentWriter|.
- PuffinExtentStream(std::unique_ptr<ExtentWriter> writer, uint64_t size)
- : PuffinExtentStream(nullptr, std::move(writer), size) {}
-
- ~PuffinExtentStream() override = default;
-
- bool GetSize(uint64_t* size) const override {
- *size = size_;
- return true;
- }
-
- bool GetOffset(uint64_t* offset) const override {
- *offset = offset_;
- return true;
- }
-
- bool Seek(uint64_t offset) override {
- if (is_read_) {
- TEST_AND_RETURN_FALSE(reader_->Seek(offset));
- offset_ = offset;
- } else {
- // For writes technically there should be no change of position, or it
- // should equivalent of current offset.
- TEST_AND_RETURN_FALSE(offset_ == offset);
- }
- return true;
- }
-
- bool Read(void* buffer, size_t count) override {
- TEST_AND_RETURN_FALSE(is_read_);
- TEST_AND_RETURN_FALSE(reader_->Read(buffer, count));
- offset_ += count;
- return true;
- }
-
- bool Write(const void* buffer, size_t count) override {
- TEST_AND_RETURN_FALSE(!is_read_);
- TEST_AND_RETURN_FALSE(writer_->Write(buffer, count));
- offset_ += count;
- return true;
- }
-
- bool Close() override { return true; }
-
- private:
- PuffinExtentStream(std::unique_ptr<ExtentReader> reader,
- std::unique_ptr<ExtentWriter> writer,
- uint64_t size)
- : reader_(std::move(reader)),
- writer_(std::move(writer)),
- size_(size),
- offset_(0),
- is_read_(reader_ ? true : false) {}
-
- std::unique_ptr<ExtentReader> reader_;
- std::unique_ptr<ExtentWriter> writer_;
- uint64_t size_;
- uint64_t offset_;
- bool is_read_;
-
- DISALLOW_COPY_AND_ASSIGN(PuffinExtentStream);
-};
-
PartitionWriter::PartitionWriter(
const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
@@ -246,8 +120,10 @@ PartitionWriter::PartitionWriter(
: partition_update_(partition_update),
install_part_(install_part),
dynamic_control_(dynamic_control),
+ verified_source_fd_(block_size, install_part.source_path),
interactive_(is_interactive),
- block_size_(block_size) {}
+ block_size_(block_size),
+ install_op_executor_(block_size) {}
PartitionWriter::~PartitionWriter() {
Close();
@@ -261,9 +137,7 @@ bool PartitionWriter::OpenSourcePartition(uint32_t source_slot,
}
if (install_part_.source_size > 0 && !install_part_.source_path.empty()) {
source_path_ = install_part_.source_path;
- int err;
- source_fd_ = OpenFile(source_path_.c_str(), O_RDONLY, false, &err);
- if (source_fd_ == nullptr) {
+ if (!verified_source_fd_.Open()) {
LOG(ERROR) << "Unable to open source partition " << install_part_.name
<< " on slot " << BootControlInterface::SlotName(source_slot)
<< ", file " << source_path_;
@@ -319,315 +193,86 @@ bool PartitionWriter::PerformReplaceOperation(const InstallOperation& operation,
size_t count) {
// Setup the ExtentWriter stack based on the operation type.
std::unique_ptr<ExtentWriter> writer = CreateBaseExtentWriter();
-
- if (operation.type() == InstallOperation::REPLACE_BZ) {
- writer.reset(new BzipExtentWriter(std::move(writer)));
- } else if (operation.type() == InstallOperation::REPLACE_XZ) {
- writer.reset(new XzExtentWriter(std::move(writer)));
- }
-
- TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
- TEST_AND_RETURN_FALSE(writer->Write(data, operation.data_length()));
-
- return true;
+ return install_op_executor_.ExecuteReplaceOperation(
+ operation, std::move(writer), data, count);
}
bool PartitionWriter::PerformZeroOrDiscardOperation(
const InstallOperation& operation) {
#ifdef BLKZEROOUT
- bool attempt_ioctl = true;
int request =
(operation.type() == InstallOperation::ZERO ? BLKZEROOUT : BLKDISCARD);
#else // !defined(BLKZEROOUT)
- bool attempt_ioctl = false;
- int request = 0;
+ auto writer = CreateBaseExtentWriter();
+ return install_op_executor_.ExecuteZeroOrDiscardOperation(operation,
+ writer.get());
#endif // !defined(BLKZEROOUT)
- brillo::Blob zeros;
for (const Extent& extent : operation.dst_extents()) {
const uint64_t start = extent.start_block() * block_size_;
const uint64_t length = extent.num_blocks() * block_size_;
- if (attempt_ioctl) {
- int result = 0;
- if (target_fd_->BlkIoctl(request, start, length, &result) && result == 0)
- continue;
- attempt_ioctl = false;
- }
- // In case of failure, we fall back to writing 0 to the selected region.
- zeros.resize(16 * block_size_);
- for (uint64_t offset = 0; offset < length; offset += zeros.size()) {
- uint64_t chunk_length =
- std::min(length - offset, static_cast<uint64_t>(zeros.size()));
- TEST_AND_RETURN_FALSE(utils::WriteAll(
- target_fd_, zeros.data(), chunk_length, start + offset));
+ int result = 0;
+ if (target_fd_->BlkIoctl(request, start, length, &result) && result == 0) {
+ continue;
}
+ // In case of failure, we fall back to writing 0 for the entire operation.
+ PLOG(WARNING) << "BlkIoctl failed. Falling back to write 0s for remainder "
+ "of this operation.";
+ auto writer = CreateBaseExtentWriter();
+ return install_op_executor_.ExecuteZeroOrDiscardOperation(
+ operation, std::move(writer));
}
return true;
}
bool PartitionWriter::PerformSourceCopyOperation(
const InstallOperation& operation, ErrorCode* error) {
- TEST_AND_RETURN_FALSE(source_fd_ != nullptr);
-
// The device may optimize the SOURCE_COPY operation.
// Being this a device-specific optimization let DynamicPartitionController
// decide it the operation should be skipped.
const PartitionUpdate& partition = partition_update_;
- const auto& partition_control = dynamic_control_;
InstallOperation buf;
- const bool should_optimize = partition_control->OptimizeOperation(
+ const bool should_optimize = dynamic_control_->OptimizeOperation(
partition.partition_name(), operation, &buf);
const InstallOperation& optimized = should_optimize ? buf : operation;
- if (operation.has_src_sha256_hash()) {
- bool read_ok;
- brillo::Blob source_hash;
- brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
- operation.src_sha256_hash().end());
-
- // We fall back to use the error corrected device if the hash of the raw
- // device doesn't match or there was an error reading the source partition.
- // Note that this code will also fall back if writing the target partition
- // fails.
- if (should_optimize) {
- // Hash operation.src_extents(), then copy optimized.src_extents to
- // optimized.dst_extents.
- read_ok =
- fd_utils::ReadAndHashExtents(
- source_fd_, operation.src_extents(), block_size_, &source_hash) &&
- fd_utils::CopyAndHashExtents(source_fd_,
- optimized.src_extents(),
- target_fd_,
- optimized.dst_extents(),
- block_size_,
- nullptr /* skip hashing */);
- } else {
- read_ok = fd_utils::CopyAndHashExtents(source_fd_,
- operation.src_extents(),
- target_fd_,
- operation.dst_extents(),
- block_size_,
- &source_hash);
- }
- if (read_ok && expected_source_hash == source_hash)
- return true;
- LOG(WARNING) << "Source hash from RAW device mismatched, attempting to "
- "correct using ECC";
- if (!OpenCurrentECCPartition()) {
- // The following function call will return false since the source hash
- // mismatches, but we still want to call it so it prints the appropriate
- // log message.
- return ValidateSourceHash(source_hash, operation, source_fd_, error);
- }
-
- LOG(WARNING) << "Source hash from RAW device mismatched: found "
- << base::HexEncode(source_hash.data(), source_hash.size())
- << ", expected "
- << base::HexEncode(expected_source_hash.data(),
- expected_source_hash.size());
- if (should_optimize) {
- TEST_AND_RETURN_FALSE(fd_utils::ReadAndHashExtents(
- source_ecc_fd_, operation.src_extents(), block_size_, &source_hash));
- TEST_AND_RETURN_FALSE(
- fd_utils::CopyAndHashExtents(source_ecc_fd_,
- optimized.src_extents(),
- target_fd_,
- optimized.dst_extents(),
- block_size_,
- nullptr /* skip hashing */));
- } else {
- TEST_AND_RETURN_FALSE(
- fd_utils::CopyAndHashExtents(source_ecc_fd_,
- operation.src_extents(),
- target_fd_,
- operation.dst_extents(),
- block_size_,
- &source_hash));
- }
- TEST_AND_RETURN_FALSE(
- ValidateSourceHash(source_hash, operation, source_ecc_fd_, error));
- // At this point reading from the error corrected device worked, but
- // reading from the raw device failed, so this is considered a recovered
- // failure.
- source_ecc_recovered_failures_++;
- } else {
- // When the operation doesn't include a source hash, we attempt the error
- // corrected device first since we can't verify the block in the raw device
- // at this point, but we fall back to the raw device since the error
- // corrected device can be shorter or not available.
-
- if (OpenCurrentECCPartition() &&
- fd_utils::CopyAndHashExtents(source_ecc_fd_,
- optimized.src_extents(),
- target_fd_,
- optimized.dst_extents(),
- block_size_,
- nullptr)) {
- return true;
- }
- TEST_AND_RETURN_FALSE(fd_utils::CopyAndHashExtents(source_fd_,
- optimized.src_extents(),
- target_fd_,
- optimized.dst_extents(),
- block_size_,
- nullptr));
+ // Invoke ChooseSourceFD with original operation, so that it can properly
+ // verify source hashes. Optimized operation might contain a smaller set of
+ // extents, or completely empty.
+ auto source_fd = ChooseSourceFD(operation, error);
+ if (source_fd == nullptr) {
+ LOG(ERROR) << "Unrecoverable source hash mismatch found on partition "
+ << partition.partition_name()
+ << " extents: " << ExtentsToString(operation.src_extents());
+ return false;
}
- return true;
-}
-
-bool PartitionWriter::PerformSourceBsdiffOperation(
- const InstallOperation& operation,
- ErrorCode* error,
- const void* data,
- size_t count) {
- FileDescriptorPtr source_fd = ChooseSourceFD(operation, error);
- TEST_AND_RETURN_FALSE(source_fd != nullptr);
-
- auto reader = std::make_unique<DirectExtentReader>();
- TEST_AND_RETURN_FALSE(
- reader->Init(source_fd, operation.src_extents(), block_size_));
- auto src_file = std::make_unique<BsdiffExtentFile>(
- std::move(reader),
- utils::BlocksInExtents(operation.src_extents()) * block_size_);
auto writer = CreateBaseExtentWriter();
- TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
- auto dst_file = std::make_unique<BsdiffExtentFile>(
- std::move(writer),
- utils::BlocksInExtents(operation.dst_extents()) * block_size_);
-
- TEST_AND_RETURN_FALSE(bsdiff::bspatch(std::move(src_file),
- std::move(dst_file),
- reinterpret_cast<const uint8_t*>(data),
- count) == 0);
- return true;
+ return install_op_executor_.ExecuteSourceCopyOperation(
+ optimized, std::move(writer), source_fd);
}
-bool PartitionWriter::PerformPuffDiffOperation(
- const InstallOperation& operation,
- ErrorCode* error,
- const void* data,
- size_t count) {
+bool PartitionWriter::PerformDiffOperation(const InstallOperation& operation,
+ ErrorCode* error,
+ const void* data,
+ size_t count) {
FileDescriptorPtr source_fd = ChooseSourceFD(operation, error);
TEST_AND_RETURN_FALSE(source_fd != nullptr);
- auto reader = std::make_unique<DirectExtentReader>();
- TEST_AND_RETURN_FALSE(
- reader->Init(source_fd, operation.src_extents(), block_size_));
- puffin::UniqueStreamPtr src_stream(new PuffinExtentStream(
- std::move(reader),
- utils::BlocksInExtents(operation.src_extents()) * block_size_));
-
auto writer = CreateBaseExtentWriter();
- TEST_AND_RETURN_FALSE(writer->Init(operation.dst_extents(), block_size_));
- puffin::UniqueStreamPtr dst_stream(new PuffinExtentStream(
- std::move(writer),
- utils::BlocksInExtents(operation.dst_extents()) * block_size_));
-
- constexpr size_t kMaxCacheSize = 5 * 1024 * 1024; // Total 5MB cache.
- TEST_AND_RETURN_FALSE(
- puffin::PuffPatch(std::move(src_stream),
- std::move(dst_stream),
- reinterpret_cast<const uint8_t*>(data),
- count,
- kMaxCacheSize));
- return true;
+ return install_op_executor_.ExecuteDiffOperation(
+ operation, std::move(writer), source_fd, data, count);
}
FileDescriptorPtr PartitionWriter::ChooseSourceFD(
const InstallOperation& operation, ErrorCode* error) {
- if (source_fd_ == nullptr) {
- LOG(ERROR) << "ChooseSourceFD fail: source_fd_ == nullptr";
- return nullptr;
- }
-
- if (!operation.has_src_sha256_hash()) {
- // When the operation doesn't include a source hash, we attempt the error
- // corrected device first since we can't verify the block in the raw device
- // at this point, but we first need to make sure all extents are readable
- // since the error corrected device can be shorter or not available.
- if (OpenCurrentECCPartition() &&
- fd_utils::ReadAndHashExtents(
- source_ecc_fd_, operation.src_extents(), block_size_, nullptr)) {
- return source_ecc_fd_;
- }
- return source_fd_;
- }
-
- brillo::Blob source_hash;
- brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
- operation.src_sha256_hash().end());
- if (fd_utils::ReadAndHashExtents(
- source_fd_, operation.src_extents(), block_size_, &source_hash) &&
- source_hash == expected_source_hash) {
- return source_fd_;
- }
- // We fall back to use the error corrected device if the hash of the raw
- // device doesn't match or there was an error reading the source partition.
- if (!OpenCurrentECCPartition()) {
- // The following function call will return false since the source hash
- // mismatches, but we still want to call it so it prints the appropriate
- // log message.
- ValidateSourceHash(source_hash, operation, source_fd_, error);
- return nullptr;
- }
- LOG(WARNING) << "Source hash from RAW device mismatched: found "
- << base::HexEncode(source_hash.data(), source_hash.size())
- << ", expected "
- << base::HexEncode(expected_source_hash.data(),
- expected_source_hash.size());
-
- if (fd_utils::ReadAndHashExtents(
- source_ecc_fd_, operation.src_extents(), block_size_, &source_hash) &&
- ValidateSourceHash(source_hash, operation, source_ecc_fd_, error)) {
- // At this point reading from the error corrected device worked, but
- // reading from the raw device failed, so this is considered a recovered
- // failure.
- source_ecc_recovered_failures_++;
- return source_ecc_fd_;
- }
- return nullptr;
-}
-
-bool PartitionWriter::OpenCurrentECCPartition() {
- // No support for ECC for full payloads.
- // Full payload should not have any opeartion that requires ECC partitions.
- if (source_ecc_fd_)
- return true;
-
- if (source_ecc_open_failure_)
- return false;
-
-#if USE_FEC
- const PartitionUpdate& partition = partition_update_;
- const InstallPlan::Partition& install_part = install_part_;
- std::string path = install_part.source_path;
- FileDescriptorPtr fd(new FecFileDescriptor());
- if (!fd->Open(path.c_str(), O_RDONLY, 0)) {
- PLOG(ERROR) << "Unable to open ECC source partition "
- << partition.partition_name() << ", file " << path;
- source_ecc_open_failure_ = true;
- return false;
- }
- source_ecc_fd_ = fd;
-#else
- // No support for ECC compiled.
- source_ecc_open_failure_ = true;
-#endif // USE_FEC
-
- return !source_ecc_open_failure_;
+ return verified_source_fd_.ChooseSourceFD(operation, error);
}
int PartitionWriter::Close() {
int err = 0;
- if (source_fd_ && !source_fd_->Close()) {
- err = errno;
- PLOG(ERROR) << "Error closing source partition";
- if (!err)
- err = 1;
- }
- source_fd_.reset();
+
source_path_.clear();
if (target_fd_ && !target_fd_->Close()) {
@@ -639,14 +284,6 @@ int PartitionWriter::Close() {
target_fd_.reset();
target_path_.clear();
- if (source_ecc_fd_ && !source_ecc_fd_->Close()) {
- err = errno;
- PLOG(ERROR) << "Error closing ECC source partition";
- if (!err)
- err = 1;
- }
- source_ecc_fd_.reset();
- source_ecc_open_failure_ = false;
return -err;
}
@@ -658,4 +295,54 @@ std::unique_ptr<ExtentWriter> PartitionWriter::CreateBaseExtentWriter() {
return std::make_unique<DirectExtentWriter>(target_fd_);
}
+bool PartitionWriter::ValidateSourceHash(const InstallOperation& operation,
+ const FileDescriptorPtr source_fd,
+ size_t block_size,
+ ErrorCode* error) {
+ brillo::Blob source_hash;
+ TEST_AND_RETURN_FALSE_ERRNO(fd_utils::ReadAndHashExtents(
+ source_fd, operation.src_extents(), block_size, &source_hash));
+ return ValidateSourceHash(source_hash, operation, source_fd, error);
+}
+
+bool PartitionWriter::ValidateSourceHash(const brillo::Blob& calculated_hash,
+ const InstallOperation& operation,
+ const FileDescriptorPtr source_fd,
+ ErrorCode* error) {
+ using std::string;
+ using std::vector;
+ brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
+ operation.src_sha256_hash().end());
+ if (calculated_hash != expected_source_hash) {
+ LOG(ERROR) << "The hash of the source data on disk for this operation "
+ << "doesn't match the expected value. This could mean that the "
+ << "delta update payload was targeted for another version, or "
+ << "that the source partition was modified after it was "
+ << "installed, for example, by mounting a filesystem.";
+ LOG(ERROR) << "Expected: sha256|hex = "
+ << base::HexEncode(expected_source_hash.data(),
+ expected_source_hash.size());
+ LOG(ERROR) << "Calculated: sha256|hex = "
+ << base::HexEncode(calculated_hash.data(),
+ calculated_hash.size());
+
+ vector<string> source_extents;
+ for (const Extent& ext : operation.src_extents()) {
+ source_extents.push_back(
+ base::StringPrintf("%" PRIu64 ":%" PRIu64,
+ static_cast<uint64_t>(ext.start_block()),
+ static_cast<uint64_t>(ext.num_blocks())));
+ }
+ LOG(ERROR) << "Operation source (offset:size) in blocks: "
+ << base::JoinString(source_extents, ",");
+
+ // Log remount history if this device is an ext4 partition.
+ LogMountHistory(source_fd);
+
+ *error = ErrorCode::kDownloadStateInitializationError;
+ return false;
+ }
+ return true;
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_consumer/partition_writer.h b/payload_consumer/partition_writer.h
index 82e557a2..e620c478 100644
--- a/payload_consumer/partition_writer.h
+++ b/payload_consumer/partition_writer.h
@@ -27,114 +27,102 @@
#include "update_engine/common/dynamic_partition_control_interface.h"
#include "update_engine/payload_consumer/extent_writer.h"
#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/install_operation_executor.h"
#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/payload_consumer/partition_writer_interface.h"
+#include "update_engine/payload_consumer/verified_source_fd.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
-class PartitionWriter {
+class PartitionWriter : public PartitionWriterInterface {
public:
PartitionWriter(const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
DynamicPartitionControlInterface* dynamic_control,
size_t block_size,
bool is_interactive);
- virtual ~PartitionWriter();
+ ~PartitionWriter();
static bool ValidateSourceHash(const brillo::Blob& calculated_hash,
const InstallOperation& operation,
const FileDescriptorPtr source_fd,
ErrorCode* error);
+ static bool ValidateSourceHash(const InstallOperation& operation,
+ const FileDescriptorPtr source_fd,
+ size_t block_size,
+ ErrorCode* error);
// Perform necessary initialization work before InstallOperation can be
// applied to this partition
- [[nodiscard]] virtual bool Init(const InstallPlan* install_plan,
- bool source_may_exist,
- size_t next_op_index);
+ [[nodiscard]] bool Init(const InstallPlan* install_plan,
+ bool source_may_exist,
+ size_t next_op_index) override;
// |CheckpointUpdateProgress| will be called after SetNextOpIndex(), but it's
// optional. DeltaPerformer may or may not call this everytime an operation is
// applied.
// |next_op_index| is index of next operation that should be applied.
// |next_op_index-1| is the last operation that is already applied.
- virtual void CheckpointUpdateProgress(size_t next_op_index);
+ void CheckpointUpdateProgress(size_t next_op_index) override;
// Close partition writer, when calling this function there's no guarantee
// that all |InstallOperations| are sent to |PartitionWriter|. This function
// will be called even if we are pausing/aborting the update.
- int Close();
+ int Close() override;
// These perform a specific type of operation and return true on success.
// |error| will be set if source hash mismatch, otherwise |error| might not be
// set even if it fails.
- [[nodiscard]] virtual bool PerformReplaceOperation(
- const InstallOperation& operation, const void* data, size_t count);
- [[nodiscard]] virtual bool PerformZeroOrDiscardOperation(
- const InstallOperation& operation);
-
- [[nodiscard]] virtual bool PerformSourceCopyOperation(
- const InstallOperation& operation, ErrorCode* error);
- [[nodiscard]] virtual bool PerformSourceBsdiffOperation(
- const InstallOperation& operation,
- ErrorCode* error,
- const void* data,
- size_t count);
- [[nodiscard]] virtual bool PerformPuffDiffOperation(
- const InstallOperation& operation,
- ErrorCode* error,
- const void* data,
- size_t count);
+ [[nodiscard]] bool PerformReplaceOperation(const InstallOperation& operation,
+ const void* data,
+ size_t count) override;
+ [[nodiscard]] bool PerformZeroOrDiscardOperation(
+ const InstallOperation& operation) override;
+
+ [[nodiscard]] bool PerformSourceCopyOperation(
+ const InstallOperation& operation, ErrorCode* error) override;
+ [[nodiscard]] bool PerformDiffOperation(const InstallOperation& operation,
+ ErrorCode* error,
+ const void* data,
+ size_t count) override;
// |DeltaPerformer| calls this when all Install Ops are sent to partition
// writer. No |Perform*Operation| methods will be called in the future, and
// the partition writer is expected to be closed soon.
- [[nodiscard]] virtual bool FinishedInstallOps() { return true; }
+ [[nodiscard]] bool FinishedInstallOps() override { return true; }
- protected:
+ private:
friend class PartitionWriterTest;
FRIEND_TEST(PartitionWriterTest, ChooseSourceFDTest);
- bool OpenSourcePartition(uint32_t source_slot, bool source_may_exist);
-
- bool OpenCurrentECCPartition();
- // For a given operation, choose the source fd to be used (raw device or error
- // correction device) based on the source operation hash.
- // Returns nullptr if the source hash mismatch cannot be corrected, and set
- // the |error| accordingly.
- FileDescriptorPtr ChooseSourceFD(const InstallOperation& operation,
+ [[nodiscard]] bool OpenSourcePartition(uint32_t source_slot,
+ bool source_may_exist);
+ FileDescriptorPtr ChooseSourceFD(const InstallOperation& op,
ErrorCode* error);
- [[nodiscard]] virtual std::unique_ptr<ExtentWriter> CreateBaseExtentWriter();
+
+ [[nodiscard]] std::unique_ptr<ExtentWriter> CreateBaseExtentWriter();
const PartitionUpdate& partition_update_;
const InstallPlan::Partition& install_part_;
DynamicPartitionControlInterface* dynamic_control_;
// Path to source partition
std::string source_path_;
+ VerifiedSourceFd verified_source_fd_;
// Path to target partition
std::string target_path_;
- FileDescriptorPtr source_fd_;
FileDescriptorPtr target_fd_;
const bool interactive_;
const size_t block_size_;
- // File descriptor of the error corrected source partition. Only set while
- // updating partition using a delta payload for a partition where error
- // correction is available. The size of the error corrected device is smaller
- // than the underlying raw device, since it doesn't include the error
- // correction blocks.
- FileDescriptorPtr source_ecc_fd_{nullptr};
-
- // The total number of operations that failed source hash verification but
- // passed after falling back to the error-corrected |source_ecc_fd_| device.
- uint64_t source_ecc_recovered_failures_{0};
-
- // Whether opening the current partition as an error-corrected device failed.
- // Used to avoid re-opening the same source partition if it is not actually
- // error corrected.
- bool source_ecc_open_failure_{false};
+
+ // This instance handles decompression/bsdfif/puffdiff. It's responsible for
+ // constructing data which should be written to target partition, actual
+ // "writing" is handled by |PartitionWriter|
+ InstallOperationExecutor install_op_executor_;
};
namespace partition_writer {
// Return a PartitionWriter instance for perform InstallOps on this partition.
// Uses VABCPartitionWriter for Virtual AB Compression
-std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+std::unique_ptr<PartitionWriterInterface> CreatePartitionWriter(
const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
DynamicPartitionControlInterface* dynamic_control,
diff --git a/payload_consumer/partition_writer_factory_android.cc b/payload_consumer/partition_writer_factory_android.cc
index 184e2d5b..67366209 100644
--- a/payload_consumer/partition_writer_factory_android.cc
+++ b/payload_consumer/partition_writer_factory_android.cc
@@ -23,7 +23,7 @@
namespace chromeos_update_engine::partition_writer {
-std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+std::unique_ptr<PartitionWriterInterface> CreatePartitionWriter(
const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
DynamicPartitionControlInterface* dynamic_control,
@@ -35,11 +35,8 @@ std::unique_ptr<PartitionWriter> CreatePartitionWriter(
LOG(INFO)
<< "Virtual AB Compression Enabled, using VABC Partition Writer for `"
<< install_part.name << '`';
- return std::make_unique<VABCPartitionWriter>(partition_update,
- install_part,
- dynamic_control,
- block_size,
- is_interactive);
+ return std::make_unique<VABCPartitionWriter>(
+ partition_update, install_part, dynamic_control, block_size);
} else {
LOG(INFO) << "Virtual AB Compression disabled, using Partition Writer for `"
<< install_part.name << '`';
diff --git a/payload_consumer/partition_writer_factory_chromeos.cc b/payload_consumer/partition_writer_factory_chromeos.cc
index 609f0431..0f7a11c3 100644
--- a/payload_consumer/partition_writer_factory_chromeos.cc
+++ b/payload_consumer/partition_writer_factory_chromeos.cc
@@ -22,7 +22,7 @@
#include "update_engine/payload_consumer/partition_writer.h"
namespace chromeos_update_engine::partition_writer {
-std::unique_ptr<PartitionWriter> CreatePartitionWriter(
+std::unique_ptr<PartitionWriterInterface> CreatePartitionWriter(
const PartitionUpdate& partition_update,
const InstallPlan::Partition& install_part,
DynamicPartitionControlInterface* dynamic_control,
diff --git a/payload_consumer/partition_writer_interface.h b/payload_consumer/partition_writer_interface.h
new file mode 100644
index 00000000..e3462923
--- /dev/null
+++ b/payload_consumer/partition_writer_interface.h
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2021 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_PARTITION_WRITER_INTERFACE_H_
+#define UPDATE_ENGINE_PARTITION_WRITER_INTERFACE_H_
+
+#include <cstdint>
+#include <string>
+
+#include <brillo/secure_blob.h>
+#include <gtest/gtest_prod.h>
+
+#include "update_engine/common/dynamic_partition_control_interface.h"
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/install_plan.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+class PartitionWriterInterface {
+ public:
+ virtual ~PartitionWriterInterface() = default;
+
+ // Perform necessary initialization work before InstallOperation can be
+ // applied to this partition
+ [[nodiscard]] virtual bool Init(const InstallPlan* install_plan,
+ bool source_may_exist,
+ size_t next_op_index) = 0;
+
+ // |CheckpointUpdateProgress| will be called after SetNextOpIndex(), but it's
+ // optional. DeltaPerformer may or may not call this everytime an operation is
+ // applied.
+ // |next_op_index| is index of next operation that should be applied.
+ // |next_op_index-1| is the last operation that is already applied.
+ virtual void CheckpointUpdateProgress(size_t next_op_index) = 0;
+
+ // Close partition writer, when calling this function there's no guarantee
+ // that all |InstallOperations| are sent to |PartitionWriter|. This function
+ // will be called even if we are pausing/aborting the update.
+ virtual int Close() = 0;
+
+ // These perform a specific type of operation and return true on success.
+ // |error| will be set if source hash mismatch, otherwise |error| might not be
+ // set even if it fails.
+ [[nodiscard]] virtual bool PerformReplaceOperation(
+ const InstallOperation& operation, const void* data, size_t count) = 0;
+ [[nodiscard]] virtual bool PerformZeroOrDiscardOperation(
+ const InstallOperation& operation) = 0;
+
+ [[nodiscard]] virtual bool PerformSourceCopyOperation(
+ const InstallOperation& operation, ErrorCode* error) = 0;
+ [[nodiscard]] virtual bool PerformDiffOperation(
+ const InstallOperation& operation,
+ ErrorCode* error,
+ const void* data,
+ size_t count) = 0;
+
+ // |DeltaPerformer| calls this when all Install Ops are sent to partition
+ // writer. No |Perform*Operation| methods will be called in the future, and
+ // the partition writer is expected to be closed soon.
+ [[nodiscard]] virtual bool FinishedInstallOps() = 0;
+};
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/partition_writer_unittest.cc b/payload_consumer/partition_writer_unittest.cc
index 263f338e..331a0613 100644
--- a/payload_consumer/partition_writer_unittest.cc
+++ b/payload_consumer/partition_writer_unittest.cc
@@ -46,18 +46,19 @@ class PartitionWriterTest : public testing::Test {
// Helper function to pretend that the ECC file descriptor was already opened.
// Returns a pointer to the created file descriptor.
FakeFileDescriptor* SetFakeECCFile(size_t size) {
- EXPECT_FALSE(writer_.source_ecc_fd_) << "source_ecc_fd_ already open.";
+ EXPECT_FALSE(writer_.verified_source_fd_.source_ecc_fd_)
+ << "source_ecc_fdb already open.";
FakeFileDescriptor* ret = new FakeFileDescriptor();
fake_ecc_fd_.reset(ret);
// Call open to simulate it was already opened.
ret->Open("", 0);
ret->SetFileSize(size);
- writer_.source_ecc_fd_ = fake_ecc_fd_;
+ writer_.verified_source_fd_.source_ecc_fd_ = fake_ecc_fd_;
return ret;
}
uint64_t GetSourceEccRecoveredFailures() const {
- return writer_.source_ecc_recovered_failures_;
+ return writer_.verified_source_fd_.source_ecc_recovered_failures_;
}
AnnotatedOperation GenerateSourceCopyOp(const brillo::Blob& copied_data,
@@ -81,22 +82,31 @@ class PartitionWriterTest : public testing::Test {
brillo::Blob PerformSourceCopyOp(const InstallOperation& op,
const brillo::Blob blob_data) {
- ScopedTempFile source_partition("Blob-XXXXXX");
+ LOG(INFO) << "Using source part " << source_partition.path();
FileDescriptorPtr fd(new EintrSafeFileDescriptor());
DirectExtentWriter extent_writer{fd};
EXPECT_TRUE(fd->Open(source_partition.path().c_str(), O_RDWR));
+ if (HasFailure()) {
+ return {};
+ }
EXPECT_TRUE(extent_writer.Init(op.src_extents(), kBlockSize));
+ if (HasFailure()) {
+ return {};
+ }
EXPECT_TRUE(extent_writer.Write(blob_data.data(), blob_data.size()));
+ if (HasFailure()) {
+ return {};
+ }
+ fd->Flush();
- ScopedTempFile target_partition("Blob-XXXXXX");
-
- install_part_.source_path = source_partition.path();
- install_part_.target_path = target_partition.path();
install_part_.source_size = blob_data.size();
install_part_.target_size = blob_data.size();
ErrorCode error;
EXPECT_TRUE(writer_.Init(&install_plan_, true, 0));
+ if (HasFailure()) {
+ return {};
+ }
EXPECT_TRUE(writer_.PerformSourceCopyOperation(op, &error));
writer_.CheckpointUpdateProgress(1);
@@ -111,8 +121,11 @@ class PartitionWriterTest : public testing::Test {
DynamicPartitionControlStub dynamic_control_{};
FileDescriptorPtr fake_ecc_fd_{};
DeltaArchiveManifest manifest_{};
+ ScopedTempFile source_partition{"source-part-XXXXXX"};
+ ScopedTempFile target_partition{"target-part-XXXXXX"};
+ InstallPlan::Partition install_part_{.source_path = source_partition.path(),
+ .target_path = target_partition.path()};
PartitionUpdate partition_update_{};
- InstallPlan::Partition install_part_{};
PartitionWriter writer_{
partition_update_, install_part_, &dynamic_control_, kBlockSize, false};
};
@@ -124,7 +137,7 @@ TEST_F(PartitionWriterTest, ErrorCorrectionSourceCopyWhenNoHashFallbackTest) {
ScopedTempFile source("Source-XXXXXX");
// Setup the source path with the right expected data.
brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
- EXPECT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
+ ASSERT_TRUE(test_utils::WriteFileVector(source.path(), expected_data));
// Setup the fec file descriptor as the fake stream, with smaller data than
// the expected.
@@ -136,17 +149,18 @@ TEST_F(PartitionWriterTest, ErrorCorrectionSourceCopyWhenNoHashFallbackTest) {
// The payload operation doesn't include an operation hash.
auto source_copy_op = GenerateSourceCopyOp(expected_data, false, &old_part);
-
+ ASSERT_NO_FATAL_FAILURE();
auto output_data = PerformSourceCopyOp(source_copy_op.op, expected_data);
+ ASSERT_NO_FATAL_FAILURE();
ASSERT_EQ(output_data, expected_data);
// Verify that the fake_fec was attempted to be used. Since the file
// descriptor is shorter it can actually do more than one read to realize it
// reached the EOF.
- EXPECT_LE(1U, fake_fec->GetReadOps().size());
+ ASSERT_LE(1U, fake_fec->GetReadOps().size());
// This fallback doesn't count as an error-corrected operation since the
// operation hash was not available.
- EXPECT_EQ(0U, GetSourceEccRecoveredFailures());
+ ASSERT_EQ(0U, GetSourceEccRecoveredFailures());
}
// Test that the error-corrected file descriptor is used to read the partition
@@ -163,11 +177,13 @@ TEST_F(PartitionWriterTest, ErrorCorrectionSourceCopyFallbackTest) {
brillo::Blob expected_data = FakeFileDescriptorData(kCopyOperationSize);
auto source_copy_op = GenerateSourceCopyOp(expected_data, true);
+ ASSERT_NO_FATAL_FAILURE();
auto output_data = PerformSourceCopyOp(source_copy_op.op, invalid_data);
+ ASSERT_NO_FATAL_FAILURE();
ASSERT_EQ(output_data, expected_data);
// Verify that the fake_fec was actually used.
- EXPECT_EQ(1U, fake_fec->GetReadOps().size());
+ EXPECT_GE(fake_fec->GetReadOps().size(), 1U);
EXPECT_EQ(1U, GetSourceEccRecoveredFailures());
}
@@ -177,10 +193,11 @@ TEST_F(PartitionWriterTest, ChooseSourceFDTest) {
// Write invalid data to the source image, which doesn't match the expected
// hash.
brillo::Blob invalid_data(kSourceSize, 0x55);
- EXPECT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
+ ASSERT_TRUE(test_utils::WriteFileVector(source.path(), invalid_data));
- writer_.source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
- writer_.source_fd_->Open(source.path().c_str(), O_RDONLY);
+ writer_.verified_source_fd_.source_fd_ =
+ std::make_shared<EintrSafeFileDescriptor>();
+ writer_.verified_source_fd_.source_fd_->Open(source.path().c_str(), O_RDONLY);
// Setup the fec file descriptor as the fake stream, which matches
// |expected_data|.
@@ -190,15 +207,16 @@ TEST_F(PartitionWriterTest, ChooseSourceFDTest) {
InstallOperation op;
*(op.add_src_extents()) = ExtentForRange(0, kSourceSize / 4096);
brillo::Blob src_hash;
- EXPECT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
+ ASSERT_TRUE(HashCalculator::RawHashOfData(expected_data, &src_hash));
op.set_src_sha256_hash(src_hash.data(), src_hash.size());
ErrorCode error = ErrorCode::kSuccess;
- EXPECT_EQ(writer_.source_ecc_fd_, writer_.ChooseSourceFD(op, &error));
- EXPECT_EQ(ErrorCode::kSuccess, error);
+ ASSERT_EQ(writer_.verified_source_fd_.source_ecc_fd_,
+ writer_.ChooseSourceFD(op, &error));
+ ASSERT_EQ(ErrorCode::kSuccess, error);
// Verify that the fake_fec was actually used.
- EXPECT_EQ(1U, fake_fec->GetReadOps().size());
- EXPECT_EQ(1U, GetSourceEccRecoveredFailures());
+ ASSERT_EQ(1U, fake_fec->GetReadOps().size());
+ ASSERT_EQ(1U, GetSourceEccRecoveredFailures());
}
} // namespace chromeos_update_engine
diff --git a/payload_consumer/payload_constants.cc b/payload_consumer/payload_constants.cc
index d62a0ec6..4719be8b 100644
--- a/payload_consumer/payload_constants.cc
+++ b/payload_consumer/payload_constants.cc
@@ -34,10 +34,10 @@ const uint32_t kBrotliBsdiffMinorPayloadVersion = 4;
const uint32_t kPuffdiffMinorPayloadVersion = 5;
const uint32_t kVerityMinorPayloadVersion = 6;
const uint32_t kPartialUpdateMinorPayloadVersion = 7;
+const uint32_t kZucchiniMinorPayloadVersion = 8;
const uint32_t kMinSupportedMinorPayloadVersion = kSourceMinorPayloadVersion;
-const uint32_t kMaxSupportedMinorPayloadVersion =
- kPartialUpdateMinorPayloadVersion;
+const uint32_t kMaxSupportedMinorPayloadVersion = kLZ4DIFFMinorPayloadVersion;
const uint64_t kMaxPayloadHeaderSize = 24;
@@ -66,7 +66,12 @@ const char* InstallOperationTypeName(InstallOperation::Type op_type) {
return "PUFFDIFF";
case InstallOperation::BROTLI_BSDIFF:
return "BROTLI_BSDIFF";
-
+ case InstallOperation::ZUCCHINI:
+ return "ZUCCHINI";
+ case InstallOperation::LZ4DIFF_BSDIFF:
+ return "LZ4DIFF_BSDIFF";
+ case InstallOperation::LZ4DIFF_PUFFDIFF:
+ return "LZ4DIFF_PUFFIDFF";
case InstallOperation::BSDIFF:
case InstallOperation::MOVE:
NOTREACHED();
diff --git a/payload_consumer/payload_constants.h b/payload_consumer/payload_constants.h
index 03647ee7..31e24f79 100644
--- a/payload_consumer/payload_constants.h
+++ b/payload_consumer/payload_constants.h
@@ -59,6 +59,12 @@ extern const uint32_t kVerityMinorPayloadVersion;
// The minor version that allows partial update, e.g. kernel only update.
extern const uint32_t kPartialUpdateMinorPayloadVersion;
+// The minor version that allows ZUCCHINI operation.
+extern const uint32_t kZucchiniMinorPayloadVersion;
+
+// THe minor version that allows LZ4DIFF operation
+constexpr uint32_t kLZ4DIFFMinorPayloadVersion = 9;
+
// The minimum and maximum supported minor version.
extern const uint32_t kMinSupportedMinorPayloadVersion;
extern const uint32_t kMaxSupportedMinorPayloadVersion;
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index 051ccbf7..a72462a7 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -24,6 +24,8 @@
#include <unistd.h>
#include <cmath>
+#include <fstream>
+#include <string>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
@@ -46,6 +48,31 @@ namespace {
// sample_images.sh file.
const int kPostinstallStatusFd = 3;
+static constexpr bool Contains(std::string_view haystack,
+ std::string_view needle) {
+ return haystack.find(needle) != std::string::npos;
+}
+
+static void LogBuildInfoForPartition(std::string_view mount_point) {
+ static constexpr std::array<std::string_view, 3> kBuildPropFiles{
+ "build.prop", "etc/build.prop", "system/build.prop"};
+ for (const auto& file : kBuildPropFiles) {
+ auto path = std::string(mount_point);
+ if (path.back() != '/') {
+ path.push_back('/');
+ }
+ path += file;
+ LOG(INFO) << "Trying to read " << path;
+ std::ifstream infile(path);
+ std::string line;
+ while (std::getline(infile, line)) {
+ if (Contains(line, "ro.build")) {
+ LOG(INFO) << line;
+ }
+ }
+ }
+}
+
} // namespace
namespace chromeos_update_engine {
@@ -64,9 +91,17 @@ PostinstallRunnerAction::PostinstallRunnerAction(
fs_mount_dir_ = temp_dir.value();
#endif // __ANDROID__
CHECK(!fs_mount_dir_.empty());
+ EnsureUnmounted();
LOG(INFO) << "postinstall mount point: " << fs_mount_dir_;
}
+void PostinstallRunnerAction::EnsureUnmounted() {
+ if (utils::IsMountpoint(fs_mount_dir_)) {
+ LOG(INFO) << "Found previously mounted filesystem at " << fs_mount_dir_;
+ utils::UnmountFilesystem(fs_mount_dir_);
+ }
+}
+
void PostinstallRunnerAction::PerformAction() {
CHECK(HasInputObject());
CHECK(boot_control_);
@@ -121,6 +156,49 @@ void PostinstallRunnerAction::PerformAction() {
PerformPartitionPostinstall();
}
+bool PostinstallRunnerAction::MountPartition(
+ const InstallPlan::Partition& partition) noexcept {
+ // Perform post-install for the current_partition_ partition. At this point we
+ // need to call CompletePartitionPostinstall to complete the operation and
+ // cleanup.
+ const auto mountable_device = partition.readonly_target_path;
+ if (!utils::FileExists(mountable_device.c_str())) {
+ LOG(ERROR) << "Mountable device " << mountable_device << " for partition "
+ << partition.name << " does not exist";
+ return false;
+ }
+
+ if (!utils::FileExists(fs_mount_dir_.c_str())) {
+ LOG(ERROR) << "Mount point " << fs_mount_dir_
+ << " does not exist, mount call will fail";
+ return false;
+ }
+ // Double check that the fs_mount_dir is not busy with a previous mounted
+ // filesystem from a previous crashed postinstall step.
+ EnsureUnmounted();
+
+#ifdef __ANDROID__
+ // In Chromium OS, the postinstall step is allowed to write to the block
+ // device on the target image, so we don't mark it as read-only and should
+ // be read-write since we just wrote to it during the update.
+
+ // Mark the block device as read-only before mounting for post-install.
+ if (!utils::SetBlockDeviceReadOnly(mountable_device, true)) {
+ return false;
+ }
+#endif // __ANDROID__
+
+ if (!utils::MountFilesystem(
+ mountable_device,
+ fs_mount_dir_,
+ MS_RDONLY,
+ partition.filesystem_type,
+ hardware_->GetPartitionMountOptions(partition.name))) {
+ return false;
+ }
+ return true;
+}
+
void PostinstallRunnerAction::PerformPartitionPostinstall() {
if (install_plan_.download_url.empty()) {
LOG(INFO) << "Skipping post-install during rollback";
@@ -132,6 +210,27 @@ void PostinstallRunnerAction::PerformPartitionPostinstall() {
!install_plan_.partitions[current_partition_].run_postinstall) {
VLOG(1) << "Skipping post-install on partition "
<< install_plan_.partitions[current_partition_].name;
+ // Attempt to mount a device if it has postinstall script configured, even
+ // if we want to skip running postinstall script.
+ // This is because we've seen bugs like b/198787355 which is only triggered
+ // when you attempt to mount a device. If device fails to mount, it will
+ // likely fail to mount during boot anyway, so it's better to catch any
+ // issues earlier.
+ // It's possible that some of the partitions aren't mountable, but these
+ // partitions shouldn't have postinstall configured. Therefore we guard this
+ // logic with |postinstall_path.empty()|.
+ const auto& partition = install_plan_.partitions[current_partition_];
+ if (!partition.postinstall_path.empty()) {
+ const auto mountable_device = partition.readonly_target_path;
+ if (!MountPartition(partition)) {
+ return CompletePostinstall(ErrorCode::kPostInstallMountError);
+ }
+ LogBuildInfoForPartition(fs_mount_dir_);
+ if (!utils::UnmountFilesystem(fs_mount_dir_)) {
+ return CompletePartitionPostinstall(
+ 1, "Error unmounting the device " + mountable_device);
+ }
+ }
current_partition_++;
}
if (current_partition_ == install_plan_.partitions.size())
@@ -141,27 +240,15 @@ void PostinstallRunnerAction::PerformPartitionPostinstall() {
install_plan_.partitions[current_partition_];
const string mountable_device = partition.readonly_target_path;
- if (mountable_device.empty()) {
- LOG(ERROR) << "Cannot make mountable device from " << partition.target_path;
- return CompletePostinstall(ErrorCode::kPostinstallRunnerError);
- }
-
// Perform post-install for the current_partition_ partition. At this point we
// need to call CompletePartitionPostinstall to complete the operation and
// cleanup.
- if (!utils::FileExists(fs_mount_dir_.c_str())) {
- LOG(ERROR) << "Mount point " << fs_mount_dir_
- << " does not exist, mount call will fail";
- return CompletePostinstall(ErrorCode::kPostinstallRunnerError);
- }
- // Double check that the fs_mount_dir is not busy with a previous mounted
- // filesystem from a previous crashed postinstall step.
- if (utils::IsMountpoint(fs_mount_dir_)) {
- LOG(INFO) << "Found previously mounted filesystem at " << fs_mount_dir_;
- utils::UnmountFilesystem(fs_mount_dir_);
+ if (!MountPartition(partition)) {
+ CompletePostinstall(ErrorCode::kPostInstallMountError);
+ return;
}
-
+ LogBuildInfoForPartition(fs_mount_dir_);
base::FilePath postinstall_path(partition.postinstall_path);
if (postinstall_path.IsAbsolute()) {
LOG(ERROR) << "Invalid absolute path passed to postinstall, use a relative"
@@ -179,31 +266,9 @@ void PostinstallRunnerAction::PerformPartitionPostinstall() {
return CompletePostinstall(ErrorCode::kPostinstallRunnerError);
}
-#ifdef __ANDROID__
- // In Chromium OS, the postinstall step is allowed to write to the block
- // device on the target image, so we don't mark it as read-only and should
- // be read-write since we just wrote to it during the update.
-
- // Mark the block device as read-only before mounting for post-install.
- if (!utils::SetBlockDeviceReadOnly(mountable_device, true)) {
- return CompletePartitionPostinstall(
- 1, "Error marking the device " + mountable_device + " read only.");
- }
-#endif // __ANDROID__
-
- if (!utils::MountFilesystem(
- mountable_device,
- fs_mount_dir_,
- MS_RDONLY,
- partition.filesystem_type,
- hardware_->GetPartitionMountOptions(partition.name))) {
- return CompletePartitionPostinstall(
- 1, "Error mounting the device " + mountable_device);
- }
-
LOG(INFO) << "Performing postinst (" << partition.postinstall_path << " at "
- << abs_path << ") installed on device " << partition.target_path
- << " and mountable device " << mountable_device;
+ << abs_path << ") installed on mountable device "
+ << mountable_device;
// Logs the file format of the postinstall script we are about to run. This
// will help debug when the postinstall script doesn't match the architecture
diff --git a/payload_consumer/postinstall_runner_action.h b/payload_consumer/postinstall_runner_action.h
index 178d72a2..66721af9 100644
--- a/payload_consumer/postinstall_runner_action.h
+++ b/payload_consumer/postinstall_runner_action.h
@@ -70,8 +70,11 @@ class PostinstallRunnerAction : public InstallPlanAction {
// exposed for testing purposes only
void SetMountDir(std::string dir) { fs_mount_dir_ = std::move(dir); }
+ void EnsureUnmounted();
void PerformPartitionPostinstall();
+ [[nodiscard]] bool MountPartition(
+ const InstallPlan::Partition& partition) noexcept;
// Called whenever the |progress_fd_| has data available to read.
void OnProgressFdReady();
diff --git a/payload_consumer/postinstall_runner_action_unittest.cc b/payload_consumer/postinstall_runner_action_unittest.cc
index 792ee282..75d93dc7 100644
--- a/payload_consumer/postinstall_runner_action_unittest.cc
+++ b/payload_consumer/postinstall_runner_action_unittest.cc
@@ -45,7 +45,6 @@
#include "update_engine/common/subprocess.h"
#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
-#include "update_engine/cros/mock_payload_state.h"
using brillo::MessageLoop;
using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
@@ -348,7 +347,7 @@ TEST_F(PostinstallRunnerActionTest, RunAsRootRollbackTestWithDataSave) {
TEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) {
RunPostinstallAction(
"/dev/null", kPostinstallDefaultScript, false, false, false);
- EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
+ EXPECT_EQ(ErrorCode::kPostInstallMountError, processor_delegate_.code_);
// In case of failure, Postinstall should not signal a powerwash even if it
// was requested.
@@ -357,12 +356,13 @@ TEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) {
}
TEST_F(PostinstallRunnerActionTest, RunAsRootSkipOptionalPostinstallTest) {
+ ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
InstallPlan::Partition part;
part.name = "part";
part.target_path = "/dev/null";
- part.readonly_target_path = "/dev/null";
+ part.readonly_target_path = loop.dev();
part.run_postinstall = true;
- part.postinstall_path = kPostinstallDefaultScript;
+ part.postinstall_path = "non_existent_path";
part.postinstall_optional = true;
InstallPlan install_plan;
install_plan.partitions = {part};
diff --git a/payload_consumer/snapshot_extent_writer.cc b/payload_consumer/snapshot_extent_writer.cc
index 242e7260..88f394aa 100644
--- a/payload_consumer/snapshot_extent_writer.cc
+++ b/payload_consumer/snapshot_extent_writer.cc
@@ -25,99 +25,11 @@
namespace chromeos_update_engine {
-SnapshotExtentWriter::SnapshotExtentWriter(
- android::snapshot::ICowWriter* cow_writer)
- : cow_writer_(cow_writer) {
- CHECK_NE(cow_writer, nullptr);
+bool SnapshotExtentWriter::WriteExtent(const void* bytes,
+ const Extent& extent,
+ size_t block_size) {
+ return cow_writer_->AddRawBlocks(
+ extent.start_block(), bytes, extent.num_blocks() * block_size);
}
-SnapshotExtentWriter::~SnapshotExtentWriter() {
- CHECK(buffer_.empty()) << buffer_.size();
-}
-
-bool SnapshotExtentWriter::Init(
- const google::protobuf::RepeatedPtrField<Extent>& extents,
- uint32_t block_size) {
- extents_ = extents;
- cur_extent_idx_ = 0;
- buffer_.clear();
- buffer_.reserve(block_size);
- block_size_ = block_size;
- return true;
-}
-
-size_t SnapshotExtentWriter::ConsumeWithBuffer(const uint8_t* data,
- size_t count) {
- CHECK_LT(cur_extent_idx_, static_cast<size_t>(extents_.size()));
- const auto& cur_extent = extents_[cur_extent_idx_];
- const auto cur_extent_size = cur_extent.num_blocks() * block_size_;
-
- if (buffer_.empty() && count >= cur_extent_size) {
- if (!cow_writer_->AddRawBlocks(
- cur_extent.start_block(), data, cur_extent_size)) {
- LOG(ERROR) << "AddRawBlocks(" << cur_extent.start_block() << ", " << data
- << ", " << cur_extent_size << ") failed.";
- // return value is expected to be greater than 0. Return 0 to signal error
- // condition
- return 0;
- }
- if (!next_extent()) {
- CHECK_EQ(count, cur_extent_size)
- << "Exhausted all blocks, but still have " << count - cur_extent_size
- << " bytes left";
- }
- return cur_extent_size;
- }
- CHECK_LT(buffer_.size(), cur_extent_size)
- << "Data left in buffer should never be >= cur_extent_size, otherwise "
- "we should have send that data to CowWriter. Buffer size: "
- << buffer_.size() << " current extent size: " << cur_extent_size;
- size_t bytes_to_copy =
- std::min<size_t>(count, cur_extent_size - buffer_.size());
- CHECK_GT(bytes_to_copy, 0U);
-
- buffer_.insert(buffer_.end(), data, data + bytes_to_copy);
- CHECK_LE(buffer_.size(), cur_extent_size);
-
- if (buffer_.size() == cur_extent_size) {
- if (!cow_writer_->AddRawBlocks(
- cur_extent.start_block(), buffer_.data(), buffer_.size())) {
- LOG(ERROR) << "AddRawBlocks(" << cur_extent.start_block() << ", "
- << buffer_.data() << ", " << buffer_.size() << ") failed.";
- return 0;
- }
- buffer_.clear();
- if (!next_extent()) {
- CHECK_EQ(count, bytes_to_copy) << "Exhausted all blocks, but still have "
- << count - bytes_to_copy << " bytes left";
- }
- }
- return bytes_to_copy;
-}
-
-// Returns true on success.
-// This will construct a COW_REPLACE operation and forward it to CowWriter. It
-// is important that caller does not perform SOURCE_COPY operation on this
-// class, otherwise raw data will be stored. Caller should find ways to use
-// COW_COPY whenever possible.
-bool SnapshotExtentWriter::Write(const void* bytes, size_t count) {
- if (count == 0) {
- return true;
- }
- CHECK_NE(extents_.size(), 0);
-
- auto data = static_cast<const uint8_t*>(bytes);
- while (count > 0) {
- auto bytes_written = ConsumeWithBuffer(data, count);
- TEST_AND_RETURN_FALSE(bytes_written > 0);
- data += bytes_written;
- count -= bytes_written;
- }
- return true;
-}
-
-bool SnapshotExtentWriter::next_extent() {
- cur_extent_idx_++;
- return cur_extent_idx_ < static_cast<size_t>(extents_.size());
-}
} // namespace chromeos_update_engine
diff --git a/payload_consumer/snapshot_extent_writer.h b/payload_consumer/snapshot_extent_writer.h
index c3a948ee..c2e54465 100644
--- a/payload_consumer/snapshot_extent_writer.h
+++ b/payload_consumer/snapshot_extent_writer.h
@@ -22,36 +22,21 @@
#include <libsnapshot/cow_writer.h>
-#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/block_extent_writer.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
-class SnapshotExtentWriter : public chromeos_update_engine::ExtentWriter {
+class SnapshotExtentWriter final : public BlockExtentWriter {
public:
- explicit SnapshotExtentWriter(android::snapshot::ICowWriter* cow_writer);
- ~SnapshotExtentWriter();
- // Returns true on success.
- bool Init(const google::protobuf::RepeatedPtrField<Extent>& extents,
- uint32_t block_size) override;
- // Returns true on success.
- // This will construct a COW_REPLACE operation and forward it to CowWriter. It
- // is important that caller does not perform SOURCE_COPY operation on this
- // class, otherwise raw data will be stored. Caller should find ways to use
- // COW_COPY whenever possible.
- bool Write(const void* bytes, size_t count) override;
+ explicit SnapshotExtentWriter(android::snapshot::ICowWriter* cow_writer)
+ : cow_writer_(cow_writer) {}
+ bool WriteExtent(const void* bytes,
+ const Extent& extent,
+ size_t block_size) override;
private:
- bool next_extent();
- [[nodiscard]] size_t ConsumeWithBuffer(const uint8_t* bytes, size_t count);
- // It's a non-owning pointer, because PartitionWriter owns the CowWruter. This
- // allows us to use a single instance of CowWriter for all operations applied
- // to the same partition.
android::snapshot::ICowWriter* cow_writer_;
- google::protobuf::RepeatedPtrField<Extent> extents_;
- size_t cur_extent_idx_;
- std::vector<uint8_t> buffer_;
- size_t block_size_;
};
} // namespace chromeos_update_engine
diff --git a/payload_consumer/snapshot_extent_writer_unittest.cc b/payload_consumer/snapshot_extent_writer_unittest.cc
index 22010433..0c96c3e0 100644
--- a/payload_consumer/snapshot_extent_writer_unittest.cc
+++ b/payload_consumer/snapshot_extent_writer_unittest.cc
@@ -60,6 +60,13 @@ class FakeCowWriter : public android::snapshot::ICowWriter {
operations_[new_block_start] = {.type = CowOp::COW_ZERO};
return true;
}
+ bool EmitXorBlocks(uint32_t new_block_start,
+ const void* data,
+ size_t size,
+ uint32_t old_block,
+ uint16_t offset) override {
+ return false;
+ }
bool Finalize() override {
finalize_called_ = true;
return true;
@@ -70,6 +77,10 @@ class FakeCowWriter : public android::snapshot::ICowWriter {
return true;
}
+ bool EmitSequenceData(size_t num_ops, const uint32_t* data) override {
+ return false;
+ }
+
// Return number of bytes the cow image occupies on disk.
uint64_t GetCowSize() override {
return std::accumulate(
diff --git a/payload_consumer/vabc_partition_writer.cc b/payload_consumer/vabc_partition_writer.cc
index 0843fffb..8ae0b51f 100644
--- a/payload_consumer/vabc_partition_writer.cc
+++ b/payload_consumer/vabc_partition_writer.cc
@@ -16,19 +16,31 @@
#include "update_engine/payload_consumer/vabc_partition_writer.h"
+#include <algorithm>
+#include <map>
#include <memory>
#include <string>
+#include <utility>
#include <vector>
+#include <android-base/properties.h>
+#include <brillo/secure_blob.h>
#include <libsnapshot/cow_writer.h>
#include "update_engine/common/cow_operation_convert.h"
#include "update_engine/common/utils.h"
-#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_consumer/block_extent_writer.h"
+#include "update_engine/payload_consumer/extent_map.h"
+#include "update_engine/payload_consumer/extent_reader.h"
#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/file_descriptor_utils.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/payload_consumer/partition_writer.h"
#include "update_engine/payload_consumer/snapshot_extent_writer.h"
+#include "update_engine/payload_consumer/xor_extent_writer.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
// Expected layout of COW file:
@@ -55,12 +67,52 @@ namespace chromeos_update_engine {
// label 3, Which contains all operation 2's data, but none of operation 3's
// data.
+using android::snapshot::ICowWriter;
+using ::google::protobuf::RepeatedPtrField;
+
+// Compute XOR map, a map from dst extent to corresponding merge operation
+static ExtentMap<const CowMergeOperation*, ExtentLess> ComputeXorMap(
+ const RepeatedPtrField<CowMergeOperation>& merge_ops) {
+ ExtentMap<const CowMergeOperation*, ExtentLess> xor_map;
+ for (const auto& merge_op : merge_ops) {
+ if (merge_op.type() == CowMergeOperation::COW_XOR) {
+ xor_map.AddExtent(merge_op.dst_extent(), &merge_op);
+ }
+ }
+ return xor_map;
+}
+
+VABCPartitionWriter::VABCPartitionWriter(
+ const PartitionUpdate& partition_update,
+ const InstallPlan::Partition& install_part,
+ DynamicPartitionControlInterface* dynamic_control,
+ size_t block_size)
+ : partition_update_(partition_update),
+ install_part_(install_part),
+ dynamic_control_(dynamic_control),
+ block_size_(block_size),
+ executor_(block_size),
+ verified_source_fd_(block_size, install_part.source_path) {}
+
bool VABCPartitionWriter::Init(const InstallPlan* install_plan,
bool source_may_exist,
size_t next_op_index) {
+ if (dynamic_control_->GetVirtualAbCompressionXorFeatureFlag().IsEnabled()) {
+ xor_map_ = ComputeXorMap(partition_update_.merge_operations());
+ if (xor_map_.size() > 0) {
+ LOG(INFO) << "Virtual AB Compression with XOR is enabled";
+ } else {
+ LOG(INFO) << "Device supports Virtual AB compression with XOR, but OTA "
+ "package does not.";
+ }
+ } else {
+ LOG(INFO) << "Virtual AB Compression with XOR is disabled.";
+ }
TEST_AND_RETURN_FALSE(install_plan != nullptr);
- TEST_AND_RETURN_FALSE(
- OpenSourcePartition(install_plan->source_slot, source_may_exist));
+ if (source_may_exist && install_part_.source_size > 0) {
+ TEST_AND_RETURN_FALSE(!install_part_.source_path.empty());
+ TEST_AND_RETURN_FALSE(verified_source_fd_.Open());
+ }
std::optional<std::string> source_path;
if (!install_part_.source_path.empty()) {
// TODO(zhangkelvin) Make |source_path| a std::optional<std::string>
@@ -85,44 +137,125 @@ bool VABCPartitionWriter::Init(const InstallPlan* install_plan,
}
// ==============================================
+ if (!partition_update_.merge_operations().empty()) {
+ if (IsXorEnabled()) {
+ LOG(INFO) << "VABC XOR enabled for partition "
+ << partition_update_.partition_name();
+ TEST_AND_RETURN_FALSE(WriteMergeSequence(
+ partition_update_.merge_operations(), cow_writer_.get()));
+ }
+ }
// TODO(zhangkelvin) Rewrite this in C++20 coroutine once that's available.
- auto converted = ConvertToCowOperations(partition_update_.operations(),
- partition_update_.merge_operations());
+ // TODO(177104308) Don't write all COPY ops up-front if merge sequence is
+ // written
+ const auto converted = ConvertToCowOperations(
+ partition_update_.operations(), partition_update_.merge_operations());
- WriteAllCowOps(block_size_, converted, cow_writer_.get(), source_fd_);
+ if (!converted.empty()) {
+ // Use source fd directly. Ideally we want to verify all extents used in
+ // source copy, but then what do we do if some extents contain correct
+ // hashes and some don't?
+ auto source_fd = std::make_shared<EintrSafeFileDescriptor>();
+ TEST_AND_RETURN_FALSE_ERRNO(
+ source_fd->Open(install_part_.source_path.c_str(), O_RDONLY));
+ TEST_AND_RETURN_FALSE(WriteSourceCopyCowOps(
+ block_size_, converted, cow_writer_.get(), source_fd));
+ cow_writer_->AddLabel(0);
+ }
return true;
}
-bool VABCPartitionWriter::WriteAllCowOps(
+bool VABCPartitionWriter::WriteMergeSequence(
+ const RepeatedPtrField<CowMergeOperation>& merge_sequence,
+ ICowWriter* cow_writer) {
+ std::vector<uint32_t> blocks_merge_order;
+ for (const auto& merge_op : merge_sequence) {
+ const auto& dst_extent = merge_op.dst_extent();
+ const auto& src_extent = merge_op.src_extent();
+ // In place copy are basically noops, they do not need to be "merged" at
+ // all, don't include them in merge sequence.
+ if (merge_op.type() == CowMergeOperation::COW_COPY &&
+ merge_op.src_extent() == merge_op.dst_extent()) {
+ continue;
+ }
+
+ const bool extent_overlap =
+ ExtentRanges::ExtentsOverlap(src_extent, dst_extent);
+ // TODO(193863443) Remove this check once this feature
+ // lands on all pixel devices.
+ const bool is_ascending = android::base::GetBoolProperty(
+ "ro.virtual_ab.userspace.snapshots.enabled", false);
+
+ // If this is a self-overlapping op and |dst_extent| comes after
+ // |src_extent|, we must write in reverse order for correctness.
+ //
+ // If this is self-overlapping op and |dst_extent| comes before
+ // |src_extent|, we must write in ascending order for correctness.
+ //
+ // If this isn't a self overlapping op, write block in ascending order
+ // if userspace snapshots are enabled
+ if (extent_overlap) {
+ if (dst_extent.start_block() <= src_extent.start_block()) {
+ for (size_t i = 0; i < dst_extent.num_blocks(); i++) {
+ blocks_merge_order.push_back(dst_extent.start_block() + i);
+ }
+ } else {
+ for (int i = dst_extent.num_blocks() - 1; i >= 0; i--) {
+ blocks_merge_order.push_back(dst_extent.start_block() + i);
+ }
+ }
+ } else {
+ if (is_ascending) {
+ for (size_t i = 0; i < dst_extent.num_blocks(); i++) {
+ blocks_merge_order.push_back(dst_extent.start_block() + i);
+ }
+ } else {
+ for (int i = dst_extent.num_blocks() - 1; i >= 0; i--) {
+ blocks_merge_order.push_back(dst_extent.start_block() + i);
+ }
+ }
+ }
+ }
+ return cow_writer->AddSequenceData(blocks_merge_order.size(),
+ blocks_merge_order.data());
+}
+
+bool VABCPartitionWriter::WriteSourceCopyCowOps(
size_t block_size,
const std::vector<CowOperation>& converted,
- android::snapshot::ICowWriter* cow_writer,
+ ICowWriter* cow_writer,
FileDescriptorPtr source_fd) {
- std::vector<uint8_t> buffer(block_size);
-
for (const auto& cow_op : converted) {
+ std::vector<uint8_t> buffer;
switch (cow_op.op) {
case CowOperation::CowCopy:
if (cow_op.src_block == cow_op.dst_block) {
continue;
}
- TEST_AND_RETURN_FALSE(
- cow_writer->AddCopy(cow_op.dst_block, cow_op.src_block));
+ // Add blocks in reverse order, because snapused specifically prefers
+ // this ordering. Since we already eliminated all self-overlapping
+ // SOURCE_COPY during delta generation, this should be safe to do.
+ for (size_t i = cow_op.block_count; i > 0; i--) {
+ TEST_AND_RETURN_FALSE(cow_writer->AddCopy(cow_op.dst_block + i - 1,
+ cow_op.src_block + i - 1));
+ }
break;
case CowOperation::CowReplace:
+ buffer.resize(block_size * cow_op.block_count);
ssize_t bytes_read = 0;
TEST_AND_RETURN_FALSE(utils::ReadAll(source_fd,
buffer.data(),
- block_size,
+ block_size * cow_op.block_count,
cow_op.src_block * block_size,
&bytes_read));
- if (bytes_read <= 0 || static_cast<size_t>(bytes_read) != block_size) {
+ if (bytes_read <= 0 ||
+ static_cast<size_t>(bytes_read) != buffer.size()) {
LOG(ERROR) << "source_fd->Read failed: " << bytes_read;
return false;
}
TEST_AND_RETURN_FALSE(cow_writer->AddRawBlocks(
- cow_op.dst_block, buffer.data(), block_size));
+ cow_op.dst_block, buffer.data(), buffer.size()));
break;
}
}
@@ -145,9 +278,43 @@ std::unique_ptr<ExtentWriter> VABCPartitionWriter::CreateBaseExtentWriter() {
[[nodiscard]] bool VABCPartitionWriter::PerformSourceCopyOperation(
const InstallOperation& operation, ErrorCode* error) {
- // TODO(zhangkelvin) Probably just ignore SOURCE_COPY? They should be taken
- // care of during Init();
- return true;
+ // COPY ops are already handled during Init(), no need to do actual work, but
+ // we still want to verify that all blocks contain expected data.
+ auto source_fd = std::make_shared<EintrSafeFileDescriptor>();
+ TEST_AND_RETURN_FALSE_ERRNO(
+ source_fd->Open(install_part_.source_path.c_str(), O_RDONLY));
+ if (!operation.has_src_sha256_hash()) {
+ return true;
+ }
+ return PartitionWriter::ValidateSourceHash(
+ operation, source_fd, block_size_, error);
+}
+
+bool VABCPartitionWriter::PerformReplaceOperation(const InstallOperation& op,
+ const void* data,
+ size_t count) {
+ // Setup the ExtentWriter stack based on the operation type.
+ std::unique_ptr<ExtentWriter> writer = CreateBaseExtentWriter();
+
+ return executor_.ExecuteReplaceOperation(op, std::move(writer), data, count);
+}
+
+bool VABCPartitionWriter::PerformDiffOperation(
+ const InstallOperation& operation,
+ ErrorCode* error,
+ const void* data,
+ size_t count) {
+ FileDescriptorPtr source_fd =
+ verified_source_fd_.ChooseSourceFD(operation, error);
+ TEST_AND_RETURN_FALSE(source_fd != nullptr);
+ TEST_AND_RETURN_FALSE(source_fd->IsOpen());
+
+ std::unique_ptr<ExtentWriter> writer =
+ IsXorEnabled() ? std::make_unique<XORExtentWriter>(
+ operation, source_fd, cow_writer_.get(), xor_map_)
+ : CreateBaseExtentWriter();
+ return executor_.ExecuteDiffOperation(
+ operation, std::move(writer), source_fd, data, count);
}
void VABCPartitionWriter::CheckpointUpdateProgress(size_t next_op_index) {
@@ -163,13 +330,22 @@ void VABCPartitionWriter::CheckpointUpdateProgress(size_t next_op_index) {
// Add a hardcoded magic label to indicate end of all install ops. This label
// is needed by filesystem verification, don't remove.
TEST_AND_RETURN_FALSE(cow_writer_ != nullptr);
- return cow_writer_->AddLabel(kEndOfInstallLabel);
+ TEST_AND_RETURN_FALSE(cow_writer_->AddLabel(kEndOfInstallLabel));
+ TEST_AND_RETURN_FALSE(cow_writer_->Finalize());
+ TEST_AND_RETURN_FALSE(cow_writer_->VerifyMergeOps());
+ return true;
}
VABCPartitionWriter::~VABCPartitionWriter() {
+ Close();
+}
+
+int VABCPartitionWriter::Close() {
if (cow_writer_) {
cow_writer_->Finalize();
+ cow_writer_ = nullptr;
}
+ return 0;
}
} // namespace chromeos_update_engine
diff --git a/payload_consumer/vabc_partition_writer.h b/payload_consumer/vabc_partition_writer.h
index 7fb2a2c6..4df5151c 100644
--- a/payload_consumer/vabc_partition_writer.h
+++ b/payload_consumer/vabc_partition_writer.h
@@ -17,26 +17,32 @@
#ifndef UPDATE_ENGINE_VABC_PARTITION_WRITER_H_
#define UPDATE_ENGINE_VABC_PARTITION_WRITER_H_
+#include <map>
#include <memory>
+#include <string>
#include <vector>
#include <libsnapshot/snapshot_writer.h>
#include "update_engine/common/cow_operation_convert.h"
+#include "update_engine/payload_consumer/extent_map.h"
+#include "update_engine/payload_consumer/install_operation_executor.h"
#include "update_engine/payload_consumer/install_plan.h"
#include "update_engine/payload_consumer/partition_writer.h"
+#include "update_engine/payload_generator/extent_ranges.h"
namespace chromeos_update_engine {
-class VABCPartitionWriter final : public PartitionWriter {
+class VABCPartitionWriter final : public PartitionWriterInterface {
public:
- using PartitionWriter::PartitionWriter;
+ VABCPartitionWriter(const PartitionUpdate& partition_update,
+ const InstallPlan::Partition& install_part,
+ DynamicPartitionControlInterface* dynamic_control,
+ size_t block_size);
[[nodiscard]] bool Init(const InstallPlan* install_plan,
bool source_may_exist,
size_t next_op_index) override;
~VABCPartitionWriter() override;
- [[nodiscard]] std::unique_ptr<ExtentWriter> CreateBaseExtentWriter() override;
-
// Only ZERO and SOURCE_COPY InstallOperations are treated special by VABC
// Partition Writer. These operations correspond to COW_ZERO and COW_COPY. All
// other operations just get converted to COW_REPLACE.
@@ -45,17 +51,46 @@ class VABCPartitionWriter final : public PartitionWriter {
[[nodiscard]] bool PerformSourceCopyOperation(
const InstallOperation& operation, ErrorCode* error) override;
+ [[nodiscard]] bool PerformReplaceOperation(const InstallOperation& operation,
+ const void* data,
+ size_t count) override;
+
+ [[nodiscard]] bool PerformDiffOperation(const InstallOperation& operation,
+ ErrorCode* error,
+ const void* data,
+ size_t count) override;
+
void CheckpointUpdateProgress(size_t next_op_index) override;
- static bool WriteAllCowOps(size_t block_size,
- const std::vector<CowOperation>& converted,
- android::snapshot::ICowWriter* cow_writer,
- FileDescriptorPtr source_fd);
+ [[nodiscard]] static bool WriteSourceCopyCowOps(
+ size_t block_size,
+ const std::vector<CowOperation>& converted,
+ android::snapshot::ICowWriter* cow_writer,
+ FileDescriptorPtr source_fd);
[[nodiscard]] bool FinishedInstallOps() override;
+ int Close() override;
+ // Send merge sequence data to cow writer
+ static bool WriteMergeSequence(
+ const ::google::protobuf::RepeatedPtrField<CowMergeOperation>& merge_ops,
+ android::snapshot::ICowWriter* cow_writer);
private:
+ bool IsXorEnabled() const noexcept { return xor_map_.size() > 0; }
std::unique_ptr<android::snapshot::ISnapshotWriter> cow_writer_;
+
+ [[nodiscard]] std::unique_ptr<ExtentWriter> CreateBaseExtentWriter();
+
+ const PartitionUpdate& partition_update_;
+ const InstallPlan::Partition& install_part_;
+ DynamicPartitionControlInterface* const dynamic_control_;
+ // Path to source partition
+ const std::string source_path_;
+
+ const size_t block_size_;
+ InstallOperationExecutor executor_;
+ VerifiedSourceFd verified_source_fd_;
+ ExtentMap<const CowMergeOperation*, ExtentLess> xor_map_;
};
} // namespace chromeos_update_engine
diff --git a/payload_consumer/vabc_partition_writer_unittest.cc b/payload_consumer/vabc_partition_writer_unittest.cc
new file mode 100644
index 00000000..20aa75f8
--- /dev/null
+++ b/payload_consumer/vabc_partition_writer_unittest.cc
@@ -0,0 +1,248 @@
+//
+// Copyright (C) 2021 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 <unistd.h>
+
+#include <android-base/file.h>
+#include <android-base/mapped_file.h>
+#include <android-base/properties.h>
+#include <bsdiff/bsdiff.h>
+#include <gtest/gtest.h>
+#include <libsnapshot/cow_writer.h>
+#include <libsnapshot/mock_snapshot_writer.h>
+
+#include "update_engine/common/hash_calculator.h"
+#include "update_engine/common/mock_dynamic_partition_control.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/vabc_partition_writer.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+using android::snapshot::CowOptions;
+using testing::_;
+using testing::Args;
+using testing::ElementsAreArray;
+using testing::Invoke;
+using testing::Return;
+using testing::Sequence;
+using utils::GetReadonlyZeroBlock;
+
+namespace {
+
+static constexpr auto& fake_part_name = "fake_part";
+static constexpr size_t FAKE_PART_SIZE = 4096 * 50;
+class VABCPartitionWriterTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ ftruncate(source_part_.fd, FAKE_PART_SIZE);
+ ON_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+ .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::NONE)));
+ }
+
+ protected:
+ CowMergeOperation* AddMergeOp(PartitionUpdate* partition,
+ std::array<size_t, 2> src_extent,
+ std::array<size_t, 2> dst_extent,
+ CowMergeOperation_Type type) {
+ auto merge_op = partition->add_merge_operations();
+ auto src = merge_op->mutable_src_extent();
+ src->set_start_block(src_extent[0]);
+ src->set_num_blocks(src_extent[1]);
+ auto dst = merge_op->mutable_dst_extent();
+ dst->set_start_block(dst_extent[0]);
+ dst->set_num_blocks(dst_extent[1]);
+ merge_op->set_type(type);
+ return merge_op;
+ }
+
+ android::snapshot::CowOptions options_ = {
+ .block_size = static_cast<uint32_t>(kBlockSize)};
+ android::snapshot::MockSnapshotWriter cow_writer_{options_};
+ MockDynamicPartitionControl dynamic_control_;
+ PartitionUpdate partition_update_;
+ InstallPlan install_plan_;
+ TemporaryFile source_part_;
+ InstallPlan::Partition install_part_{.name = fake_part_name,
+ .source_path = source_part_.path,
+ .source_size = FAKE_PART_SIZE};
+};
+
+TEST_F(VABCPartitionWriterTest, MergeSequenceWriteTest) {
+ AddMergeOp(&partition_update_, {5, 1}, {10, 1}, CowMergeOperation::COW_COPY);
+ AddMergeOp(&partition_update_, {12, 2}, {13, 2}, CowMergeOperation::COW_XOR);
+ AddMergeOp(&partition_update_, {15, 1}, {20, 1}, CowMergeOperation::COW_COPY);
+ AddMergeOp(&partition_update_, {20, 1}, {25, 1}, CowMergeOperation::COW_COPY);
+ AddMergeOp(&partition_update_, {42, 5}, {40, 5}, CowMergeOperation::COW_XOR);
+ VABCPartitionWriter writer_{
+ partition_update_, install_part_, &dynamic_control_, kBlockSize};
+ EXPECT_CALL(dynamic_control_, OpenCowWriter(fake_part_name, _, false))
+ .WillOnce(Invoke([](const std::string&,
+ const std::optional<std::string>&,
+ bool) {
+ auto cow_writer =
+ std::make_unique<android::snapshot::MockSnapshotWriter>(
+ android::snapshot::CowOptions{});
+ auto expected_merge_sequence = {10, 14, 13, 20, 25, 40, 41, 42, 43, 44};
+ EXPECT_CALL(*cow_writer, Initialize()).WillOnce(Return(true));
+ EXPECT_CALL(*cow_writer, EmitSequenceData(_, _))
+ .With(Args<1, 0>(ElementsAreArray(expected_merge_sequence)))
+ .WillOnce(Return(true));
+ ON_CALL(*cow_writer, EmitCopy(_, _)).WillByDefault(Return(true));
+ ON_CALL(*cow_writer, EmitLabel(_)).WillByDefault(Return(true));
+ return cow_writer;
+ }));
+ EXPECT_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+ .WillRepeatedly(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
+ ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
+}
+
+TEST_F(VABCPartitionWriterTest, MergeSequenceXorSameBlock) {
+ AddMergeOp(&partition_update_, {19, 4}, {19, 3}, CowMergeOperation::COW_XOR)
+ ->set_src_offset(1);
+ VABCPartitionWriter writer_{
+ partition_update_, install_part_, &dynamic_control_, kBlockSize};
+ EXPECT_CALL(dynamic_control_, OpenCowWriter(fake_part_name, _, false))
+ .WillOnce(Invoke(
+ [](const std::string&, const std::optional<std::string>&, bool) {
+ auto cow_writer =
+ std::make_unique<android::snapshot::MockSnapshotWriter>(
+ android::snapshot::CowOptions{});
+ auto expected_merge_sequence = {19, 20, 21};
+ EXPECT_CALL(*cow_writer, Initialize()).WillOnce(Return(true));
+ EXPECT_CALL(*cow_writer, EmitSequenceData(_, _))
+ .With(Args<1, 0>(ElementsAreArray(expected_merge_sequence)))
+ .WillOnce(Return(true));
+ ON_CALL(*cow_writer, EmitCopy(_, _)).WillByDefault(Return(true));
+ ON_CALL(*cow_writer, EmitLabel(_)).WillByDefault(Return(true));
+ return cow_writer;
+ }));
+ EXPECT_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+ .WillRepeatedly(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
+ ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
+}
+
+TEST_F(VABCPartitionWriterTest, EmitBlockTest) {
+ AddMergeOp(&partition_update_, {5, 1}, {10, 1}, CowMergeOperation::COW_COPY);
+ AddMergeOp(&partition_update_, {10, 1}, {15, 1}, CowMergeOperation::COW_COPY);
+ AddMergeOp(&partition_update_, {15, 2}, {20, 2}, CowMergeOperation::COW_COPY);
+ AddMergeOp(&partition_update_, {20, 1}, {25, 1}, CowMergeOperation::COW_COPY);
+ VABCPartitionWriter writer_{
+ partition_update_, install_part_, &dynamic_control_, kBlockSize};
+ EXPECT_CALL(dynamic_control_, OpenCowWriter(fake_part_name, _, false))
+ .WillOnce(Invoke(
+ [](const std::string&, const std::optional<std::string>&, bool) {
+ auto cow_writer =
+ std::make_unique<android::snapshot::MockSnapshotWriter>(
+ android::snapshot::CowOptions{});
+ Sequence s;
+ ON_CALL(*cow_writer, EmitCopy(_, _)).WillByDefault(Return(true));
+ ON_CALL(*cow_writer, EmitLabel(_)).WillByDefault(Return(true));
+ ON_CALL(*cow_writer, Initialize()).WillByDefault(Return(true));
+ EXPECT_CALL(*cow_writer, Initialize()).InSequence(s);
+ EXPECT_CALL(*cow_writer, EmitCopy(10, 5)).InSequence(s);
+ EXPECT_CALL(*cow_writer, EmitCopy(15, 10)).InSequence(s);
+ // libsnapshot want blocks in reverser order, so 21 goes before 20
+ EXPECT_CALL(*cow_writer, EmitCopy(21, 16)).InSequence(s);
+ EXPECT_CALL(*cow_writer, EmitCopy(20, 15)).InSequence(s);
+
+ EXPECT_CALL(*cow_writer, EmitCopy(25, 20)).InSequence(s);
+ return cow_writer;
+ }));
+ ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
+}
+
+std::string GetNoopBSDIFF(size_t data_size) {
+ auto zeros = GetReadonlyZeroBlock(data_size);
+ TemporaryFile patch_file;
+ int error = bsdiff::bsdiff(reinterpret_cast<const uint8_t*>(zeros->data()),
+ zeros->size(),
+ reinterpret_cast<const uint8_t*>(zeros->data()),
+ zeros->size(),
+ patch_file.path,
+ nullptr);
+ if (error) {
+ LOG(ERROR) << "Failed to generate BSDIFF patch " << error;
+ return {};
+ }
+ std::string patch_data;
+ if (!utils::ReadFile(patch_file.path, &patch_data)) {
+ return {};
+ }
+ return patch_data;
+}
+
+TEST_F(VABCPartitionWriterTest, StreamXORBlockTest) {
+ AddMergeOp(&partition_update_, {5, 2}, {10, 2}, CowMergeOperation::COW_XOR);
+ AddMergeOp(&partition_update_, {8, 2}, {13, 2}, CowMergeOperation::COW_XOR);
+ auto install_op = partition_update_.add_operations();
+ *install_op->add_src_extents() = ExtentForRange(5, 5);
+ *install_op->add_dst_extents() = ExtentForRange(10, 5);
+ install_op->set_type(InstallOperation::SOURCE_BSDIFF);
+ auto data_hash = install_op->mutable_src_sha256_hash();
+ auto zeros = GetReadonlyZeroBlock(kBlockSize * 5);
+ brillo::Blob expected_hash;
+ truncate64(source_part_.path, kBlockSize * 20);
+ HashCalculator::RawHashOfBytes(zeros->data(), zeros->size(), &expected_hash);
+ data_hash->assign(reinterpret_cast<const char*>(expected_hash.data()),
+ expected_hash.size());
+
+ EXPECT_CALL(dynamic_control_, OpenCowWriter(fake_part_name, _, false))
+ .WillOnce(Invoke([](const std::string&,
+ const std::optional<std::string>&,
+ bool) {
+ auto cow_writer =
+ std::make_unique<android::snapshot::MockSnapshotWriter>(
+ android::snapshot::CowOptions{});
+ ON_CALL(*cow_writer, EmitLabel(_)).WillByDefault(Return(true));
+ auto expected_merge_sequence = {10, 11, 13, 14};
+ auto expected_merge_sequence_rev = {11, 10, 14, 13};
+ const bool is_ascending = android::base::GetBoolProperty(
+ "ro.virtual_ab.userspace.snapshots.enabled", false);
+ ON_CALL(*cow_writer, Initialize()).WillByDefault(Return(true));
+ if (!is_ascending) {
+ EXPECT_CALL(*cow_writer, EmitSequenceData(_, _))
+ .With(Args<1, 0>(ElementsAreArray(expected_merge_sequence_rev)))
+ .WillOnce(Return(true));
+ } else {
+ EXPECT_CALL(*cow_writer, EmitSequenceData(_, _))
+ .With(Args<1, 0>(ElementsAreArray(expected_merge_sequence)))
+ .WillOnce(Return(true));
+ }
+ EXPECT_CALL(*cow_writer, Initialize()).Times(1);
+ EXPECT_CALL(*cow_writer, EmitCopy(_, _)).Times(0);
+ EXPECT_CALL(*cow_writer, EmitRawBlocks(_, _, _)).WillOnce(Return(true));
+ EXPECT_CALL(*cow_writer, EmitXorBlocks(10, _, kBlockSize * 2, 5, 0))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*cow_writer, EmitXorBlocks(13, _, kBlockSize * 2, 8, 0))
+ .WillOnce(Return(true));
+ return cow_writer;
+ }));
+ EXPECT_CALL(dynamic_control_, GetVirtualAbCompressionXorFeatureFlag())
+ .WillRepeatedly(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
+ VABCPartitionWriter writer_{
+ partition_update_, install_part_, &dynamic_control_, kBlockSize};
+ ASSERT_TRUE(writer_.Init(&install_plan_, true, 0));
+ const auto patch_data = GetNoopBSDIFF(kBlockSize * 5);
+ ASSERT_GT(patch_data.size(), 0UL);
+ ASSERT_TRUE(writer_.PerformDiffOperation(
+ *install_op, nullptr, patch_data.data(), patch_data.size()));
+}
+
+} // namespace
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/verified_source_fd.cc b/payload_consumer/verified_source_fd.cc
new file mode 100644
index 00000000..002bd072
--- /dev/null
+++ b/payload_consumer/verified_source_fd.cc
@@ -0,0 +1,124 @@
+//
+// Copyright (C) 2021 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
+// limi
+
+#include "update_engine/payload_consumer/verified_source_fd.h"
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/fec_file_descriptor.h"
+#include "update_engine/payload_consumer/file_descriptor_utils.h"
+#include "update_engine/payload_consumer/mount_history.h"
+#include "update_engine/payload_consumer/partition_writer.h"
+
+namespace chromeos_update_engine {
+using std::string;
+
+bool VerifiedSourceFd::OpenCurrentECCPartition() {
+ // No support for ECC for full payloads.
+ // Full payload should not have any opeartion that requires ECC partitions.
+ if (source_ecc_fd_)
+ return true;
+
+ if (source_ecc_open_failure_)
+ return false;
+
+#if USE_FEC
+ FileDescriptorPtr fd(new FecFileDescriptor());
+ if (!fd->Open(source_path_.c_str(), O_RDONLY, 0)) {
+ PLOG(ERROR) << "Unable to open ECC source partition " << source_path_;
+ source_ecc_open_failure_ = true;
+ return false;
+ }
+ source_ecc_fd_ = fd;
+#else
+ // No support for ECC compiled.
+ source_ecc_open_failure_ = true;
+#endif // USE_FEC
+
+ return !source_ecc_open_failure_;
+}
+
+FileDescriptorPtr VerifiedSourceFd::ChooseSourceFD(
+ const InstallOperation& operation, ErrorCode* error) {
+ if (source_fd_ == nullptr) {
+ LOG(ERROR) << "ChooseSourceFD fail: source_fd_ == nullptr";
+ return nullptr;
+ }
+ if (!operation.has_src_sha256_hash()) {
+ // When the operation doesn't include a source hash, we attempt the error
+ // corrected device first since we can't verify the block in the raw device
+ // at this point, but we first need to make sure all extents are readable
+ // since the error corrected device can be shorter or not available.
+ if (OpenCurrentECCPartition() &&
+ fd_utils::ReadAndHashExtents(
+ source_ecc_fd_, operation.src_extents(), block_size_, nullptr)) {
+ return source_ecc_fd_;
+ }
+ return source_fd_;
+ }
+
+ brillo::Blob source_hash;
+ brillo::Blob expected_source_hash(operation.src_sha256_hash().begin(),
+ operation.src_sha256_hash().end());
+ if (fd_utils::ReadAndHashExtents(
+ source_fd_, operation.src_extents(), block_size_, &source_hash) &&
+ source_hash == expected_source_hash) {
+ return source_fd_;
+ }
+ // We fall back to use the error corrected device if the hash of the raw
+ // device doesn't match or there was an error reading the source partition.
+ if (!OpenCurrentECCPartition()) {
+ // The following function call will return false since the source hash
+ // mismatches, but we still want to call it so it prints the appropriate
+ // log message.
+ PartitionWriter::ValidateSourceHash(
+ source_hash, operation, source_fd_, error);
+ return nullptr;
+ }
+ LOG(WARNING) << "Source hash from RAW device mismatched: found "
+ << base::HexEncode(source_hash.data(), source_hash.size())
+ << ", expected "
+ << base::HexEncode(expected_source_hash.data(),
+ expected_source_hash.size());
+
+ if (fd_utils::ReadAndHashExtents(
+ source_ecc_fd_, operation.src_extents(), block_size_, &source_hash) &&
+ PartitionWriter::ValidateSourceHash(
+ source_hash, operation, source_ecc_fd_, error)) {
+ source_ecc_recovered_failures_++;
+ return source_ecc_fd_;
+ }
+ return nullptr;
+}
+
+bool VerifiedSourceFd::Open() {
+ source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
+ if (source_fd_ == nullptr)
+ return false;
+ TEST_AND_RETURN_FALSE_ERRNO(source_fd_->Open(source_path_.c_str(), O_RDONLY));
+ return true;
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/verified_source_fd.h b/payload_consumer/verified_source_fd.h
new file mode 100644
index 00000000..f7d06207
--- /dev/null
+++ b/payload_consumer/verified_source_fd.h
@@ -0,0 +1,61 @@
+//
+// Copyright (C) 2021 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
+// limi
+
+#ifndef UPDATE_ENGINE_VERIFIED_SOURCE_FD_H__
+#define UPDATE_ENGINE_VERIFIED_SOURCE_FD_H__
+
+#include <cstddef>
+
+#include <string>
+#include <utility>
+
+#include <gtest/gtest_prod.h>
+#include <update_engine/update_metadata.pb.h>
+
+#include "update_engine/common/error_code.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+
+namespace chromeos_update_engine {
+
+class VerifiedSourceFd {
+ public:
+ explicit VerifiedSourceFd(size_t block_size, std::string source_path)
+ : block_size_(block_size), source_path_(std::move(source_path)) {}
+ FileDescriptorPtr ChooseSourceFD(const InstallOperation& operation,
+ ErrorCode* error);
+
+ [[nodiscard]] bool Open();
+
+ private:
+ bool OpenCurrentECCPartition();
+ const size_t block_size_;
+ const std::string source_path_;
+ FileDescriptorPtr source_ecc_fd_;
+ FileDescriptorPtr source_fd_;
+
+ friend class PartitionWriterTest;
+ FRIEND_TEST(PartitionWriterTest, ChooseSourceFDTest);
+ // The total number of operations that failed source hash verification but
+ // passed after falling back to the error-corrected |source_ecc_fd_| device.
+ uint64_t source_ecc_recovered_failures_{0};
+
+ // Whether opening the current partition as an error-corrected device failed.
+ // Used to avoid re-opening the same source partition if it is not actually
+ // error corrected.
+ bool source_ecc_open_failure_{false};
+};
+} // namespace chromeos_update_engine
+
+#endif
diff --git a/payload_consumer/verity_writer_android.cc b/payload_consumer/verity_writer_android.cc
index e2fab7dd..91efa3e2 100644
--- a/payload_consumer/verity_writer_android.cc
+++ b/payload_consumer/verity_writer_android.cc
@@ -104,8 +104,8 @@ bool VerityWriterAndroid::Update(const uint64_t offset,
return true;
}
-bool VerityWriterAndroid::Finalize(FileDescriptorPtr read_fd,
- FileDescriptorPtr write_fd) {
+bool VerityWriterAndroid::Finalize(FileDescriptor* read_fd,
+ FileDescriptor* write_fd) {
const auto hash_tree_data_end =
partition_->hash_tree_data_offset + partition_->hash_tree_data_size;
if (total_offset_ < hash_tree_data_end) {
@@ -116,19 +116,22 @@ bool VerityWriterAndroid::Finalize(FileDescriptorPtr read_fd,
return false;
}
// All hash tree data blocks has been hashed, write hash tree to disk.
- LOG(INFO) << "Writing verity hash tree to " << partition_->target_path;
- TEST_AND_RETURN_FALSE(hash_tree_builder_->BuildHashTree());
- TEST_AND_RETURN_FALSE_ERRNO(
- write_fd->Seek(partition_->hash_tree_offset, SEEK_SET));
- auto success =
- hash_tree_builder_->WriteHashTree([write_fd](auto data, auto size) {
- return utils::WriteAll(write_fd, data, size);
- });
- // hashtree builder already prints error messages.
- TEST_AND_RETURN_FALSE(success);
- hash_tree_builder_.reset();
+ LOG(INFO) << "Writing verity hash tree to "
+ << partition_->readonly_target_path;
+ if (hash_tree_builder_) {
+ TEST_AND_RETURN_FALSE(hash_tree_builder_->BuildHashTree());
+ TEST_AND_RETURN_FALSE_ERRNO(
+ write_fd->Seek(partition_->hash_tree_offset, SEEK_SET));
+ auto success =
+ hash_tree_builder_->WriteHashTree([write_fd](auto data, auto size) {
+ return utils::WriteAll(write_fd, data, size);
+ });
+ // hashtree builder already prints error messages.
+ TEST_AND_RETURN_FALSE(success);
+ hash_tree_builder_.reset();
+ }
if (partition_->fec_size != 0) {
- LOG(INFO) << "Writing verity FEC to " << partition_->target_path;
+ LOG(INFO) << "Writing verity FEC to " << partition_->readonly_target_path;
TEST_AND_RETURN_FALSE(EncodeFEC(read_fd,
write_fd,
partition_->fec_data_offset,
@@ -142,8 +145,8 @@ bool VerityWriterAndroid::Finalize(FileDescriptorPtr read_fd,
return true;
}
-bool VerityWriterAndroid::EncodeFEC(FileDescriptorPtr read_fd,
- FileDescriptorPtr write_fd,
+bool VerityWriterAndroid::EncodeFEC(FileDescriptor* read_fd,
+ FileDescriptor* write_fd,
uint64_t data_offset,
uint64_t data_size,
uint64_t fec_offset,
@@ -161,11 +164,12 @@ bool VerityWriterAndroid::EncodeFEC(FileDescriptorPtr read_fd,
std::unique_ptr<void, decltype(&free_rs_char)> rs_char(
init_rs_char(FEC_PARAMS(fec_roots)), &free_rs_char);
TEST_AND_RETURN_FALSE(rs_char != nullptr);
-
// Cache at most 1MB of fec data, in VABC, we need to re-open fd if we
// perform a read() operation after write(). So reduce the number of writes
// can save unnecessary re-opens.
- write_fd = std::make_shared<CachedFileDescriptor>(write_fd, 1 * (1 << 20));
+ UnownedCachedFileDescriptor cache_fd(write_fd, 1 * (1 << 20));
+ write_fd = &cache_fd;
+
for (size_t i = 0; i < rounds; i++) {
// Encodes |block_size| number of rs blocks each round so that we can read
// one block each time instead of 1 byte to increase random read
@@ -229,11 +233,10 @@ bool VerityWriterAndroid::EncodeFEC(const std::string& path,
uint32_t fec_roots,
uint32_t block_size,
bool verify_mode) {
- FileDescriptorPtr fd(new EintrSafeFileDescriptor());
- TEST_AND_RETURN_FALSE(
- fd->Open(path.c_str(), verify_mode ? O_RDONLY : O_RDWR));
- return EncodeFEC(fd,
- fd,
+ EintrSafeFileDescriptor fd;
+ TEST_AND_RETURN_FALSE(fd.Open(path.c_str(), verify_mode ? O_RDONLY : O_RDWR));
+ return EncodeFEC(&fd,
+ &fd,
data_offset,
data_size,
fec_offset,
diff --git a/payload_consumer/verity_writer_android.h b/payload_consumer/verity_writer_android.h
index 8339528d..a6a49209 100644
--- a/payload_consumer/verity_writer_android.h
+++ b/payload_consumer/verity_writer_android.h
@@ -34,7 +34,7 @@ class VerityWriterAndroid : public VerityWriterInterface {
bool Init(const InstallPlan::Partition& partition);
bool Update(uint64_t offset, const uint8_t* buffer, size_t size) override;
- bool Finalize(FileDescriptorPtr read_fd, FileDescriptorPtr write_fd) override;
+ bool Finalize(FileDescriptor* read_fd, FileDescriptor* write_fd) override;
// Read [data_offset : data_offset + data_size) from |path| and encode FEC
// data, if |verify_mode|, then compare the encoded FEC with the one in
@@ -42,8 +42,8 @@ class VerityWriterAndroid : public VerityWriterInterface {
// in each Update() like hash tree, because for every rs block, its data are
// spreaded across entire |data_size|, unless we can cache all data in
// memory, we have to re-read them from disk.
- static bool EncodeFEC(FileDescriptorPtr read_fd,
- FileDescriptorPtr write_fd,
+ static bool EncodeFEC(FileDescriptor* read_fd,
+ FileDescriptor* write_fd,
uint64_t data_offset,
uint64_t data_size,
uint64_t fec_offset,
diff --git a/payload_consumer/verity_writer_android_unittest.cc b/payload_consumer/verity_writer_android_unittest.cc
index 75da0ae3..5ff0189e 100644
--- a/payload_consumer/verity_writer_android_unittest.cc
+++ b/payload_consumer/verity_writer_android_unittest.cc
@@ -54,7 +54,8 @@ TEST_F(VerityWriterAndroidTest, SimpleTest) {
ASSERT_TRUE(verity_writer_.Init(partition_));
ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), 4096));
ASSERT_TRUE(verity_writer_.Update(4096, part_data.data() + 4096, 4096));
- ASSERT_TRUE(verity_writer_.Finalize(partition_fd_, partition_fd_));
+ ASSERT_TRUE(
+ verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
brillo::Blob actual_part;
utils::ReadFile(partition_.target_path, &actual_part);
// dd if=/dev/zero bs=4096 count=1 2>/dev/null | sha1sum | xxd -r -p |
@@ -102,7 +103,8 @@ TEST_F(VerityWriterAndroidTest, SHA256Test) {
ASSERT_TRUE(verity_writer_.Init(partition_));
ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), 4096));
ASSERT_TRUE(verity_writer_.Update(4096, part_data.data() + 4096, 4096));
- ASSERT_TRUE(verity_writer_.Finalize(partition_fd_, partition_fd_));
+ ASSERT_TRUE(
+ verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
brillo::Blob actual_part;
utils::ReadFile(partition_.target_path, &actual_part);
// dd if=/dev/zero bs=4096 count=1 2>/dev/null | sha256sum | xxd -r -p |
@@ -127,7 +129,8 @@ TEST_F(VerityWriterAndroidTest, NonZeroOffsetSHA256Test) {
ASSERT_TRUE(verity_writer_.Update(4096, part_data.data() + 4096, 4096));
ASSERT_TRUE(verity_writer_.Update(
8192, part_data.data() + 8192, partition_.hash_tree_data_offset));
- ASSERT_TRUE(verity_writer_.Finalize(partition_fd_, partition_fd_));
+ ASSERT_TRUE(
+ verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
brillo::Blob actual_part;
utils::ReadFile(partition_.target_path, &actual_part);
// dd if=/dev/zero bs=4096 count=1 2>/dev/null | sha256sum | xxd -r -p |
@@ -150,7 +153,8 @@ TEST_F(VerityWriterAndroidTest, FECTest) {
test_utils::WriteFileVector(partition_.target_path, part_data);
ASSERT_TRUE(verity_writer_.Init(partition_));
ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), part_data.size()));
- ASSERT_TRUE(verity_writer_.Finalize(partition_fd_, partition_fd_));
+ ASSERT_TRUE(
+ verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
brillo::Blob actual_part;
utils::ReadFile(partition_.target_path, &actual_part);
// Write FEC data.
@@ -161,4 +165,22 @@ TEST_F(VerityWriterAndroidTest, FECTest) {
ASSERT_EQ(part_data, actual_part);
}
+TEST_F(VerityWriterAndroidTest, HashTreeDisabled) {
+ partition_.hash_tree_size = 0;
+ partition_.hash_tree_data_size = 0;
+ partition_.hash_tree_offset = 0;
+ partition_.hash_tree_data_offset = 0;
+
+ partition_.fec_data_offset = 0;
+ partition_.fec_data_size = 4096;
+ partition_.fec_offset = 4096;
+ partition_.fec_size = 2 * 4096;
+ brillo::Blob part_data(3 * 4096, 0x1);
+ test_utils::WriteFileVector(partition_.target_path, part_data);
+ ASSERT_TRUE(verity_writer_.Init(partition_));
+ ASSERT_TRUE(verity_writer_.Update(0, part_data.data(), part_data.size()));
+ ASSERT_TRUE(
+ verity_writer_.Finalize(partition_fd_.get(), partition_fd_.get()));
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_consumer/verity_writer_interface.h b/payload_consumer/verity_writer_interface.h
index 37ed605c..432ede73 100644
--- a/payload_consumer/verity_writer_interface.h
+++ b/payload_consumer/verity_writer_interface.h
@@ -39,8 +39,7 @@ class VerityWriterInterface {
virtual bool Update(uint64_t offset, const uint8_t* buffer, size_t size) = 0;
// Write hash tree && FEC data to underlying fd, if they are present
- virtual bool Finalize(FileDescriptorPtr read_fd,
- FileDescriptorPtr write_fd) = 0;
+ virtual bool Finalize(FileDescriptor* read_fd, FileDescriptor* write_fd) = 0;
protected:
VerityWriterInterface() = default;
diff --git a/payload_consumer/xor_extent_writer.cc b/payload_consumer/xor_extent_writer.cc
new file mode 100644
index 00000000..31567f29
--- /dev/null
+++ b/payload_consumer/xor_extent_writer.cc
@@ -0,0 +1,121 @@
+//
+// Copyright (C) 2021 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 <algorithm>
+#include <optional>
+#include <vector>
+
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/xor_extent_writer.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+namespace chromeos_update_engine {
+
+// Returns true on success.
+bool XORExtentWriter::WriteExtent(const void* bytes,
+ const Extent& extent,
+ const size_t size) {
+ brillo::Blob xor_block_data;
+ const auto xor_extents = xor_map_.GetIntersectingExtents(extent);
+ for (const auto& xor_ext : xor_extents) {
+ const auto merge_op_opt = xor_map_.Get(xor_ext);
+ if (!merge_op_opt.has_value()) {
+ // If a file in the target build contains duplicate blocks, e.g.
+ // [120503-120514], [120503-120503], we can end up here. If that's the
+ // case then there's no bug, just some annoying edge cases.
+ LOG(ERROR)
+ << xor_ext
+ << " isn't in XOR map but it's returned by GetIntersectingExtents(), "
+ "this is either a bug inside GetIntersectingExtents, or some "
+ "duplicate blocks are present in target build. OTA extent: "
+ << extent;
+ return false;
+ }
+
+ const auto merge_op = merge_op_opt.value();
+ TEST_AND_RETURN_FALSE(merge_op->has_src_extent());
+ TEST_AND_RETURN_FALSE(merge_op->has_dst_extent());
+ if (merge_op->dst_extent() != xor_ext) {
+ LOG(ERROR) << "Each xor extent is expected to correspond to a complete "
+ "MergeOp, extent in value: "
+ << merge_op->dst_extent() << " extent in key: " << xor_ext;
+ return false;
+ }
+ if (xor_ext.start_block() + xor_ext.num_blocks() >
+ extent.start_block() + extent.num_blocks()) {
+ LOG(ERROR) << "CowXor merge op extent should be completely inside "
+ "InstallOp's extent. merge op extent: "
+ << xor_ext << " InstallOp extent: " << extent;
+ return false;
+ }
+ const auto src_offset = merge_op->src_offset();
+ const auto src_block = merge_op->src_extent().start_block();
+ xor_block_data.resize(BlockSize() * xor_ext.num_blocks());
+ ssize_t bytes_read = 0;
+ TEST_AND_RETURN_FALSE_ERRNO(
+ utils::PReadAll(source_fd_,
+ xor_block_data.data(),
+ xor_block_data.size(),
+ src_offset + src_block * BlockSize(),
+ &bytes_read));
+ if (bytes_read != static_cast<ssize_t>(xor_block_data.size())) {
+ LOG(ERROR) << "bytes_read: " << bytes_read;
+ return false;
+ }
+
+ const auto i = xor_ext.start_block() - extent.start_block();
+
+ const auto dst_block_data =
+ static_cast<const unsigned char*>(bytes) + i * BlockSize();
+ std::transform(xor_block_data.cbegin(),
+ xor_block_data.cbegin() + xor_block_data.size(),
+ dst_block_data,
+ xor_block_data.begin(),
+ std::bit_xor<unsigned char>{});
+ TEST_AND_RETURN_FALSE(cow_writer_->AddXorBlocks(xor_ext.start_block(),
+ xor_block_data.data(),
+ xor_block_data.size(),
+ src_block,
+ src_offset));
+ }
+ const auto replace_extents = xor_map_.GetNonIntersectingExtents(extent);
+ return WriteReplaceExtents(replace_extents, extent, bytes, size);
+}
+
+bool XORExtentWriter::WriteReplaceExtents(
+ const std::vector<Extent>& replace_extents,
+ const Extent& extent,
+ const void* bytes,
+ size_t size) {
+ const uint64_t new_block_start = extent.start_block();
+ for (const auto& ext : replace_extents) {
+ if (ext.start_block() + ext.num_blocks() >
+ extent.start_block() + extent.num_blocks()) {
+ LOG(ERROR) << "CowReplace merge op extent should be completely inside "
+ "InstallOp's extent. merge op extent: "
+ << ext << " InstallOp extent: " << extent;
+ return false;
+ }
+ const auto i = ext.start_block() - new_block_start;
+ const auto dst_block_data =
+ static_cast<const unsigned char*>(bytes) + i * BlockSize();
+ TEST_AND_RETURN_FALSE(cow_writer_->AddRawBlocks(
+ ext.start_block(), dst_block_data, ext.num_blocks() * BlockSize()));
+ }
+ return true;
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/xor_extent_writer.h b/payload_consumer/xor_extent_writer.h
new file mode 100644
index 00000000..35565eab
--- /dev/null
+++ b/payload_consumer/xor_extent_writer.h
@@ -0,0 +1,68 @@
+//
+// Copyright (C) 2021 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_PAYLOAD_CONSUMER_XOR_EXTENT_WRITER_H_
+#define UPDATE_ENGINE_PAYLOAD_CONSUMER_XOR_EXTENT_WRITER_H_
+
+#include <vector>
+
+#include "update_engine/payload_consumer/block_extent_writer.h"
+#include "update_engine/payload_consumer/extent_map.h"
+#include "update_engine/payload_consumer/extent_reader.h"
+#include "update_engine/payload_consumer/extent_writer.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+#include <update_engine/update_metadata.pb.h>
+#include <libsnapshot/cow_writer.h>
+
+namespace chromeos_update_engine {
+
+// An extent writer that will selectively convert some of the blocks into an XOR
+// block. All blocks that appear in |xor_map| will be converted,
+class XORExtentWriter : public BlockExtentWriter {
+ public:
+ XORExtentWriter(const InstallOperation& op,
+ FileDescriptorPtr source_fd,
+ android::snapshot::ICowWriter* cow_writer,
+ const ExtentMap<const CowMergeOperation*>& xor_map)
+ : src_extents_(op.src_extents()),
+ source_fd_(source_fd),
+ xor_map_(xor_map),
+ cow_writer_(cow_writer) {
+ CHECK(source_fd->IsOpen());
+ }
+ ~XORExtentWriter() = default;
+
+ // Returns true on success.
+ bool WriteExtent(const void* bytes,
+ const Extent& extent,
+ size_t size) override;
+
+ private:
+ bool WriteReplaceExtents(const std::vector<Extent>& replace_extents,
+ const Extent& extent,
+ const void* bytes,
+ size_t size);
+ const google::protobuf::RepeatedPtrField<Extent>& src_extents_;
+ const FileDescriptorPtr source_fd_;
+ const ExtentMap<const CowMergeOperation*>& xor_map_;
+ android::snapshot::ICowWriter* cow_writer_;
+};
+
+} // namespace chromeos_update_engine
+
+#endif // UPDATE_ENGINE_PAYLOAD_CONSUMER_XOR_EXTENT_WRITER_H_
diff --git a/payload_consumer/xor_extent_writer_unittest.cc b/payload_consumer/xor_extent_writer_unittest.cc
new file mode 100644
index 00000000..7f35bc28
--- /dev/null
+++ b/payload_consumer/xor_extent_writer_unittest.cc
@@ -0,0 +1,134 @@
+//
+// Copyright (C) 2021 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 <memory>
+
+#include <unistd.h>
+
+#include <android-base/file.h>
+#include <gtest/gtest.h>
+#include <libsnapshot/mock_snapshot_writer.h>
+
+#include "common/utils.h"
+#include "update_engine/payload_consumer/extent_map.h"
+#include "update_engine/payload_consumer/file_descriptor.h"
+#include "update_engine/payload_consumer/xor_extent_writer.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/merge_sequence_generator.h"
+#include "update_engine/update_metadata.pb.h"
+
+namespace chromeos_update_engine {
+
+using testing::_;
+using testing::Args;
+using testing::Return;
+
+class XorExtentWriterTest : public ::testing::Test {
+ public:
+ static constexpr size_t NUM_BLOCKS = 50;
+ void SetUp() override {
+ ASSERT_EQ(ftruncate64(source_part_.fd, kBlockSize * NUM_BLOCKS), 0);
+ ASSERT_EQ(ftruncate64(target_part_.fd, kBlockSize * NUM_BLOCKS), 0);
+
+ // Fill source part with 1s, as we are computing XOR between source and
+ // target data later.
+ ASSERT_EQ(lseek(source_part_.fd, 0, SEEK_SET), 0);
+ brillo::Blob buffer(kBlockSize);
+ std::fill(buffer.begin(), buffer.end(), 1);
+ for (size_t i = 0; i < NUM_BLOCKS; i++) {
+ ASSERT_EQ(write(source_part_.fd, buffer.data(), buffer.size()),
+ static_cast<ssize_t>(buffer.size()));
+ }
+ ASSERT_EQ(fsync(source_part_.fd), 0);
+ ASSERT_EQ(fsync(target_part_.fd), 0);
+ ASSERT_TRUE(source_fd_->Open(source_part_.path, O_RDONLY | O_CREAT, 0644));
+ }
+ InstallOperation op_;
+ FileDescriptorPtr source_fd_ = std::make_shared<EintrSafeFileDescriptor>();
+ ExtentMap<const CowMergeOperation*> xor_map_;
+ android::snapshot::MockSnapshotWriter cow_writer_;
+ TemporaryFile source_part_;
+ TemporaryFile target_part_;
+};
+
+MATCHER_P2(BytesEqual,
+ bytes,
+ size,
+ "Check if args match expected value byte for byte") {
+ return std::get<1>(arg) == size && std::get<0>(arg) != nullptr &&
+ memcmp(std::get<0>(arg), bytes, size) == 0;
+}
+
+TEST_F(XorExtentWriterTest, StreamTest) {
+ constexpr auto COW_XOR = CowMergeOperation::COW_XOR;
+ ON_CALL(cow_writer_, EmitXorBlocks(_, _, _, _, _))
+ .WillByDefault(Return(true));
+ const auto op1 = CreateCowMergeOperation(
+ ExtentForRange(5, 2), ExtentForRange(5, 2), COW_XOR);
+ ASSERT_TRUE(xor_map_.AddExtent(op1.dst_extent(), &op1));
+ *op_.add_src_extents() = op1.src_extent();
+ *op_.add_dst_extents() = op1.dst_extent();
+
+ const auto op2 = CreateCowMergeOperation(
+ ExtentForRange(45, 2), ExtentForRange(456, 2), COW_XOR);
+ ASSERT_TRUE(xor_map_.AddExtent(op2.dst_extent(), &op2));
+ *op_.add_src_extents() = ExtentForRange(45, 3);
+ *op_.add_dst_extents() = ExtentForRange(455, 3);
+
+ const auto op3 = CreateCowMergeOperation(
+ ExtentForRange(12, 2), ExtentForRange(321, 2), COW_XOR, 777);
+ ASSERT_TRUE(xor_map_.AddExtent(op3.dst_extent(), &op3));
+ *op_.add_src_extents() = ExtentForRange(12, 4);
+ *op_.add_dst_extents() = ExtentForRange(320, 4);
+ XORExtentWriter writer_{op_, source_fd_, &cow_writer_, xor_map_};
+
+ // OTA op:
+ // [5-6] => [5-6], [45-47] => [455-457], [12-15] => [320-323]
+
+ // merge op:
+ // [5-6] => [5-6], [45-46] => [456-457], [12-13] => [321-322]
+
+ // Expected result:
+ // [5-7], [45-47], [12-14] should be XOR blocks
+ // [320], [323], [455] should be regular replace blocks
+
+ auto zeros = utils::GetReadonlyZeroBlock(kBlockSize * 10);
+ EXPECT_CALL(cow_writer_,
+ EmitRawBlocks(455, zeros->data() + 2 * kBlockSize, kBlockSize))
+ .With(Args<1, 2>(BytesEqual(zeros->data(), kBlockSize)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(cow_writer_,
+ EmitRawBlocks(320, zeros->data() + 5 * kBlockSize, kBlockSize))
+ .With(Args<1, 2>(BytesEqual(zeros->data(), kBlockSize)))
+ .WillOnce(Return(true));
+ EXPECT_CALL(cow_writer_,
+ EmitRawBlocks(323, zeros->data() + 8 * kBlockSize, kBlockSize))
+ .With(Args<1, 2>(BytesEqual(zeros->data(), kBlockSize)))
+ .WillOnce(Return(true));
+
+ EXPECT_CALL(cow_writer_, EmitXorBlocks(5, _, kBlockSize * 2, 5, 0))
+ .WillOnce(Return(true));
+ EXPECT_CALL(cow_writer_, EmitXorBlocks(456, _, kBlockSize * 2, 45, 0))
+ .WillOnce(Return(true));
+ EXPECT_CALL(cow_writer_, EmitXorBlocks(321, _, kBlockSize * 2, 12, 777))
+ .WillOnce(Return(true));
+
+ ASSERT_TRUE(writer_.Init(op_.dst_extents(), kBlockSize));
+ ASSERT_TRUE(writer_.Write(zeros->data(), 9 * kBlockSize));
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_consumer/xz_extent_writer.cc b/payload_consumer/xz_extent_writer.cc
index a6483519..361e6353 100644
--- a/payload_consumer/xz_extent_writer.cc
+++ b/payload_consumer/xz_extent_writer.cc
@@ -53,13 +53,13 @@ const char* XzErrorString(enum xz_ret error) {
} // namespace
XzExtentWriter::~XzExtentWriter() {
- xz_dec_end(stream_);
+ stream_.reset();
TEST_AND_RETURN(input_buffer_.empty());
}
bool XzExtentWriter::Init(const RepeatedPtrField<Extent>& extents,
uint32_t block_size) {
- stream_ = xz_dec_init(XZ_DYNALLOC, kXzMaxDictSize);
+ stream_.reset(xz_dec_init(XZ_DYNALLOC, kXzMaxDictSize));
TEST_AND_RETURN_FALSE(stream_ != nullptr);
return underlying_writer_->Init(extents, block_size);
}
@@ -86,7 +86,7 @@ bool XzExtentWriter::Write(const void* bytes, size_t count) {
for (;;) {
request.out_pos = 0;
- xz_ret ret = xz_dec_run(stream_, &request);
+ xz_ret ret = xz_dec_run(stream_.get(), &request);
if (ret != XZ_OK && ret != XZ_STREAM_END) {
LOG(ERROR) << "xz_dec_run returned " << XzErrorString(ret);
return false;
diff --git a/payload_consumer/xz_extent_writer.h b/payload_consumer/xz_extent_writer.h
index 70338f20..caf34ec8 100644
--- a/payload_consumer/xz_extent_writer.h
+++ b/payload_consumer/xz_extent_writer.h
@@ -34,6 +34,10 @@
namespace chromeos_update_engine {
class XzExtentWriter : public ExtentWriter {
+ struct xz_deleter {
+ constexpr void operator()(xz_dec* p) { xz_dec_end(p); }
+ };
+
public:
explicit XzExtentWriter(std::unique_ptr<ExtentWriter> underlying_writer)
: underlying_writer_(std::move(underlying_writer)) {}
@@ -47,7 +51,7 @@ class XzExtentWriter : public ExtentWriter {
// The underlying ExtentWriter.
std::unique_ptr<ExtentWriter> underlying_writer_;
// The opaque xz decompressor struct.
- xz_dec* stream_{nullptr};
+ std::unique_ptr<xz_dec, xz_deleter> stream_{nullptr};
brillo::Blob input_buffer_;
DISALLOW_COPY_AND_ASSIGN(XzExtentWriter);
diff --git a/payload_generator/ab_generator.cc b/payload_generator/ab_generator.cc
index d9b9d885..25cafe34 100644
--- a/payload_generator/ab_generator.cc
+++ b/payload_generator/ab_generator.cc
@@ -54,7 +54,7 @@ bool ABGenerator::GenerateOperations(const PayloadGenerationConfig& config,
new_part,
hard_chunk_blocks,
soft_chunk_blocks,
- config.version,
+ config,
blob_file));
LOG(INFO) << "done reading " << new_part.name;
diff --git a/payload_generator/annotated_operation.h b/payload_generator/annotated_operation.h
index 653bab0f..c57f249a 100644
--- a/payload_generator/annotated_operation.h
+++ b/payload_generator/annotated_operation.h
@@ -19,6 +19,7 @@
#include <ostream> // NOLINT(readability/streams)
#include <string>
+#include <vector>
#include <brillo/secure_blob.h>
@@ -35,6 +36,11 @@ struct AnnotatedOperation {
// The InstallOperation, as defined by the protobuf.
InstallOperation op;
+ // Array of blocks which should be converted to XOR during OTA install.
+ // All elements in this array should have |merge_op.type() == COW_XOR|.
+ // This information is typically derived from BSDIFF patch data.
+ std::vector<CowMergeOperation> xor_ops;
+
// Writes |blob| to the end of |blob_file|. It sets the data_offset and
// data_length in AnnotatedOperation to match the offset and size of |blob|
// in |blob_file|.
diff --git a/payload_generator/boot_img_filesystem.cc b/payload_generator/boot_img_filesystem.cc
index 89b175ec..cad267ec 100644
--- a/payload_generator/boot_img_filesystem.cc
+++ b/payload_generator/boot_img_filesystem.cc
@@ -57,7 +57,7 @@ unique_ptr<BootImgFilesystem> BootImgFilesystem::CreateFromFile(
}
uint32_t header_version =
*reinterpret_cast<uint32_t*>(header_version_blob.data());
- if (header_version > 3) {
+ if (header_version > 4) {
LOG(WARNING) << "Boot image header version " << header_version
<< " isn't supported for parsing";
return nullptr;
@@ -80,13 +80,22 @@ unique_ptr<BootImgFilesystem> BootImgFilesystem::CreateFromFile(
result->kernel_size_ = hdr_v0->kernel_size;
result->ramdisk_size_ = hdr_v0->ramdisk_size;
result->page_size_ = hdr_v0->page_size;
- } else {
+ } else if (header_version == 3) {
auto hdr_v3 = reinterpret_cast<boot_img_hdr_v3*>(header_blob.data());
CHECK_EQ(0, memcmp(hdr_v3->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE));
CHECK_EQ(3u, hdr_v3->header_version);
result->kernel_size_ = hdr_v3->kernel_size;
result->ramdisk_size_ = hdr_v3->ramdisk_size;
result->page_size_ = 4096;
+ } else {
+ auto hdr_v4 = reinterpret_cast<boot_img_hdr_v4*>(header_blob.data());
+ CHECK_EQ(0, memcmp(hdr_v4->magic, BOOT_MAGIC, BOOT_MAGIC_SIZE));
+ CHECK_EQ(hdr_v4->header_version, 4u);
+ result->kernel_size_ = hdr_v4->kernel_size;
+ result->ramdisk_size_ = hdr_v4->ramdisk_size;
+ // In boot image v3 and v4, page size is hard coded as 4096
+ result->page_size_ = 4096;
+ result->signature_size_ = hdr_v4->signature_size;
}
CHECK_GT(result->page_size_, 0u);
@@ -141,6 +150,10 @@ bool BootImgFilesystem::GetFiles(vector<File>* files) const {
if (ramdisk_size_ > 0 && offset + ramdisk_size_ <= file_size) {
files->emplace_back(GetFile("<ramdisk>", offset, ramdisk_size_));
}
+ offset += utils::RoundUp(ramdisk_size_, page_size_);
+ if (signature_size_ > 0) {
+ files->emplace_back(GetFile("<boot signature>", offset, signature_size_));
+ }
return true;
}
diff --git a/payload_generator/boot_img_filesystem.h b/payload_generator/boot_img_filesystem.h
index 61f755c4..7773461f 100644
--- a/payload_generator/boot_img_filesystem.h
+++ b/payload_generator/boot_img_filesystem.h
@@ -52,9 +52,10 @@ class BootImgFilesystem : public FilesystemInterface {
// The boot.img file path.
std::string filename_;
- uint32_t kernel_size_; /* size in bytes */
- uint32_t ramdisk_size_; /* size in bytes */
- uint32_t page_size_; /* flash page size we assume */
+ uint32_t kernel_size_ = 0; /* size in bytes */
+ uint32_t ramdisk_size_ = 0; /* size in bytes */
+ uint32_t signature_size_ = 0; /* size in bytes */
+ uint32_t page_size_ = 4096; /* flash page size we assume */
DISALLOW_COPY_AND_ASSIGN(BootImgFilesystem);
};
diff --git a/payload_generator/cow_size_estimator.cc b/payload_generator/cow_size_estimator.cc
index 01e99653..3a23f444 100644
--- a/payload_generator/cow_size_estimator.cc
+++ b/payload_generator/cow_size_estimator.cc
@@ -16,6 +16,8 @@
#include "update_engine/payload_generator/cow_size_estimator.h"
+#include <algorithm>
+#include <functional>
#include <string>
#include <utility>
#include <vector>
@@ -25,143 +27,139 @@
#include "update_engine/common/cow_operation_convert.h"
#include "update_engine/common/utils.h"
+#include "update_engine/payload_consumer/vabc_partition_writer.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
using android::snapshot::CowWriter;
-namespace {
-bool PerformReplaceOp(const InstallOperation& op,
- CowWriter* writer,
- FileDescriptorPtr target_fd,
- size_t block_size) {
- std::vector<unsigned char> buffer;
- for (const auto& extent : op.dst_extents()) {
- buffer.resize(extent.num_blocks() * block_size);
- // No need to read from payload.bin then decompress, just read from target
- // directly.
- ssize_t bytes_read = 0;
- auto success = utils::ReadAll(target_fd,
- buffer.data(),
- buffer.size(),
- extent.start_block() * block_size,
- &bytes_read);
- TEST_AND_RETURN_FALSE(success);
- CHECK_EQ(static_cast<size_t>(bytes_read), buffer.size());
- TEST_AND_RETURN_FALSE(writer->AddRawBlocks(
- extent.start_block(), buffer.data(), buffer.size()));
+bool CowDryRun(
+ FileDescriptorPtr source_fd,
+ FileDescriptorPtr target_fd,
+ const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
+ const google::protobuf::RepeatedPtrField<CowMergeOperation>&
+ merge_operations,
+ const size_t block_size,
+ android::snapshot::CowWriter* cow_writer,
+ const size_t partition_size,
+ const bool xor_enabled) {
+ CHECK_NE(target_fd, nullptr);
+ CHECK(target_fd->IsOpen());
+ VABCPartitionWriter::WriteMergeSequence(merge_operations, cow_writer);
+ ExtentRanges visited;
+ for (const auto& op : merge_operations) {
+ if (op.type() == CowMergeOperation::COW_COPY) {
+ visited.AddExtent(op.dst_extent());
+ for (size_t i = 0; i < op.dst_extent().num_blocks(); i++) {
+ cow_writer->AddCopy(op.dst_extent().start_block() + i,
+ op.src_extent().start_block() + i);
+ }
+ } else if (op.type() == CowMergeOperation::COW_XOR && xor_enabled) {
+ CHECK_NE(source_fd, nullptr) << "Source fd is required to enable XOR ops";
+ CHECK(source_fd->IsOpen());
+ visited.AddExtent(op.dst_extent());
+ // dst block count is used, because
+ // src block count is probably(if src_offset > 0) 1 block
+ // larger than dst extent. Using it might lead to intreseting out of bound
+ // disk reads.
+ std::vector<unsigned char> old_data(op.dst_extent().num_blocks() *
+ block_size);
+ ssize_t bytes_read = 0;
+ if (!utils::PReadAll(
+ source_fd,
+ old_data.data(),
+ old_data.size(),
+ op.src_extent().start_block() * block_size + op.src_offset(),
+ &bytes_read)) {
+ PLOG(ERROR) << "Failed to read source data at " << op.src_extent();
+ return false;
+ }
+ std::vector<unsigned char> new_data(op.dst_extent().num_blocks() *
+ block_size);
+ if (!utils::PReadAll(target_fd,
+ new_data.data(),
+ new_data.size(),
+ op.dst_extent().start_block() * block_size,
+ &bytes_read)) {
+ PLOG(ERROR) << "Failed to read target data at " << op.dst_extent();
+ return false;
+ }
+ CHECK_GT(old_data.size(), 0UL);
+ CHECK_GT(new_data.size(), 0UL);
+ std::transform(new_data.begin(),
+ new_data.end(),
+ old_data.begin(),
+ new_data.begin(),
+ std::bit_xor<unsigned char>{});
+ CHECK(cow_writer->AddXorBlocks(op.dst_extent().start_block(),
+ new_data.data(),
+ new_data.size(),
+ op.src_extent().start_block(),
+ op.src_offset()));
+ }
+ // The value of label doesn't really matter, we just want to write some
+ // labels to simulate bahvior of update_engine. As update_engine writes
+ // labels every once a while when installing OTA, it's important that we do
+ // the same to get accurate size estimation.
+ cow_writer->AddLabel(0);
}
- return true;
-}
-
-bool PerformZeroOp(const InstallOperation& op,
- CowWriter* writer,
- size_t block_size) {
- for (const auto& extent : op.dst_extents()) {
- TEST_AND_RETURN_FALSE(
- writer->AddZeroBlocks(extent.start_block(), extent.num_blocks()));
+ for (const auto& op : operations) {
+ if (op.type() == InstallOperation::ZERO) {
+ for (const auto& ext : op.dst_extents()) {
+ visited.AddExtent(ext);
+ cow_writer->AddZeroBlocks(ext.start_block(), ext.num_blocks());
+ }
+ cow_writer->AddLabel(0);
+ }
}
- return true;
-}
-
-bool WriteAllCowOps(size_t block_size,
- const std::vector<CowOperation>& converted,
- android::snapshot::ICowWriter* cow_writer,
- FileDescriptorPtr target_fd) {
- std::vector<uint8_t> buffer(block_size);
-
- for (const auto& cow_op : converted) {
- switch (cow_op.op) {
- case CowOperation::CowCopy:
- if (cow_op.src_block == cow_op.dst_block) {
- continue;
- }
- TEST_AND_RETURN_FALSE(
- cow_writer->AddCopy(cow_op.dst_block, cow_op.src_block));
- break;
- case CowOperation::CowReplace:
- ssize_t bytes_read = 0;
- TEST_AND_RETURN_FALSE(chromeos_update_engine::utils::ReadAll(
- target_fd,
- buffer.data(),
- block_size,
- cow_op.dst_block * block_size,
- &bytes_read));
- if (bytes_read <= 0 || static_cast<size_t>(bytes_read) != block_size) {
- LOG(ERROR) << "source_fd->Read failed: " << bytes_read;
- return false;
- }
- TEST_AND_RETURN_FALSE(cow_writer->AddRawBlocks(
- cow_op.dst_block, buffer.data(), block_size));
- break;
+ const size_t last_block = partition_size / block_size;
+ const auto unvisited_extents =
+ FilterExtentRanges({ExtentForRange(0, last_block)}, visited);
+ for (const auto& ext : unvisited_extents) {
+ std::vector<unsigned char> data(ext.num_blocks() * block_size);
+ ssize_t bytes_read = 0;
+ if (!utils::PReadAll(target_fd,
+ data.data(),
+ data.size(),
+ ext.start_block() * block_size,
+ &bytes_read)) {
+ PLOG(ERROR) << "Failed to read new block data at " << ext;
+ return false;
}
+ cow_writer->AddRawBlocks(ext.start_block(), data.data(), data.size());
+ cow_writer->AddLabel(0);
}
- return true;
+ return cow_writer->Finalize();
}
-} // namespace
size_t EstimateCowSize(
+ FileDescriptorPtr source_fd,
FileDescriptorPtr target_fd,
const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
const google::protobuf::RepeatedPtrField<CowMergeOperation>&
merge_operations,
- size_t block_size,
- std::string compression) {
+ const size_t block_size,
+ std::string compression,
+ const size_t partition_size,
+ const bool xor_enabled) {
android::snapshot::CowWriter cow_writer{
{.block_size = static_cast<uint32_t>(block_size),
.compression = std::move(compression)}};
// CowWriter treats -1 as special value, will discard all the data but still
// reports Cow size. Good for estimation purposes
cow_writer.Initialize(android::base::borrowed_fd{-1});
- CHECK(CowDryRun(
- target_fd, operations, merge_operations, block_size, &cow_writer));
- CHECK(cow_writer.Finalize());
+ CHECK(CowDryRun(source_fd,
+ target_fd,
+ operations,
+ merge_operations,
+ block_size,
+ &cow_writer,
+ partition_size,
+ xor_enabled));
return cow_writer.GetCowSize();
}
-bool CowDryRun(
- FileDescriptorPtr target_fd,
- const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
- const google::protobuf::RepeatedPtrField<CowMergeOperation>&
- merge_operations,
- size_t block_size,
- android::snapshot::CowWriter* cow_writer) {
- const auto converted = ConvertToCowOperations(operations, merge_operations);
- WriteAllCowOps(block_size, converted, cow_writer, target_fd);
- cow_writer->AddLabel(0);
- for (const auto& op : operations) {
- switch (op.type()) {
- case InstallOperation::REPLACE:
- case InstallOperation::REPLACE_BZ:
- case InstallOperation::REPLACE_XZ:
- TEST_AND_RETURN_FALSE(
- PerformReplaceOp(op, cow_writer, target_fd, block_size));
- break;
- case InstallOperation::ZERO:
- case InstallOperation::DISCARD:
- TEST_AND_RETURN_FALSE(PerformZeroOp(op, cow_writer, block_size));
- break;
- case InstallOperation::SOURCE_COPY:
- case InstallOperation::MOVE:
- // Already handeled by WriteAllCowOps,
- break;
- case InstallOperation::SOURCE_BSDIFF:
- case InstallOperation::BROTLI_BSDIFF:
- case InstallOperation::PUFFDIFF:
- case InstallOperation::BSDIFF:
- // We might do something special by adding CowBsdiff to CowWriter.
- // For now proceed the same way as normal REPLACE operation.
- TEST_AND_RETURN_FALSE(
- PerformReplaceOp(op, cow_writer, target_fd, block_size));
- break;
- }
- // Arbitrary label number, we won't be resuming use these labels here.
- // They are emitted just to keep size estimates accurate. As update_engine
- // emits 1 label for every op.
- cow_writer->AddLabel(2);
- }
- // TODO(zhangkelvin) Take FEC extents into account once VABC stabilizes
- return true;
-}
} // namespace chromeos_update_engine
diff --git a/payload_generator/cow_size_estimator.h b/payload_generator/cow_size_estimator.h
index 850c8909..c0209d97 100644
--- a/payload_generator/cow_size_estimator.h
+++ b/payload_generator/cow_size_estimator.h
@@ -27,21 +27,28 @@ namespace chromeos_update_engine {
// Virtual AB Compression enabled device. This is intended to be used by update
// generators to put an estimate cow size in OTA payload. When installing an OTA
// update, libsnapshot will take this estimate as a hint to allocate spaces.
+// If |xor_enabled| is true, then |source_fd| must be non-null.
size_t EstimateCowSize(
+ FileDescriptorPtr source_fd,
FileDescriptorPtr target_fd,
const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
const google::protobuf::RepeatedPtrField<CowMergeOperation>&
merge_operations,
- size_t block_size,
- std::string compression);
+ const size_t block_size,
+ std::string compression,
+ const size_t partition_size,
+ bool xor_enabled);
// Convert InstallOps to CowOps and apply the converted cow op to |cow_writer|
bool CowDryRun(
+ FileDescriptorPtr source_fd,
FileDescriptorPtr target_fd,
const google::protobuf::RepeatedPtrField<InstallOperation>& operations,
const google::protobuf::RepeatedPtrField<CowMergeOperation>&
merge_operations,
size_t block_size,
- android::snapshot::CowWriter* cow_writer);
+ android::snapshot::CowWriter* cow_writer,
+ size_t partition_size,
+ bool xor_enabled);
} // namespace chromeos_update_engine
diff --git a/payload_generator/deflate_utils.cc b/payload_generator/deflate_utils.cc
index c874bfd2..30e3f67a 100644
--- a/payload_generator/deflate_utils.cc
+++ b/payload_generator/deflate_utils.cc
@@ -113,15 +113,25 @@ bool IsBitExtentInExtent(const Extent& extent, const BitExtent& bit_extent) {
// Returns whether the given file |name| has an extension listed in
// |extensions|.
-bool IsFileExtensions(const string& name,
- const std::initializer_list<string>& extensions) {
- return any_of(extensions.begin(), extensions.end(), [&name](const auto& ext) {
- return base::EndsWith(name, ext, base::CompareCase::INSENSITIVE_ASCII);
- });
-}
} // namespace
+constexpr base::StringPiece ToStringPiece(std::string_view s) {
+ return base::StringPiece(s.data(), s.length());
+}
+
+bool IsFileExtensions(
+ const std::string_view name,
+ const std::initializer_list<std::string_view>& extensions) {
+ return any_of(extensions.begin(),
+ extensions.end(),
+ [name = ToStringPiece(name)](const auto& ext) {
+ return base::EndsWith(name,
+ ToStringPiece(ext),
+ base::CompareCase::INSENSITIVE_ASCII);
+ });
+}
+
ByteExtent ExpandToByteExtent(const BitExtent& extent) {
uint64_t offset = extent.offset / 8;
uint64_t length = ((extent.offset + extent.length + 7) / 8) - offset;
@@ -179,8 +189,8 @@ bool ShiftBitExtentsOverExtents(const vector<Extent>& base_extents,
// This check is needed to make sure the number of bytes in |over_extents|
// does not exceed |base_extents|.
auto last_extent = ExpandToByteExtent(over_extents->back());
- TEST_AND_RETURN_FALSE(last_extent.offset + last_extent.length <=
- utils::BlocksInExtents(base_extents) * kBlockSize);
+ TEST_LE(last_extent.offset + last_extent.length,
+ utils::BlocksInExtents(base_extents) * kBlockSize);
for (auto o_ext = over_extents->begin(); o_ext != over_extents->end();) {
size_t gap_blocks = base_extents[0].start_block();
@@ -265,6 +275,28 @@ bool FindAndCompactDeflates(const vector<Extent>& extents,
return true;
}
+bool DeflatePreprocessFileData(const std::string_view filename,
+ const brillo::Blob& data,
+ vector<puffin::BitExtent>* deflates) {
+ bool is_zip = IsFileExtensions(
+ filename, {".apk", ".zip", ".jar", ".zvoice", ".apex", "capex"});
+ bool is_gzip = IsFileExtensions(filename, {".gz", ".gzip", ".tgz"});
+ if (is_zip) {
+ if (!puffin::LocateDeflatesInZipArchive(data, deflates)) {
+ LOG(ERROR) << "Failed to locate deflates in zip file " << filename;
+ deflates->clear();
+ return false;
+ }
+ } else if (is_gzip) {
+ if (!puffin::LocateDeflatesInGzip(data, deflates)) {
+ LOG(ERROR) << "Failed to locate deflates in gzip file " << filename;
+ deflates->clear();
+ return false;
+ }
+ }
+ return true;
+}
+
bool PreprocessPartitionFiles(const PartitionConfig& part,
vector<FilesystemInterface::File>* result_files,
bool extract_deflates) {
@@ -312,7 +344,7 @@ bool PreprocessPartitionFiles(const PartitionConfig& part,
// .zvoice files may eventually move out of rootfs. If that happens,
// remove ".zvoice" (crbug.com/782918).
bool is_zip = IsFileExtensions(
- file.name, {".apk", ".zip", ".jar", ".zvoice", ".apex"});
+ file.name, {".apk", ".zip", ".jar", ".zvoice", ".apex", "capex"});
bool is_gzip = IsFileExtensions(file.name, {".gz", ".gzip", ".tgz"});
if (is_zip || is_gzip) {
brillo::Blob data;
@@ -322,12 +354,18 @@ bool PreprocessPartitionFiles(const PartitionConfig& part,
&data,
kBlockSize * utils::BlocksInExtents(file.extents),
kBlockSize));
+ // |data| read from disk always has size multiple of kBlockSize. So it
+ // might contain trailing garbage data and confuse the gzip/zip
+ // processors. Trim them.
+ if (file.file_stat.st_size > 0 &&
+ static_cast<size_t>(file.file_stat.st_size) < data.size()) {
+ data.resize(file.file_stat.st_size);
+ }
vector<puffin::BitExtent> deflates;
- if (is_zip) {
- TEST_AND_RETURN_FALSE(
- puffin::LocateDeflatesInZipArchive(data, &deflates));
- } else if (is_gzip) {
- TEST_AND_RETURN_FALSE(puffin::LocateDeflatesInGzip(data, &deflates));
+ if (!DeflatePreprocessFileData(file.name, data, &deflates)) {
+ LOG(ERROR) << "Failed to preprocess deflate data in partition "
+ << part.name;
+ return false;
}
// Shift the deflate's extent to the offset starting from the beginning
// of the current partition; and the delta processor will align the
diff --git a/payload_generator/deflate_utils.h b/payload_generator/deflate_utils.h
index 752bd9f4..517fc4eb 100644
--- a/payload_generator/deflate_utils.h
+++ b/payload_generator/deflate_utils.h
@@ -17,9 +17,11 @@
#ifndef UPDATE_ENGINE_PAYLOAD_GENERATOR_DEFLATE_UTILS_H_
#define UPDATE_ENGINE_PAYLOAD_GENERATOR_DEFLATE_UTILS_H_
-#include <puffin/puffdiff.h>
+#include <string>
#include <vector>
+#include <puffin/puffdiff.h>
+
#include "update_engine/payload_generator/filesystem_interface.h"
#include "update_engine/payload_generator/payload_generation_config.h"
@@ -93,6 +95,14 @@ bool FindAndCompactDeflates(const std::vector<Extent>& extents,
// Expands a BitExtents to a ByteExtent.
puffin::ByteExtent ExpandToByteExtent(const puffin::BitExtent& extent);
+bool IsFileExtensions(
+ const std::string_view name,
+ const std::initializer_list<std::string_view>& extensions);
+
+bool DeflatePreprocessFileData(const std::string_view filename,
+ const brillo::Blob& data,
+ std::vector<puffin::BitExtent>* deflates);
+
} // namespace deflate_utils
} // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_PAYLOAD_GENERATOR_DEFLATE_UTILS_H_
diff --git a/payload_generator/delta_diff_generator.cc b/payload_generator/delta_diff_generator.cc
index ab0f0364..46dfb0fa 100644
--- a/payload_generator/delta_diff_generator.cc
+++ b/payload_generator/delta_diff_generator.cc
@@ -53,7 +53,6 @@ namespace chromeos_update_engine {
// bytes
const size_t kRootFSPartitionSize = static_cast<size_t>(2) * 1024 * 1024 * 1024;
-const size_t kBlockSize = 4096; // bytes
class PartitionProcessor : public base::DelegateSimpleThread::Delegate {
bool IsDynamicPartition(const std::string& partition_name) {
@@ -120,9 +119,6 @@ class PartitionProcessor : public base::DelegateSimpleThread::Delegate {
LOG(INFO) << "Estimating COW size for partition: " << new_part_.name;
// Need the contents of source/target image bytes when doing
// dry run.
- FileDescriptorPtr source_fd{new EintrSafeFileDescriptor()};
- source_fd->Open(old_part_.path.c_str(), O_RDONLY);
-
auto target_fd = std::make_unique<EintrSafeFileDescriptor>();
target_fd->Open(new_part_.path.c_str(), O_RDONLY);
@@ -131,18 +127,22 @@ class PartitionProcessor : public base::DelegateSimpleThread::Delegate {
for (const AnnotatedOperation& aop : *aops_) {
*operations.Add() = aop.op;
}
+
+ FileDescriptorPtr source_fd = nullptr;
+ if (config_.enable_vabc_xor) {
+ source_fd = std::make_shared<EintrSafeFileDescriptor>();
+ source_fd->Open(old_part_.path.c_str(), O_RDONLY);
+ }
+
*cow_size_ = EstimateCowSize(
+ std::move(source_fd),
std::move(target_fd),
std::move(operations),
{cow_merge_sequence_->begin(), cow_merge_sequence_->end()},
config_.block_size,
- config_.target.dynamic_partition_metadata->vabc_compression_param());
- if (!new_part_.disable_fec_computation) {
- *cow_size_ +=
- new_part_.verity.fec_extent.num_blocks() * config_.block_size;
- }
- *cow_size_ +=
- new_part_.verity.hash_tree_extent.num_blocks() * config_.block_size;
+ config_.target.dynamic_partition_metadata->vabc_compression_param(),
+ new_part_.size,
+ config_.enable_vabc_xor);
LOG(INFO) << "Estimated COW size for partition: " << new_part_.name << " "
<< *cow_size_;
}
diff --git a/payload_generator/delta_diff_generator.h b/payload_generator/delta_diff_generator.h
index 8323f479..2ffca38e 100644
--- a/payload_generator/delta_diff_generator.h
+++ b/payload_generator/delta_diff_generator.h
@@ -23,7 +23,8 @@
namespace chromeos_update_engine {
-extern const size_t kBlockSize;
+constexpr size_t kBlockSize = 4096;
+
extern const size_t kRootFSPartitionSize;
// The |config| describes the payload generation request, describing both
diff --git a/payload_generator/delta_diff_utils.cc b/payload_generator/delta_diff_utils.cc
index 3c025e10..389cf977 100644
--- a/payload_generator/delta_diff_utils.cc
+++ b/payload_generator/delta_diff_utils.cc
@@ -17,6 +17,7 @@
#include "update_engine/payload_generator/delta_diff_utils.h"
#include <endian.h>
+#include <sys/user.h>
#if defined(__clang__)
// TODO(*): Remove these pragmas when b/35721782 is fixed.
#pragma clang diagnostic push
@@ -30,22 +31,30 @@
#include <algorithm>
#include <functional>
+#include <limits>
#include <list>
#include <map>
#include <memory>
#include <numeric>
#include <utility>
+#include <vector>
#include <base/files/file_util.h>
#include <base/format_macros.h>
#include <base/strings/string_util.h>
#include <base/strings/stringprintf.h>
#include <base/threading/simple_thread.h>
-#include <base/time/time.h>
#include <brillo/data_encoding.h>
#include <bsdiff/bsdiff.h>
+#include <bsdiff/constants.h>
+#include <bsdiff/control_entry.h>
+#include <bsdiff/patch_reader.h>
#include <bsdiff/patch_writer_factory.h>
+#include <puffin/brotli_util.h>
#include <puffin/utils.h>
+#include <zucchini/buffer_view.h>
+#include <zucchini/patch_writer.h>
+#include <zucchini/zucchini.h>
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/subprocess.h"
@@ -58,8 +67,10 @@
#include "update_engine/payload_generator/delta_diff_generator.h"
#include "update_engine/payload_generator/extent_ranges.h"
#include "update_engine/payload_generator/extent_utils.h"
+#include "update_engine/payload_generator/merge_sequence_generator.h"
#include "update_engine/payload_generator/squashfs_filesystem.h"
#include "update_engine/payload_generator/xz.h"
+#include "update_engine/lz4diff/lz4diff.h"
using std::list;
using std::map;
@@ -81,6 +92,10 @@ const uint64_t kMaxBsdiffDestinationSize = 200 * 1024 * 1024; // bytes
// memory intensive, so we limit these operations to 150 MiB.
const uint64_t kMaxPuffdiffDestinationSize = 150 * 1024 * 1024; // bytes
+// The maximum destination size allowed for zucchini. We are conservative here
+// as zucchini tends to use more peak memory.
+const uint64_t kMaxZucchiniDestinationSize = 150 * 1024 * 1024; // bytes
+
const int kBrotliCompressionQuality = 11;
// Storing a diff operation has more overhead over replace operation in the
@@ -131,9 +146,252 @@ int LevenshteinDistance(const string& a, const string& b) {
}
return distances.back();
}
+
+static bool ShouldCreateNewOp(const std::vector<CowMergeOperation>& ops,
+ size_t src_block,
+ size_t dst_block,
+ size_t src_offset) {
+ if (ops.empty()) {
+ return true;
+ }
+ const auto& op = ops.back();
+ if (op.src_offset() != src_offset) {
+ return true;
+ }
+ const auto& src_extent = op.src_extent();
+ const auto& dst_extent = op.dst_extent();
+ return src_extent.start_block() + src_extent.num_blocks() != src_block ||
+ dst_extent.start_block() + dst_extent.num_blocks() != dst_block;
+}
+
+void AppendXorBlock(std::vector<CowMergeOperation>* ops,
+ size_t src_block,
+ size_t dst_block,
+ size_t src_offset) {
+ if (!ops->empty() && ExtentContains(ops->back().dst_extent(), dst_block)) {
+ return;
+ }
+ CHECK_NE(src_block, std::numeric_limits<uint64_t>::max());
+ CHECK_NE(dst_block, std::numeric_limits<uint64_t>::max());
+ if (ShouldCreateNewOp(*ops, src_block, dst_block, src_offset)) {
+ auto& op = ops->emplace_back();
+ op.mutable_src_extent()->set_start_block(src_block);
+ op.mutable_src_extent()->set_num_blocks(1);
+ op.mutable_dst_extent()->set_start_block(dst_block);
+ op.mutable_dst_extent()->set_num_blocks(1);
+ op.set_src_offset(src_offset);
+ op.set_type(CowMergeOperation::COW_XOR);
+ } else {
+ auto& op = ops->back();
+ auto& src_extent = *op.mutable_src_extent();
+ auto& dst_extent = *op.mutable_dst_extent();
+ src_extent.set_num_blocks(src_extent.num_blocks() + 1);
+ dst_extent.set_num_blocks(dst_extent.num_blocks() + 1);
+ }
+}
+
} // namespace
namespace diff_utils {
+bool BestDiffGenerator::GenerateBestDiffOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ std::vector<std::pair<InstallOperation_Type, size_t>> diff_candidates = {
+ {InstallOperation::SOURCE_BSDIFF, kMaxBsdiffDestinationSize},
+ {InstallOperation::PUFFDIFF, kMaxPuffdiffDestinationSize},
+ {InstallOperation::ZUCCHINI, kMaxZucchiniDestinationSize},
+ };
+
+ return GenerateBestDiffOperation(diff_candidates, aop, data_blob);
+}
+
+std::vector<bsdiff::CompressorType>
+BestDiffGenerator::GetUsableCompressorTypes() const {
+ return config_.compressors;
+}
+
+bool BestDiffGenerator::GenerateBestDiffOperation(
+ const std::vector<std::pair<InstallOperation_Type, size_t>>&
+ diff_candidates,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ CHECK(aop);
+ CHECK(data_blob);
+ if (!old_block_info_.blocks.empty() && !new_block_info_.blocks.empty() &&
+ config_.OperationEnabled(InstallOperation::LZ4DIFF_BSDIFF) &&
+ config_.OperationEnabled(InstallOperation::LZ4DIFF_PUFFDIFF)) {
+ brillo::Blob patch;
+ InstallOperation::Type op_type;
+ if (Lz4Diff(old_data_,
+ new_data_,
+ old_block_info_,
+ new_block_info_,
+ &patch,
+ &op_type)) {
+ aop->op.set_type(op_type);
+ // LZ4DIFF is likely significantly better than BSDIFF/PUFFDIFF when
+ // working with EROFS. So no need to even try other diffing algorithms.
+ *data_blob = std::move(patch);
+ return true;
+ }
+ }
+
+ const uint64_t input_bytes = std::max(utils::BlocksInExtents(src_extents_),
+ utils::BlocksInExtents(dst_extents_)) *
+ kBlockSize;
+
+ for (auto [op_type, limit] : diff_candidates) {
+ if (!config_.OperationEnabled(op_type)) {
+ continue;
+ }
+
+ // Disable the specific diff algorithm when the data is too big.
+ if (input_bytes > limit) {
+ LOG(INFO) << op_type << " ignored, file " << aop->name
+ << " too big: " << input_bytes << " bytes";
+ continue;
+ }
+
+ // Prefer BROTLI_BSDIFF as it gives smaller patch size.
+ if (op_type == InstallOperation::SOURCE_BSDIFF &&
+ config_.OperationEnabled(InstallOperation::BROTLI_BSDIFF)) {
+ op_type = InstallOperation::BROTLI_BSDIFF;
+ }
+
+ switch (op_type) {
+ case InstallOperation::SOURCE_BSDIFF:
+ case InstallOperation::BROTLI_BSDIFF:
+ TEST_AND_RETURN_FALSE(
+ TryBsdiffAndUpdateOperation(op_type, aop, data_blob));
+ break;
+ case InstallOperation::PUFFDIFF:
+ TEST_AND_RETURN_FALSE(TryPuffdiffAndUpdateOperation(aop, data_blob));
+ break;
+ case InstallOperation::ZUCCHINI:
+ TEST_AND_RETURN_FALSE(TryZucchiniAndUpdateOperation(aop, data_blob));
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ return true;
+}
+
+bool BestDiffGenerator::TryBsdiffAndUpdateOperation(
+ InstallOperation_Type operation_type,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ base::FilePath patch;
+ TEST_AND_RETURN_FALSE(base::CreateTemporaryFile(&patch));
+ ScopedPathUnlinker unlinker(patch.value());
+
+ std::unique_ptr<bsdiff::PatchWriterInterface> bsdiff_patch_writer;
+ if (operation_type == InstallOperation::BROTLI_BSDIFF) {
+ bsdiff_patch_writer = bsdiff::CreateBSDF2PatchWriter(
+ patch.value(), GetUsableCompressorTypes(), kBrotliCompressionQuality);
+ } else {
+ bsdiff_patch_writer = bsdiff::CreateBsdiffPatchWriter(patch.value());
+ }
+
+ brillo::Blob bsdiff_delta;
+ TEST_AND_RETURN_FALSE(0 == bsdiff::bsdiff(old_data_.data(),
+ old_data_.size(),
+ new_data_.data(),
+ new_data_.size(),
+ bsdiff_patch_writer.get(),
+ nullptr));
+
+ TEST_AND_RETURN_FALSE(utils::ReadFile(patch.value(), &bsdiff_delta));
+ TEST_AND_RETURN_FALSE(!bsdiff_delta.empty());
+
+ InstallOperation& operation = aop->op;
+ if (IsDiffOperationBetter(operation,
+ data_blob->size(),
+ bsdiff_delta.size(),
+ src_extents_.size())) {
+ // VABC XOR won't work with compressed files just yet.
+ if (config_.enable_vabc_xor) {
+ StoreExtents(src_extents_, operation.mutable_src_extents());
+ diff_utils::PopulateXorOps(aop, bsdiff_delta);
+ }
+ operation.set_type(operation_type);
+ *data_blob = std::move(bsdiff_delta);
+ }
+ return true;
+}
+
+bool BestDiffGenerator::TryPuffdiffAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ // Only Puffdiff if both files have at least one deflate left.
+ if (!old_deflates_.empty() && !new_deflates_.empty()) {
+ brillo::Blob puffdiff_delta;
+ ScopedTempFile temp_file("puffdiff-delta.XXXXXX");
+ // Perform PuffDiff operation.
+ TEST_AND_RETURN_FALSE(puffin::PuffDiff(old_data_,
+ new_data_,
+ old_deflates_,
+ new_deflates_,
+ GetUsableCompressorTypes(),
+ temp_file.path(),
+ &puffdiff_delta));
+ TEST_AND_RETURN_FALSE(!puffdiff_delta.empty());
+
+ InstallOperation& operation = aop->op;
+ if (IsDiffOperationBetter(operation,
+ data_blob->size(),
+ puffdiff_delta.size(),
+ src_extents_.size())) {
+ operation.set_type(InstallOperation::PUFFDIFF);
+ *data_blob = std::move(puffdiff_delta);
+ }
+ }
+ return true;
+}
+
+bool BestDiffGenerator::TryZucchiniAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob) {
+ // zip files are ignored for now. We expect puffin to perform better on those.
+ // Investigate whether puffin over zucchini yields better results on those.
+ if (!deflate_utils::IsFileExtensions(
+ aop->name,
+ {".ko",
+ ".so",
+ ".art",
+ ".odex",
+ ".vdex",
+ "<kernel>",
+ "<modem-partition>",
+ /*, ".capex",".jar", ".apk", ".apex"*/})) {
+ return true;
+ }
+ zucchini::ConstBufferView src_bytes(old_data_.data(), old_data_.size());
+ zucchini::ConstBufferView dst_bytes(new_data_.data(), new_data_.size());
+
+ zucchini::EnsemblePatchWriter patch_writer(src_bytes, dst_bytes);
+ auto status = zucchini::GenerateBuffer(src_bytes, dst_bytes, &patch_writer);
+ TEST_AND_RETURN_FALSE(status == zucchini::status::kStatusSuccess);
+
+ brillo::Blob zucchini_delta(patch_writer.SerializedSize());
+ patch_writer.SerializeInto({zucchini_delta.data(), zucchini_delta.size()});
+
+ // Compress the delta with brotli.
+ // TODO(197361113) support compressing the delta with different algorithms,
+ // similar to the usage in puffin.
+ brillo::Blob compressed_delta;
+ TEST_AND_RETURN_FALSE(puffin::BrotliEncode(
+ zucchini_delta.data(), zucchini_delta.size(), &compressed_delta));
+
+ InstallOperation& operation = aop->op;
+ if (IsDiffOperationBetter(operation,
+ data_blob->size(),
+ compressed_delta.size(),
+ src_extents_.size())) {
+ operation.set_type(InstallOperation::ZUCCHINI);
+ *data_blob = std::move(compressed_delta);
+ }
+
+ return true;
+}
// This class encapsulates a file delta processing thread work. The
// processor computes the delta between the source and target files;
@@ -142,22 +400,18 @@ class FileDeltaProcessor : public base::DelegateSimpleThread::Delegate {
public:
FileDeltaProcessor(const string& old_part,
const string& new_part,
- const PayloadVersion& version,
- const vector<Extent>& old_extents,
- const vector<Extent>& new_extents,
- const vector<puffin::BitExtent>& old_deflates,
- const vector<puffin::BitExtent>& new_deflates,
+ const PayloadGenerationConfig& config,
+ const File& old_extents,
+ const File& new_extents,
const string& name,
ssize_t chunk_blocks,
BlobFileWriter* blob_file)
: old_part_(old_part),
new_part_(new_part),
- version_(version),
+ config_(config),
old_extents_(old_extents),
new_extents_(new_extents),
- new_extents_blocks_(utils::BlocksInExtents(new_extents)),
- old_deflates_(old_deflates),
- new_deflates_(new_deflates),
+ new_extents_blocks_(utils::BlocksInExtents(new_extents.extents)),
name_(name),
chunk_blocks_(chunk_blocks),
blob_file_(blob_file) {}
@@ -179,14 +433,12 @@ class FileDeltaProcessor : public base::DelegateSimpleThread::Delegate {
private:
const string& old_part_; // NOLINT(runtime/member_string_references)
const string& new_part_; // NOLINT(runtime/member_string_references)
- const PayloadVersion& version_;
+ const PayloadGenerationConfig& config_;
// The block ranges of the old/new file within the src/tgt image
- const vector<Extent> old_extents_;
- const vector<Extent> new_extents_;
+ const File old_extents_;
+ const File new_extents_;
const size_t new_extents_blocks_;
- const vector<puffin::BitExtent> old_deflates_;
- const vector<puffin::BitExtent> new_deflates_;
const string name_;
// Block limit of one aop.
const ssize_t chunk_blocks_;
@@ -209,11 +461,8 @@ void FileDeltaProcessor::Run() {
new_part_,
old_extents_,
new_extents_,
- old_deflates_,
- new_deflates_,
- name_,
chunk_blocks_,
- version_,
+ config_,
blob_file_)) {
LOG(ERROR) << "Failed to generate delta for " << name_ << " ("
<< new_extents_blocks_ << " blocks)";
@@ -222,7 +471,7 @@ void FileDeltaProcessor::Run() {
}
if (!ABGenerator::FragmentOperations(
- version_, &file_aops_, new_part_, blob_file_)) {
+ config_.version, &file_aops_, new_part_, blob_file_)) {
LOG(ERROR) << "Failed to fragment operations for " << name_;
failed_ = true;
return;
@@ -235,7 +484,6 @@ void FileDeltaProcessor::Run() {
bool FileDeltaProcessor::MergeOperation(vector<AnnotatedOperation>* aops) {
if (failed_)
return false;
- aops->reserve(aops->size() + file_aops_.size());
std::move(file_aops_.begin(), file_aops_.end(), std::back_inserter(*aops));
return true;
}
@@ -268,13 +516,27 @@ FilesystemInterface::File GetOldFile(
return *old_file;
}
+std::vector<Extent> RemoveDuplicateBlocks(const std::vector<Extent>& extents) {
+ ExtentRanges extent_set;
+ std::vector<Extent> ret;
+ for (const auto& extent : extents) {
+ auto vec = FilterExtentRanges({extent}, extent_set);
+ ret.insert(ret.end(),
+ std::make_move_iterator(vec.begin()),
+ std::make_move_iterator(vec.end()));
+ extent_set.AddExtent(extent);
+ }
+ return ret;
+}
+
bool DeltaReadPartition(vector<AnnotatedOperation>* aops,
const PartitionConfig& old_part,
const PartitionConfig& new_part,
ssize_t hard_chunk_blocks,
size_t soft_chunk_blocks,
- const PayloadVersion& version,
+ const PayloadGenerationConfig& config,
BlobFileWriter* blob_file) {
+ const auto& version = config.version;
ExtentRanges old_visited_blocks;
ExtentRanges new_visited_blocks;
@@ -290,20 +552,40 @@ bool DeltaReadPartition(vector<AnnotatedOperation>* aops,
new_visited_blocks.AddExtent(new_part.verity.fec_extent);
}
+ const bool puffdiff_allowed =
+ config.OperationEnabled(InstallOperation::PUFFDIFF);
+
+ TEST_AND_RETURN_FALSE(new_part.fs_interface);
+ vector<FilesystemInterface::File> new_files;
+ TEST_AND_RETURN_FALSE(deflate_utils::PreprocessPartitionFiles(
+ new_part, &new_files, puffdiff_allowed));
+
ExtentRanges old_zero_blocks;
- TEST_AND_RETURN_FALSE(DeltaMovedAndZeroBlocks(aops,
- old_part.path,
- new_part.path,
- old_part.size / kBlockSize,
- new_part.size / kBlockSize,
- soft_chunk_blocks,
- version,
- blob_file,
- &old_visited_blocks,
- &new_visited_blocks,
- &old_zero_blocks));
-
- bool puffdiff_allowed = version.OperationAllowed(InstallOperation::PUFFDIFF);
+ // Prematurely removing moved blocks will render compression info useless.
+ // Even if a single block inside a 100MB file is filtered out, the entire
+ // 100MB file can't be decompressed. In this case we will fallback to BSDIFF,
+ // which performs much worse than LZ4diff. It's better to let LZ4DIFF perform
+ // decompression, and let underlying BSDIFF to take care of moved blocks.
+ // TODO(b/206729162) Implement block filtering with compression block info
+ const auto no_compressed_files =
+ std::all_of(new_files.begin(), new_files.end(), [](const File& a) {
+ return a.compressed_file_info.blocks.empty();
+ });
+ if (!config.OperationEnabled(InstallOperation::LZ4DIFF_BSDIFF) ||
+ no_compressed_files) {
+ TEST_AND_RETURN_FALSE(DeltaMovedAndZeroBlocks(aops,
+ old_part.path,
+ new_part.path,
+ old_part.size / kBlockSize,
+ new_part.size / kBlockSize,
+ soft_chunk_blocks,
+ config,
+ blob_file,
+ &old_visited_blocks,
+ &new_visited_blocks,
+ &old_zero_blocks));
+ }
+
map<string, FilesystemInterface::File> old_files_map;
if (old_part.fs_interface) {
vector<FilesystemInterface::File> old_files;
@@ -313,11 +595,6 @@ bool DeltaReadPartition(vector<AnnotatedOperation>* aops,
old_files_map[file.name] = file;
}
- TEST_AND_RETURN_FALSE(new_part.fs_interface);
- vector<FilesystemInterface::File> new_files;
- TEST_AND_RETURN_FALSE(deflate_utils::PreprocessPartitionFiles(
- new_part, &new_files, puffdiff_allowed));
-
list<FileDeltaProcessor> file_delta_processors;
// The processing is very straightforward here, we generate operations for
@@ -339,27 +616,32 @@ bool DeltaReadPartition(vector<AnnotatedOperation>* aops,
if (new_file_extents.empty())
continue;
- // We can't visit each dst image inode more than once, as that would
- // duplicate work. Here, we avoid visiting each source image inode
- // more than once. Technically, we could have multiple operations
- // that read the same blocks from the source image for diffing, but
- // we choose not to avoid complexity. Eventually we will move away
- // from using a graph/cycle detection/etc to generate diffs, and at that
- // time, it will be easy (non-complex) to have many operations read
- // from the same source blocks. At that time, this code can die. -adlr
FilesystemInterface::File old_file =
GetOldFile(old_files_map, new_file.name);
- auto old_file_extents =
- FilterExtentRanges(old_file.extents, old_zero_blocks);
- old_visited_blocks.AddExtents(old_file_extents);
-
+ old_visited_blocks.AddExtents(old_file.extents);
+
+ // TODO(b/177104308) Filtering |new_file_extents| might confuse puffdiff, as
+ // we might filterout extents with deflate streams. PUFFDIFF is written with
+ // that in mind, so it will try to adapt to the filtered extents.
+ // Correctness is intact, but might yield larger patch sizes. From what we
+ // experimented, this has little impact on OTA size. Meanwhile, XOR ops
+ // depend on this. So filter out duplicate blocks from new file.
+ // TODO(b/194237829) |old_file.extents| is used instead of the de-duped
+ // |old_file_extents|. This is because zucchini diffing algorithm works
+ // better when given the full source file.
+ // Current logic:
+ // 1. src extent is completely unfiltered. It may contain
+ // duplicate blocks across files, within files, it may contain zero blocks,
+ // etc.
+ // 2. dst extent is completely filtered, no duplicate blocks or zero blocks
+ // whatsoever.
+ auto filtered_new_file = new_file;
+ filtered_new_file.extents = RemoveDuplicateBlocks(new_file_extents);
file_delta_processors.emplace_back(old_part.path,
new_part.path,
- version,
- std::move(old_file_extents),
- std::move(new_file_extents),
- old_file.deflates,
- new_file.deflates,
+ config,
+ std::move(old_file),
+ std::move(filtered_new_file),
new_file.name, // operation name
hard_chunk_blocks,
blob_file);
@@ -382,17 +664,18 @@ bool DeltaReadPartition(vector<AnnotatedOperation>* aops,
// We use the soft_chunk_blocks limit for the <non-file-data> as we don't
// really know the structure of this data and we should not expect it to
// have redundancy between partitions.
- file_delta_processors.emplace_back(
- old_part.path,
- new_part.path,
- version,
- std::move(old_unvisited),
- std::move(new_unvisited),
- vector<puffin::BitExtent>{}, // old_deflates,
- vector<puffin::BitExtent>{}, // new_deflates
- "<non-file-data>", // operation name
- soft_chunk_blocks,
- blob_file);
+ File old_file;
+ old_file.extents = old_unvisited;
+ File new_file;
+ new_file.extents = RemoveDuplicateBlocks(new_unvisited);
+ file_delta_processors.emplace_back(old_part.path,
+ new_part.path,
+ config,
+ old_file,
+ new_file,
+ "<non-file-data>", // operation name
+ soft_chunk_blocks,
+ blob_file);
}
size_t max_threads = GetMaxThreads();
@@ -424,7 +707,7 @@ bool DeltaMovedAndZeroBlocks(vector<AnnotatedOperation>* aops,
size_t old_num_blocks,
size_t new_num_blocks,
ssize_t chunk_blocks,
- const PayloadVersion& version,
+ const PayloadGenerationConfig& config,
BlobFileWriter* blob_file,
ExtentRanges* old_visited_blocks,
ExtentRanges* new_visited_blocks,
@@ -494,7 +777,7 @@ bool DeltaMovedAndZeroBlocks(vector<AnnotatedOperation>* aops,
size_t num_ops = aops->size();
new_visited_blocks->AddExtents(new_zeros);
for (const Extent& extent : new_zeros) {
- if (version.OperationAllowed(InstallOperation::ZERO)) {
+ if (config.OperationEnabled(InstallOperation::ZERO)) {
for (uint64_t offset = 0; offset < extent.num_blocks();
offset += chunk_blocks) {
uint64_t num_blocks =
@@ -507,16 +790,17 @@ bool DeltaMovedAndZeroBlocks(vector<AnnotatedOperation>* aops,
aops->push_back({.name = "<zeros>", .op = operation});
}
} else {
+ File old_file;
+ File new_file;
+ new_file.name = "<zeros>";
+ new_file.extents = {extent};
TEST_AND_RETURN_FALSE(DeltaReadFile(aops,
"",
new_part,
- {}, // old_extents
- {extent}, // new_extents
- {}, // old_deflates
- {}, // new_deflates
- "<zeros>",
+ old_file, // old_extents
+ new_file, // new_extents
chunk_blocks,
- version,
+ config,
blob_file));
}
}
@@ -566,19 +850,19 @@ bool DeltaMovedAndZeroBlocks(vector<AnnotatedOperation>* aops,
return true;
}
-bool DeltaReadFile(vector<AnnotatedOperation>* aops,
- const string& old_part,
- const string& new_part,
- const vector<Extent>& old_extents,
- const vector<Extent>& new_extents,
- const vector<puffin::BitExtent>& old_deflates,
- const vector<puffin::BitExtent>& new_deflates,
- const string& name,
+bool DeltaReadFile(std::vector<AnnotatedOperation>* aops,
+ const std::string& old_part,
+ const std::string& new_part,
+ const File& old_file,
+ const File& new_file,
ssize_t chunk_blocks,
- const PayloadVersion& version,
+ const PayloadGenerationConfig& config,
BlobFileWriter* blob_file) {
+ const auto& old_extents = old_file.extents;
+ const auto& new_extents = new_file.extents;
+ const auto& name = new_file.name;
+
brillo::Blob data;
- InstallOperation operation;
uint64_t total_blocks = utils::BlocksInExtents(new_extents);
if (chunk_blocks == 0) {
@@ -602,30 +886,29 @@ bool DeltaReadFile(vector<AnnotatedOperation>* aops,
NormalizeExtents(&old_extents_chunk);
NormalizeExtents(&new_extents_chunk);
+ // Now, insert into the list of operations.
+ AnnotatedOperation aop;
+ aop.name = new_file.name;
TEST_AND_RETURN_FALSE(ReadExtentsToDiff(old_part,
new_part,
old_extents_chunk,
new_extents_chunk,
- old_deflates,
- new_deflates,
- version,
+ old_file,
+ new_file,
+ config,
&data,
- &operation));
+ &aop));
// Check if the operation writes nothing.
- if (operation.dst_extents_size() == 0) {
+ if (aop.op.dst_extents_size() == 0) {
LOG(ERROR) << "Empty non-MOVE operation";
return false;
}
- // Now, insert into the list of operations.
- AnnotatedOperation aop;
- aop.name = name;
if (static_cast<uint64_t>(chunk_blocks) < total_blocks) {
aop.name = base::StringPrintf(
"%s:%" PRIu64, name.c_str(), block_offset / chunk_blocks);
}
- aop.op = operation;
// Write the data
TEST_AND_RETURN_FALSE(aop.SetOperationBlob(data, blob_file));
@@ -688,47 +971,96 @@ bool GenerateBestFullOperation(const brillo::Blob& new_data,
return true;
}
-bool ReadExtentsToDiff(const string& old_part,
- const string& new_part,
- const vector<Extent>& old_extents,
- const vector<Extent>& new_extents,
- const vector<puffin::BitExtent>& old_deflates,
- const vector<puffin::BitExtent>& new_deflates,
- const PayloadVersion& version,
- brillo::Blob* out_data,
- InstallOperation* out_op) {
- InstallOperation operation;
+// Decide which blocks are similar from bsdiff patch.
+// Blocks included in out_op->xor_map will be converted to COW_XOR during OTA
+// installation
+bool PopulateXorOps(AnnotatedOperation* aop, const uint8_t* data, size_t size) {
+ bsdiff::BsdiffPatchReader patch_reader;
+ TEST_AND_RETURN_FALSE(patch_reader.Init(data, size));
+ ControlEntry entry;
+ size_t new_off = 0;
+ int64_t old_off = 0;
+ auto& xor_ops = aop->xor_ops;
+ size_t total_xor_blocks = 0;
+ const auto new_file_size =
+ utils::BlocksInExtents(aop->op.dst_extents()) * kBlockSize;
+ while (new_off < new_file_size) {
+ if (!patch_reader.ParseControlEntry(&entry)) {
+ LOG(ERROR)
+ << "Exhausted bsdiff patch data before reaching end of new file. "
+ "Current position: "
+ << new_off << " new file size: " << new_file_size;
+ return false;
+ }
+ if (old_off >= 0) {
+ auto dst_off_aligned = utils::RoundUp(new_off, kBlockSize);
+ const auto skip = dst_off_aligned - new_off;
+ auto src_off = old_off + skip;
+ const size_t chunk_size =
+ entry.diff_size - std::min(skip, entry.diff_size);
+ const auto xor_blocks = (chunk_size + kBlockSize / 2) / kBlockSize;
+ total_xor_blocks += xor_blocks;
+ // Append chunk_size/kBlockSize number of XOR blocks, subject to rounding
+ // rules: if decimal part of that division is >= 0.5, round up.
+ for (size_t i = 0; i < xor_blocks; i++) {
+ AppendXorBlock(
+ &xor_ops,
+ GetNthBlock(aop->op.src_extents(), src_off / kBlockSize),
+ GetNthBlock(aop->op.dst_extents(), dst_off_aligned / kBlockSize),
+ src_off % kBlockSize);
+ src_off += kBlockSize;
+ dst_off_aligned += kBlockSize;
+ }
+ }
- // We read blocks from old_extents and write blocks to new_extents.
- uint64_t blocks_to_read = utils::BlocksInExtents(old_extents);
- uint64_t blocks_to_write = utils::BlocksInExtents(new_extents);
+ old_off += entry.diff_size + entry.offset_increment;
+ new_off += entry.diff_size + entry.extra_size;
+ }
- // Disable bsdiff, and puffdiff when the data is too big.
- bool bsdiff_allowed =
- version.OperationAllowed(InstallOperation::SOURCE_BSDIFF);
- if (bsdiff_allowed &&
- blocks_to_read * kBlockSize > kMaxBsdiffDestinationSize) {
- LOG(INFO) << "bsdiff ignored, data too big: " << blocks_to_read * kBlockSize
- << " bytes";
- bsdiff_allowed = false;
+ for (auto& op : xor_ops) {
+ CHECK_EQ(op.src_extent().num_blocks(), op.dst_extent().num_blocks());
+ // If |src_offset| is greater than 0, then we are reading 1
+ // extra block at the end of src_extent. This dependency must
+ // be honored during merge sequence generation, or we can end
+ // up with a corrupted device after merge.
+ if (op.src_offset() > 0) {
+ op.mutable_src_extent()->set_num_blocks(op.dst_extent().num_blocks() + 1);
+ }
}
- bool puffdiff_allowed = version.OperationAllowed(InstallOperation::PUFFDIFF);
- if (puffdiff_allowed &&
- blocks_to_read * kBlockSize > kMaxPuffdiffDestinationSize) {
- LOG(INFO) << "puffdiff ignored, data too big: "
- << blocks_to_read * kBlockSize << " bytes";
- puffdiff_allowed = false;
+ if (xor_ops.size() > 0) {
+ // TODO(177104308) Filter out duplicate blocks in XOR op
+ LOG(INFO) << "Added " << total_xor_blocks << " XOR blocks, "
+ << total_xor_blocks * 100.0f / new_off * kBlockSize
+ << "% of blocks in this InstallOp are XOR";
}
+ return true;
+}
- // Make copies of the extents so we can modify them.
- vector<Extent> src_extents = old_extents;
- vector<Extent> dst_extents = new_extents;
+bool ReadExtentsToDiff(const string& old_part,
+ const string& new_part,
+ const vector<Extent>& src_extents,
+ const vector<Extent>& dst_extents,
+ const File& old_file,
+ const File& new_file,
+ const PayloadGenerationConfig& config,
+ brillo::Blob* out_data,
+ AnnotatedOperation* out_op) {
+ const auto& version = config.version;
+ AnnotatedOperation& aop = *out_op;
+ InstallOperation& operation = aop.op;
+
+ // We read blocks from old_extents and write blocks to new_extents.
+ const uint64_t blocks_to_read = utils::BlocksInExtents(src_extents);
+ const uint64_t blocks_to_write = utils::BlocksInExtents(dst_extents);
+
+ // All operations have dst_extents.
+ StoreExtents(dst_extents, operation.mutable_dst_extents());
// Read in bytes from new data.
brillo::Blob new_data;
TEST_AND_RETURN_FALSE(utils::ReadExtents(new_part,
- new_extents,
+ dst_extents,
&new_data,
kBlockSize * blocks_to_write,
kBlockSize));
@@ -744,8 +1076,8 @@ bool ReadExtentsToDiff(const string& old_part,
GenerateBestFullOperation(new_data, version, &data_blob, &op_type));
operation.set_type(op_type);
- brillo::Blob old_data;
if (blocks_to_read > 0) {
+ brillo::Blob old_data;
// Read old data.
TEST_AND_RETURN_FALSE(utils::ReadExtents(old_part,
src_extents,
@@ -760,85 +1092,17 @@ bool ReadExtentsToDiff(const string& old_part,
operation, data_blob.size(), 0, src_extents.size())) {
// No point in trying diff if zero blob size diff operation is
// still worse than replace.
- if (bsdiff_allowed) {
- base::FilePath patch;
- TEST_AND_RETURN_FALSE(base::CreateTemporaryFile(&patch));
- ScopedPathUnlinker unlinker(patch.value());
-
- std::unique_ptr<bsdiff::PatchWriterInterface> bsdiff_patch_writer;
- InstallOperation::Type operation_type = InstallOperation::SOURCE_BSDIFF;
- if (version.OperationAllowed(InstallOperation::BROTLI_BSDIFF)) {
- bsdiff_patch_writer =
- bsdiff::CreateBSDF2PatchWriter(patch.value(),
- bsdiff::CompressorType::kBrotli,
- kBrotliCompressionQuality);
- operation_type = InstallOperation::BROTLI_BSDIFF;
- } else {
- bsdiff_patch_writer = bsdiff::CreateBsdiffPatchWriter(patch.value());
- }
-
- brillo::Blob bsdiff_delta;
- TEST_AND_RETURN_FALSE(0 == bsdiff::bsdiff(old_data.data(),
- old_data.size(),
- new_data.data(),
- new_data.size(),
- bsdiff_patch_writer.get(),
- nullptr));
-
- TEST_AND_RETURN_FALSE(utils::ReadFile(patch.value(), &bsdiff_delta));
- CHECK_GT(bsdiff_delta.size(), static_cast<brillo::Blob::size_type>(0));
- if (IsDiffOperationBetter(operation,
- data_blob.size(),
- bsdiff_delta.size(),
- src_extents.size())) {
- operation.set_type(operation_type);
- data_blob = std::move(bsdiff_delta);
- }
- }
- if (puffdiff_allowed) {
- // Find all deflate positions inside the given extents and then put all
- // deflates together because we have already read all the extents into
- // one buffer.
- vector<puffin::BitExtent> src_deflates;
- TEST_AND_RETURN_FALSE(deflate_utils::FindAndCompactDeflates(
- src_extents, old_deflates, &src_deflates));
-
- vector<puffin::BitExtent> dst_deflates;
- TEST_AND_RETURN_FALSE(deflate_utils::FindAndCompactDeflates(
- dst_extents, new_deflates, &dst_deflates));
-
- puffin::RemoveEqualBitExtents(
- old_data, new_data, &src_deflates, &dst_deflates);
-
- // See crbug.com/915559.
- if (version.minor <= kPuffdiffMinorPayloadVersion) {
- TEST_AND_RETURN_FALSE(puffin::RemoveDeflatesWithBadDistanceCaches(
- old_data, &src_deflates));
-
- TEST_AND_RETURN_FALSE(puffin::RemoveDeflatesWithBadDistanceCaches(
- new_data, &dst_deflates));
- }
-
- // Only Puffdiff if both files have at least one deflate left.
- if (!src_deflates.empty() && !dst_deflates.empty()) {
- brillo::Blob puffdiff_delta;
- ScopedTempFile temp_file("puffdiff-delta.XXXXXX");
- // Perform PuffDiff operation.
- TEST_AND_RETURN_FALSE(puffin::PuffDiff(old_data,
- new_data,
- src_deflates,
- dst_deflates,
- temp_file.path(),
- &puffdiff_delta));
- TEST_AND_RETURN_FALSE(puffdiff_delta.size() > 0);
- if (IsDiffOperationBetter(operation,
- data_blob.size(),
- puffdiff_delta.size(),
- src_extents.size())) {
- operation.set_type(InstallOperation::PUFFDIFF);
- data_blob = std::move(puffdiff_delta);
- }
- }
+
+ BestDiffGenerator best_diff_generator(old_data,
+ new_data,
+ src_extents,
+ dst_extents,
+ old_file,
+ new_file,
+ config);
+ if (!best_diff_generator.GenerateBestDiffOperation(&aop, &data_blob)) {
+ LOG(INFO) << "Failed to generate diff for " << new_file.name;
+ return false;
}
}
}
@@ -851,20 +1115,22 @@ bool ReadExtentsToDiff(const string& old_part,
// parameters for those minor versions, the delta payloads will be invalid.
if (operation.type() == InstallOperation::SOURCE_BSDIFF &&
version.minor <= kOpSrcHashMinorPayloadVersion) {
- operation.set_src_length(old_data.size());
- operation.set_dst_length(new_data.size());
+ operation.set_src_length(blocks_to_read * kBlockSize);
+ operation.set_dst_length(blocks_to_write * kBlockSize);
}
// Embed extents in the operation. Replace (all variants), zero and discard
// operations should not have source extents.
if (!IsNoSourceOperation(operation.type())) {
- StoreExtents(src_extents, operation.mutable_src_extents());
+ if (operation.src_extents_size() == 0) {
+ StoreExtents(src_extents, operation.mutable_src_extents());
+ }
+ } else {
+ operation.clear_src_extents();
}
- // All operations have dst_extents.
- StoreExtents(dst_extents, operation.mutable_dst_extents());
*out_data = std::move(data_blob);
- *out_op = operation;
+ *out_op = aop;
return true;
}
@@ -888,7 +1154,7 @@ bool InitializePartitionInfo(const PartitionConfig& part, PartitionInfo* info) {
const brillo::Blob& hash = hasher.raw_hash();
info->set_hash(hash.data(), hash.size());
LOG(INFO) << part.path << ": size=" << part.size
- << " hash=" << brillo::data_encoding::Base64Encode(hash);
+ << " hash=" << HexEncode(hash);
return true;
}
diff --git a/payload_generator/delta_diff_utils.h b/payload_generator/delta_diff_utils.h
index c75d16d9..dcb68673 100644
--- a/payload_generator/delta_diff_utils.h
+++ b/payload_generator/delta_diff_utils.h
@@ -14,16 +14,18 @@
// limitations under the License.
//
-#ifndef UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_UTILS_H_
-#define UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_UTILS_H_
+#ifndef PAYLOAD_GENERATOR_DELTA_DIFF_UTILS_H_
+#define PAYLOAD_GENERATOR_DELTA_DIFF_UTILS_H_
#include <map>
#include <string>
+#include <utility>
#include <vector>
#include <brillo/secure_blob.h>
#include <puffin/puffdiff.h>
+#include "payload_generator/deflate_utils.h"
#include "update_engine/payload_generator/annotated_operation.h"
#include "update_engine/payload_generator/extent_ranges.h"
#include "update_engine/payload_generator/payload_generation_config.h"
@@ -32,6 +34,7 @@
namespace chromeos_update_engine {
namespace diff_utils {
+using File = FilesystemInterface::File;
// Create operations in |aops| to produce all the blocks in the |new_part|
// partition using the filesystem opened in that PartitionConfig.
@@ -48,7 +51,7 @@ bool DeltaReadPartition(std::vector<AnnotatedOperation>* aops,
const PartitionConfig& new_part,
ssize_t hard_chunk_blocks,
size_t soft_chunk_blocks,
- const PayloadVersion& version,
+ const PayloadGenerationConfig& version,
BlobFileWriter* blob_file);
// Create operations in |aops| for identical blocks that moved around in the old
@@ -67,7 +70,7 @@ bool DeltaMovedAndZeroBlocks(std::vector<AnnotatedOperation>* aops,
size_t old_num_blocks,
size_t new_num_blocks,
ssize_t chunk_blocks,
- const PayloadVersion& version,
+ const PayloadGenerationConfig& version,
BlobFileWriter* blob_file,
ExtentRanges* old_visited_blocks,
ExtentRanges* new_visited_blocks,
@@ -84,13 +87,10 @@ bool DeltaMovedAndZeroBlocks(std::vector<AnnotatedOperation>* aops,
bool DeltaReadFile(std::vector<AnnotatedOperation>* aops,
const std::string& old_part,
const std::string& new_part,
- const std::vector<Extent>& old_extents,
- const std::vector<Extent>& new_extents,
- const std::vector<puffin::BitExtent>& old_deflates,
- const std::vector<puffin::BitExtent>& new_deflates,
- const std::string& name,
+ const File& old_file,
+ const File& new_file,
ssize_t chunk_blocks,
- const PayloadVersion& version,
+ const PayloadGenerationConfig& config,
BlobFileWriter* blob_file);
// Reads the blocks |old_extents| from |old_part| (if it exists) and the
@@ -99,18 +99,19 @@ bool DeltaReadFile(std::vector<AnnotatedOperation>* aops,
// fills in |out_op|. If there's no change in old and new files, it creates a
// MOVE or SOURCE_COPY operation. If there is a change, the smallest of the
// operations allowed in the given |version| (REPLACE, REPLACE_BZ, BSDIFF,
-// SOURCE_BSDIFF, or PUFFDIFF) wins.
+// SOURCE_BSDIFF, PUFFDIFF or ZUCCHINI) wins.
// |new_extents| must not be empty. |old_deflates| and |new_deflates| are all
// the deflate locations in |old_part| and |new_part|. Returns true on success.
+// TODO(197361113) Move logic to calculate deflates inside puffin.
bool ReadExtentsToDiff(const std::string& old_part,
const std::string& new_part,
const std::vector<Extent>& old_extents,
const std::vector<Extent>& new_extents,
- const std::vector<puffin::BitExtent>& old_deflates,
- const std::vector<puffin::BitExtent>& new_deflates,
- const PayloadVersion& version,
+ const File& old_file,
+ const File& new_file,
+ const PayloadGenerationConfig& config,
brillo::Blob* out_data,
- InstallOperation* out_op);
+ AnnotatedOperation* out_op);
// Generates the best allowed full operation to produce |new_data|. The allowed
// operations are based on |payload_version|. The operation blob will be stored
@@ -149,8 +150,96 @@ FilesystemInterface::File GetOldFile(
const std::map<std::string, FilesystemInterface::File>& old_files_map,
const std::string& new_file_name);
+// Read BSDIFF patch data in |data|, compute list of blocks that can be COW_XOR,
+// store these blocks in |aop|.
+bool PopulateXorOps(AnnotatedOperation* aop, const uint8_t* data, size_t size);
+
+inline bool PopulateXorOps(AnnotatedOperation* aop,
+ const brillo::Blob& patch_data) {
+ return PopulateXorOps(aop, patch_data.data(), patch_data.size());
+}
+
+// A utility class that tries different algorithms and pick the patch with the
+// smallest size.
+
+class BestDiffGenerator {
+ public:
+ BestDiffGenerator(const brillo::Blob& old_data,
+ const brillo::Blob& new_data,
+ const std::vector<Extent>& src_extents,
+ const std::vector<Extent>& dst_extents,
+ const File& old_file,
+ const File& new_file,
+ const PayloadGenerationConfig& config)
+ : old_data_(old_data),
+ new_data_(new_data),
+ src_extents_(src_extents),
+ dst_extents_(dst_extents),
+ old_deflates_(old_file.deflates),
+ new_deflates_(new_file.deflates),
+ old_block_info_(old_file.compressed_file_info),
+ new_block_info_(new_file.compressed_file_info),
+ config_(config) {
+ using std::vector;
+ // Find all deflate positions inside the given extents and then put all
+ // deflates together because we have already read all the extents into
+ // one buffer.
+ vector<puffin::BitExtent> src_deflates;
+ TEST_AND_RETURN(deflate_utils::FindAndCompactDeflates(
+ src_extents_, old_deflates_, &src_deflates));
+
+ vector<puffin::BitExtent> dst_deflates;
+ TEST_AND_RETURN(deflate_utils::FindAndCompactDeflates(
+ dst_extents_, new_deflates_, &dst_deflates));
+ puffin::RemoveEqualBitExtents(
+ old_data_, new_data_, &src_deflates, &dst_deflates);
+ // See crbug.com/915559.
+ if (config.version.minor <= kPuffdiffMinorPayloadVersion) {
+ CHECK(
+ puffin::RemoveDeflatesWithBadDistanceCaches(old_data, &src_deflates));
+
+ CHECK(
+ puffin::RemoveDeflatesWithBadDistanceCaches(new_data, &dst_deflates));
+ }
+ old_deflates_ = std::move(src_deflates);
+ new_deflates_ = std::move(dst_deflates);
+ }
+
+ // Tries different algorithms and compares their patch sizes with the
+ // compressed full operation data in |data_blob|. If the size is smaller,
+ // updates the operation type in |aop| and bytes in |data_blob|.
+ bool GenerateBestDiffOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+
+ bool GenerateBestDiffOperation(
+ const std::vector<std::pair<InstallOperation_Type, size_t>>&
+ diff_candidates,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+
+ private:
+ std::vector<bsdiff::CompressorType> GetUsableCompressorTypes() const;
+ bool TryBsdiffAndUpdateOperation(InstallOperation_Type operation_type,
+ AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+ bool TryPuffdiffAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+ bool TryZucchiniAndUpdateOperation(AnnotatedOperation* aop,
+ brillo::Blob* data_blob);
+
+ const brillo::Blob& old_data_;
+ const brillo::Blob& new_data_;
+ const std::vector<Extent>& src_extents_;
+ const std::vector<Extent>& dst_extents_;
+ std::vector<puffin::BitExtent> old_deflates_;
+ std::vector<puffin::BitExtent> new_deflates_;
+ const CompressedFile& old_block_info_;
+ const CompressedFile& new_block_info_;
+ const PayloadGenerationConfig& config_;
+};
+
} // namespace diff_utils
} // namespace chromeos_update_engine
-#endif // UPDATE_ENGINE_PAYLOAD_GENERATOR_DELTA_DIFF_UTILS_H_
+#endif // PAYLOAD_GENERATOR_DELTA_DIFF_UTILS_H_
diff --git a/payload_generator/delta_diff_utils_unittest.cc b/payload_generator/delta_diff_utils_unittest.cc
index f2db1bdc..7348d745 100644
--- a/payload_generator/delta_diff_utils_unittest.cc
+++ b/payload_generator/delta_diff_utils_unittest.cc
@@ -24,8 +24,10 @@
#include <base/files/scoped_file.h>
#include <base/format_macros.h>
#include <base/strings/stringprintf.h>
+#include <bsdiff/patch_writer.h>
#include <gtest/gtest.h>
+#include "payload_generator/filesystem_interface.h"
#include "update_engine/common/test_utils.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
@@ -133,7 +135,7 @@ class DeltaDiffUtilsTest : public ::testing::Test {
old_part_.size / block_size_,
new_part_.size / block_size_,
chunk_blocks,
- version,
+ {.version = version},
&blob_file,
&old_visited_blocks_,
&new_visited_blocks_,
@@ -164,22 +166,22 @@ TEST_F(DeltaDiffUtilsTest, SkipVerityExtentsTest) {
new_part_.verity.fec_extent = ExtentForRange(40, 50);
BlobFileWriter blob_file(tmp_blob_file_.fd(), &blob_size_);
- EXPECT_TRUE(diff_utils::DeltaReadPartition(
+ ASSERT_TRUE(diff_utils::DeltaReadPartition(
&aops_,
old_part_,
new_part_,
-1,
-1,
- PayloadVersion(kMaxSupportedMajorPayloadVersion,
- kVerityMinorPayloadVersion),
+ {.version = PayloadVersion(kMaxSupportedMajorPayloadVersion,
+ kVerityMinorPayloadVersion)},
&blob_file));
for (const auto& aop : aops_) {
new_visited_blocks_.AddRepeatedExtents(aop.op.dst_extents());
}
for (const auto& extent : new_visited_blocks_.extent_set()) {
- EXPECT_FALSE(ExtentRanges::ExtentsOverlap(
+ ASSERT_FALSE(ExtentRanges::ExtentsOverlap(
extent, new_part_.verity.hash_tree_extent));
- EXPECT_FALSE(
+ ASSERT_FALSE(
ExtentRanges::ExtentsOverlap(extent, new_part_.verity.fec_extent));
}
}
@@ -203,34 +205,36 @@ TEST_F(DeltaDiffUtilsTest, ReplaceSmallTest) {
for (int i = 0; i < 2; i++) {
brillo::Blob data_to_test = i == 0 ? random_data : ones;
// The old_extents will be initialized with 0.
- EXPECT_TRUE(
+ ASSERT_TRUE(
WriteExtents(new_part_.path, new_extents, kBlockSize, data_to_test));
brillo::Blob data;
- InstallOperation op;
- EXPECT_TRUE(diff_utils::ReadExtentsToDiff(
+ AnnotatedOperation aop;
+ InstallOperation& op = aop.op;
+ ASSERT_TRUE(diff_utils::ReadExtentsToDiff(
old_part_.path,
new_part_.path,
old_extents,
new_extents,
- {}, // old_deflates
- {}, // new_deflates
- PayloadVersion(kBrilloMajorPayloadVersion, kSourceMinorPayloadVersion),
+ {}, // old_file
+ {}, // new_file
+ {.version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kSourceMinorPayloadVersion)},
&data,
- &op));
- EXPECT_FALSE(data.empty());
+ &aop));
+ ASSERT_FALSE(data.empty());
- EXPECT_TRUE(op.has_type());
+ ASSERT_TRUE(op.has_type());
const InstallOperation::Type expected_type =
(i == 0 ? InstallOperation::REPLACE : InstallOperation::REPLACE_BZ);
- EXPECT_EQ(expected_type, op.type());
- EXPECT_FALSE(op.has_data_offset());
- EXPECT_FALSE(op.has_data_length());
- EXPECT_EQ(0, op.src_extents_size());
- EXPECT_FALSE(op.has_src_length());
- EXPECT_EQ(1, op.dst_extents_size());
- EXPECT_FALSE(op.has_dst_length());
- EXPECT_EQ(1U, utils::BlocksInExtents(op.dst_extents()));
+ ASSERT_EQ(expected_type, op.type());
+ ASSERT_FALSE(op.has_data_offset());
+ ASSERT_FALSE(op.has_data_length());
+ ASSERT_EQ(0, op.src_extents_size());
+ ASSERT_FALSE(op.has_src_length());
+ ASSERT_EQ(1, op.dst_extents_size());
+ ASSERT_FALSE(op.has_dst_length());
+ ASSERT_EQ(1U, utils::BlocksInExtents(op.dst_extents()));
}
}
@@ -245,25 +249,27 @@ TEST_F(DeltaDiffUtilsTest, SourceCopyTest) {
vector<Extent> old_extents = {ExtentForRange(11, 1)};
vector<Extent> new_extents = {ExtentForRange(1, 1)};
- EXPECT_TRUE(WriteExtents(old_part_.path, old_extents, kBlockSize, data_blob));
- EXPECT_TRUE(WriteExtents(new_part_.path, new_extents, kBlockSize, data_blob));
+ ASSERT_TRUE(WriteExtents(old_part_.path, old_extents, kBlockSize, data_blob));
+ ASSERT_TRUE(WriteExtents(new_part_.path, new_extents, kBlockSize, data_blob));
brillo::Blob data;
- InstallOperation op;
- EXPECT_TRUE(diff_utils::ReadExtentsToDiff(
+ AnnotatedOperation aop;
+ ASSERT_TRUE(diff_utils::ReadExtentsToDiff(
old_part_.path,
new_part_.path,
old_extents,
new_extents,
{}, // old_deflates
{}, // new_deflates
- PayloadVersion(kBrilloMajorPayloadVersion, kSourceMinorPayloadVersion),
+ {.version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kSourceMinorPayloadVersion)},
&data,
- &op));
- EXPECT_TRUE(data.empty());
+ &aop));
+ InstallOperation& op = aop.op;
+ ASSERT_TRUE(data.empty());
- EXPECT_TRUE(op.has_type());
- EXPECT_EQ(InstallOperation::SOURCE_COPY, op.type());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::SOURCE_COPY, op.type());
}
TEST_F(DeltaDiffUtilsTest, SourceBsdiffTest) {
@@ -277,27 +283,154 @@ TEST_F(DeltaDiffUtilsTest, SourceBsdiffTest) {
vector<Extent> old_extents = {ExtentForRange(1, 1)};
vector<Extent> new_extents = {ExtentForRange(2, 1)};
- EXPECT_TRUE(WriteExtents(old_part_.path, old_extents, kBlockSize, data_blob));
+ ASSERT_TRUE(WriteExtents(old_part_.path, old_extents, kBlockSize, data_blob));
// Modify one byte in the new file.
data_blob[0]++;
- EXPECT_TRUE(WriteExtents(new_part_.path, new_extents, kBlockSize, data_blob));
+ ASSERT_TRUE(WriteExtents(new_part_.path, new_extents, kBlockSize, data_blob));
brillo::Blob data;
- InstallOperation op;
- EXPECT_TRUE(diff_utils::ReadExtentsToDiff(
+ AnnotatedOperation aop;
+ ASSERT_TRUE(diff_utils::ReadExtentsToDiff(
old_part_.path,
new_part_.path,
old_extents,
new_extents,
{}, // old_deflates
{}, // new_deflates
- PayloadVersion(kBrilloMajorPayloadVersion, kSourceMinorPayloadVersion),
+ {.version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kSourceMinorPayloadVersion)},
&data,
- &op));
+ &aop));
+ auto& op = aop.op;
+ ASSERT_FALSE(data.empty());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::SOURCE_BSDIFF, op.type());
+}
+
+TEST_F(DeltaDiffUtilsTest, BrotliBsdiffTest) {
+ // Makes sure SOURCE_BSDIFF operations are emitted whenever src_ops_allowed
+ // is true. It is the same setup as BsdiffSmallTest, which checks
+ // that the operation is well-formed.
+ brillo::Blob data_blob(kBlockSize);
+ test_utils::FillWithData(&data_blob);
+
+ // The old file is on a different block than the new one.
+ vector<Extent> old_extents = {ExtentForRange(1, 1)};
+ vector<Extent> new_extents = {ExtentForRange(2, 1)};
+
+ ASSERT_TRUE(WriteExtents(old_part_.path, old_extents, kBlockSize, data_blob));
+ // Modify one byte in the new file.
+ data_blob[0]++;
+ ASSERT_TRUE(WriteExtents(new_part_.path, new_extents, kBlockSize, data_blob));
+
+ brillo::Blob data;
+ AnnotatedOperation aop;
+
+ std::vector<puffin::BitExtent> empty;
+ PayloadGenerationConfig config{
+ .version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kBrotliBsdiffMinorPayloadVersion)};
+ ASSERT_TRUE(diff_utils::ReadExtentsToDiff(old_part_.path,
+ new_part_.path,
+ old_extents,
+ new_extents,
+ {}, // old_file
+ {}, // new_file
+ config,
+ &data,
+ &aop));
+ auto& op = aop.op;
+ ASSERT_FALSE(data.empty());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::BROTLI_BSDIFF, op.type());
+}
+
+TEST_F(DeltaDiffUtilsTest, GenerateBestDiffOperation_Zucchini) {
+ // Makes sure SOURCE_BSDIFF operations are emitted whenever src_ops_allowed
+ // is true. It is the same setup as BsdiffSmallTest, which checks
+ // that the operation is well-formed.
+ brillo::Blob dst_data_blob(kBlockSize);
+ test_utils::FillWithData(&dst_data_blob);
+
+ // The old file is on a different block than the new one.
+ vector<Extent> old_extents = {ExtentForRange(1, 1)};
+ vector<Extent> new_extents = {ExtentForRange(2, 1)};
+
+ ASSERT_TRUE(
+ WriteExtents(old_part_.path, old_extents, kBlockSize, dst_data_blob));
+ // Modify one byte in the new file.
+ brillo::Blob src_data_blob = dst_data_blob;
+ src_data_blob[0]++;
+ ASSERT_TRUE(
+ WriteExtents(new_part_.path, new_extents, kBlockSize, src_data_blob));
+
+ brillo::Blob data = dst_data_blob; // Fake the full operation
+ AnnotatedOperation aop;
+ // Zucchini is only enabled on files with certain extensions
+ aop.name = "data.so";
+
+ const FilesystemInterface::File empty;
+ PayloadGenerationConfig config{
+ .version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kZucchiniMinorPayloadVersion)};
+ diff_utils::BestDiffGenerator best_diff_generator(src_data_blob,
+ dst_data_blob,
+ old_extents,
+ new_extents,
+ empty,
+ empty,
+ config);
+ ASSERT_TRUE(best_diff_generator.GenerateBestDiffOperation(
+ {{InstallOperation::ZUCCHINI, 1024 * 1024}}, &aop, &data));
+
+ auto& op = aop.op;
+ ASSERT_FALSE(data.empty());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::ZUCCHINI, op.type());
+}
+
+TEST_F(DeltaDiffUtilsTest, GenerateBestDiffOperation_FullOperationBetter) {
+ // Makes sure SOURCE_BSDIFF operations are emitted whenever src_ops_allowed
+ // is true. It is the same setup as BsdiffSmallTest, which checks
+ // that the operation is well-formed.
+ brillo::Blob dst_data_blob(kBlockSize);
+ test_utils::FillWithData(&dst_data_blob);
+
+ // The old file is on a different block than the new one.
+ vector<Extent> old_extents = {ExtentForRange(1, 1)};
+ vector<Extent> new_extents = {ExtentForRange(2, 1)};
- EXPECT_FALSE(data.empty());
- EXPECT_TRUE(op.has_type());
- EXPECT_EQ(InstallOperation::SOURCE_BSDIFF, op.type());
+ ASSERT_TRUE(
+ WriteExtents(old_part_.path, old_extents, kBlockSize, dst_data_blob));
+ // Modify one byte in the new file.
+ brillo::Blob src_data_blob = dst_data_blob;
+ src_data_blob[0]++;
+ ASSERT_TRUE(
+ WriteExtents(new_part_.path, new_extents, kBlockSize, src_data_blob));
+
+ brillo::Blob data(1);
+ test_utils::FillWithData(&data); // Fake the full operation
+ AnnotatedOperation aop;
+ aop.op.set_type(InstallOperation::REPLACE_XZ);
+
+ const FilesystemInterface::File empty;
+ PayloadGenerationConfig config{
+ .version = PayloadVersion(kBrilloMajorPayloadVersion,
+ kZucchiniMinorPayloadVersion)};
+ diff_utils::BestDiffGenerator best_diff_generator(src_data_blob,
+ dst_data_blob,
+ old_extents,
+ new_extents,
+ empty,
+ empty,
+ config);
+ ASSERT_TRUE(best_diff_generator.GenerateBestDiffOperation(
+ {{InstallOperation::ZUCCHINI, 1024 * 1024}}, &aop, &data));
+
+ auto& op = aop.op;
+ ASSERT_EQ(1u, data.size());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::REPLACE_XZ, op.type());
}
TEST_F(DeltaDiffUtilsTest, PreferReplaceTest) {
@@ -307,28 +440,31 @@ TEST_F(DeltaDiffUtilsTest, PreferReplaceTest) {
// Write something in the first 50 bytes so that REPLACE_BZ will be slightly
// larger than BROTLI_BSDIFF.
std::iota(data_blob.begin(), data_blob.begin() + 50, 0);
- EXPECT_TRUE(WriteExtents(old_part_.path, extents, kBlockSize, data_blob));
+ ASSERT_TRUE(WriteExtents(old_part_.path, extents, kBlockSize, data_blob));
// Shift the first 50 bytes in the new file by one.
std::iota(data_blob.begin(), data_blob.begin() + 50, 1);
- EXPECT_TRUE(WriteExtents(new_part_.path, extents, kBlockSize, data_blob));
+ ASSERT_TRUE(WriteExtents(new_part_.path, extents, kBlockSize, data_blob));
brillo::Blob data;
- InstallOperation op;
- EXPECT_TRUE(diff_utils::ReadExtentsToDiff(
- old_part_.path,
- new_part_.path,
- extents,
- extents,
- {}, // old_deflates
- {}, // new_deflates
- PayloadVersion(kMaxSupportedMajorPayloadVersion,
- kMaxSupportedMinorPayloadVersion),
- &data,
- &op));
-
- EXPECT_FALSE(data.empty());
- EXPECT_TRUE(op.has_type());
- EXPECT_EQ(InstallOperation::REPLACE_BZ, op.type());
+ AnnotatedOperation aop;
+
+ const FilesystemInterface::File empty;
+ PayloadGenerationConfig config{
+ .version = PayloadVersion(kMaxSupportedMajorPayloadVersion,
+ kMaxSupportedMinorPayloadVersion)};
+ ASSERT_TRUE(diff_utils::ReadExtentsToDiff(old_part_.path,
+ new_part_.path,
+ extents,
+ extents,
+ empty, // old_file
+ empty, // new_file
+ config,
+ &data,
+ &aop));
+ auto& op = aop.op;
+ ASSERT_FALSE(data.empty());
+ ASSERT_TRUE(op.has_type());
+ ASSERT_EQ(InstallOperation::REPLACE_BZ, op.type());
}
// Test the simple case where all the blocks are different and no new blocks are
@@ -337,13 +473,13 @@ TEST_F(DeltaDiffUtilsTest, NoZeroedOrUniqueBlocksDetected) {
InitializePartitionWithUniqueBlocks(old_part_, block_size_, 5);
InitializePartitionWithUniqueBlocks(new_part_, block_size_, 42);
- EXPECT_TRUE(RunDeltaMovedAndZeroBlocks(-1, // chunk_blocks
+ ASSERT_TRUE(RunDeltaMovedAndZeroBlocks(-1, // chunk_blocks
kSourceMinorPayloadVersion));
- EXPECT_EQ(0U, old_visited_blocks_.blocks());
- EXPECT_EQ(0U, new_visited_blocks_.blocks());
- EXPECT_EQ(0, blob_size_);
- EXPECT_TRUE(aops_.empty());
+ ASSERT_EQ(0U, old_visited_blocks_.blocks());
+ ASSERT_EQ(0U, new_visited_blocks_.blocks());
+ ASSERT_EQ(0, blob_size_);
+ ASSERT_TRUE(aops_.empty());
}
// Test that when the partitions have identical blocks in the same positions
@@ -364,21 +500,21 @@ TEST_F(DeltaDiffUtilsTest, IdenticalBlocksAreCopiedFromSource) {
// Override some of the old blocks with different data.
vector<Extent> different_blocks = {ExtentForRange(40, 5)};
- EXPECT_TRUE(WriteExtents(old_part_.path,
+ ASSERT_TRUE(WriteExtents(old_part_.path,
different_blocks,
kBlockSize,
brillo::Blob(5 * kBlockSize, 'a')));
- EXPECT_TRUE(RunDeltaMovedAndZeroBlocks(10, // chunk_blocks
+ ASSERT_TRUE(RunDeltaMovedAndZeroBlocks(10, // chunk_blocks
kSourceMinorPayloadVersion));
ExtentRanges expected_ranges;
expected_ranges.AddExtent(ExtentForRange(0, 50));
expected_ranges.SubtractExtents(different_blocks);
- EXPECT_EQ(expected_ranges.extent_set(), old_visited_blocks_.extent_set());
- EXPECT_EQ(expected_ranges.extent_set(), new_visited_blocks_.extent_set());
- EXPECT_EQ(0, blob_size_);
+ ASSERT_EQ(expected_ranges.extent_set(), old_visited_blocks_.extent_set());
+ ASSERT_EQ(expected_ranges.extent_set(), new_visited_blocks_.extent_set());
+ ASSERT_EQ(0, blob_size_);
// We expect all the blocks that we didn't override with |different_blocks|
// and that we didn't mark as visited in |already_visited| to match and have a
@@ -391,15 +527,15 @@ TEST_F(DeltaDiffUtilsTest, IdenticalBlocksAreCopiedFromSource) {
ExtentForRange(45, 5),
};
- EXPECT_EQ(expected_op_extents.size(), aops_.size());
+ ASSERT_EQ(expected_op_extents.size(), aops_.size());
for (size_t i = 0; i < aops_.size() && i < expected_op_extents.size(); ++i) {
SCOPED_TRACE(base::StringPrintf("Failed on operation number %" PRIuS, i));
const AnnotatedOperation& aop = aops_[i];
- EXPECT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
- EXPECT_EQ(1, aop.op.src_extents_size());
- EXPECT_EQ(expected_op_extents[i], aop.op.src_extents(0));
- EXPECT_EQ(1, aop.op.dst_extents_size());
- EXPECT_EQ(expected_op_extents[i], aop.op.dst_extents(0));
+ ASSERT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
+ ASSERT_EQ(1, aop.op.src_extents_size());
+ ASSERT_EQ(expected_op_extents[i], aop.op.src_extents(0));
+ ASSERT_EQ(1, aop.op.dst_extents_size());
+ ASSERT_EQ(expected_op_extents[i], aop.op.dst_extents(0));
}
}
@@ -419,28 +555,28 @@ TEST_F(DeltaDiffUtilsTest, IdenticalBlocksAreCopiedInOder) {
std::copy(
file_data.begin(), file_data.end(), partition_data.begin() + offset);
}
- EXPECT_TRUE(test_utils::WriteFileVector(old_part_.path, partition_data));
- EXPECT_TRUE(test_utils::WriteFileVector(new_part_.path, partition_data));
+ ASSERT_TRUE(test_utils::WriteFileVector(old_part_.path, partition_data));
+ ASSERT_TRUE(test_utils::WriteFileVector(new_part_.path, partition_data));
- EXPECT_TRUE(RunDeltaMovedAndZeroBlocks(-1, // chunk_blocks
+ ASSERT_TRUE(RunDeltaMovedAndZeroBlocks(-1, // chunk_blocks
kSourceMinorPayloadVersion));
// There should be only one SOURCE_COPY, for the whole partition and the
// source extents should cover only the first copy of the source file since
// we prefer to re-read files (maybe cached) instead of continue reading the
// rest of the partition.
- EXPECT_EQ(1U, aops_.size());
+ ASSERT_EQ(1U, aops_.size());
const AnnotatedOperation& aop = aops_[0];
- EXPECT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
- EXPECT_EQ(5, aop.op.src_extents_size());
+ ASSERT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
+ ASSERT_EQ(5, aop.op.src_extents_size());
for (int i = 0; i < aop.op.src_extents_size(); ++i) {
- EXPECT_EQ(ExtentForRange(0, 10), aop.op.src_extents(i));
+ ASSERT_EQ(ExtentForRange(0, 10), aop.op.src_extents(i));
}
- EXPECT_EQ(1, aop.op.dst_extents_size());
- EXPECT_EQ(ExtentForRange(0, 50), aop.op.dst_extents(0));
+ ASSERT_EQ(1, aop.op.dst_extents_size());
+ ASSERT_EQ(ExtentForRange(0, 50), aop.op.dst_extents(0));
- EXPECT_EQ(0, blob_size_);
+ ASSERT_EQ(0, blob_size_);
}
// Test that all blocks with zeros are handled separately using REPLACE_BZ
@@ -460,21 +596,21 @@ TEST_F(DeltaDiffUtilsTest, ZeroBlocksUseReplaceBz) {
};
brillo::Blob zeros_data(utils::BlocksInExtents(new_zeros) * block_size_,
'\0');
- EXPECT_TRUE(WriteExtents(new_part_.path, new_zeros, block_size_, zeros_data));
+ ASSERT_TRUE(WriteExtents(new_part_.path, new_zeros, block_size_, zeros_data));
vector<Extent> old_zeros = vector<Extent>{ExtentForRange(43, 7)};
- EXPECT_TRUE(WriteExtents(old_part_.path, old_zeros, block_size_, zeros_data));
+ ASSERT_TRUE(WriteExtents(old_part_.path, old_zeros, block_size_, zeros_data));
- EXPECT_TRUE(RunDeltaMovedAndZeroBlocks(5, // chunk_blocks
+ ASSERT_TRUE(RunDeltaMovedAndZeroBlocks(5, // chunk_blocks
kSourceMinorPayloadVersion));
// Zeroed blocks from |old_visited_blocks_| were copied over.
- EXPECT_EQ(old_zeros,
+ ASSERT_EQ(old_zeros,
old_visited_blocks_.GetExtentsForBlockCount(
old_visited_blocks_.blocks()));
// All the new zeroed blocks should be used with REPLACE_BZ.
- EXPECT_EQ(new_zeros,
+ ASSERT_EQ(new_zeros,
new_visited_blocks_.GetExtentsForBlockCount(
new_visited_blocks_.blocks()));
@@ -488,16 +624,16 @@ TEST_F(DeltaDiffUtilsTest, ZeroBlocksUseReplaceBz) {
ExtentForRange(45, 5),
};
- EXPECT_EQ(expected_op_extents.size(), aops_.size());
+ ASSERT_EQ(expected_op_extents.size(), aops_.size());
for (size_t i = 0; i < aops_.size() && i < expected_op_extents.size(); ++i) {
SCOPED_TRACE(base::StringPrintf("Failed on operation number %" PRIuS, i));
const AnnotatedOperation& aop = aops_[i];
- EXPECT_EQ(InstallOperation::REPLACE_BZ, aop.op.type());
- EXPECT_EQ(0, aop.op.src_extents_size());
- EXPECT_EQ(1, aop.op.dst_extents_size());
- EXPECT_EQ(expected_op_extents[i], aop.op.dst_extents(0));
+ ASSERT_EQ(InstallOperation::REPLACE_BZ, aop.op.type());
+ ASSERT_EQ(0, aop.op.src_extents_size());
+ ASSERT_EQ(1, aop.op.dst_extents_size());
+ ASSERT_EQ(expected_op_extents[i], aop.op.dst_extents(0));
}
- EXPECT_NE(0, blob_size_);
+ ASSERT_NE(0, blob_size_);
}
TEST_F(DeltaDiffUtilsTest, ShuffledBlocksAreTracked) {
@@ -515,39 +651,39 @@ TEST_F(DeltaDiffUtilsTest, ShuffledBlocksAreTracked) {
// |permutation| order. Block i in the old_part_ will contain the same data
// as block permutation[i] in the new_part_.
brillo::Blob new_contents;
- EXPECT_TRUE(utils::ReadFile(new_part_.path, &new_contents));
- EXPECT_TRUE(
+ ASSERT_TRUE(utils::ReadFile(new_part_.path, &new_contents));
+ ASSERT_TRUE(
WriteExtents(old_part_.path, perm_extents, block_size_, new_contents));
- EXPECT_TRUE(RunDeltaMovedAndZeroBlocks(-1, // chunk_blocks
+ ASSERT_TRUE(RunDeltaMovedAndZeroBlocks(-1, // chunk_blocks
kSourceMinorPayloadVersion));
- EXPECT_EQ(permutation.size(), old_visited_blocks_.blocks());
- EXPECT_EQ(permutation.size(), new_visited_blocks_.blocks());
+ ASSERT_EQ(permutation.size(), old_visited_blocks_.blocks());
+ ASSERT_EQ(permutation.size(), new_visited_blocks_.blocks());
// There should be only one SOURCE_COPY, with a complicate list of extents.
- EXPECT_EQ(1U, aops_.size());
+ ASSERT_EQ(1U, aops_.size());
const AnnotatedOperation& aop = aops_[0];
- EXPECT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
+ ASSERT_EQ(InstallOperation::SOURCE_COPY, aop.op.type());
vector<Extent> aop_src_extents;
ExtentsToVector(aop.op.src_extents(), &aop_src_extents);
- EXPECT_EQ(perm_extents, aop_src_extents);
+ ASSERT_EQ(perm_extents, aop_src_extents);
- EXPECT_EQ(1, aop.op.dst_extents_size());
- EXPECT_EQ(ExtentForRange(0, permutation.size()), aop.op.dst_extents(0));
+ ASSERT_EQ(1, aop.op.dst_extents_size());
+ ASSERT_EQ(ExtentForRange(0, permutation.size()), aop.op.dst_extents(0));
- EXPECT_EQ(0, blob_size_);
+ ASSERT_EQ(0, blob_size_);
}
TEST_F(DeltaDiffUtilsTest, IsExtFilesystemTest) {
- EXPECT_TRUE(diff_utils::IsExtFilesystem(
+ ASSERT_TRUE(diff_utils::IsExtFilesystem(
test_utils::GetBuildArtifactsPath("gen/disk_ext2_1k.img")));
- EXPECT_TRUE(diff_utils::IsExtFilesystem(
+ ASSERT_TRUE(diff_utils::IsExtFilesystem(
test_utils::GetBuildArtifactsPath("gen/disk_ext2_4k.img")));
}
TEST_F(DeltaDiffUtilsTest, GetOldFileEmptyTest) {
- EXPECT_TRUE(diff_utils::GetOldFile({}, "filename").name.empty());
+ ASSERT_TRUE(diff_utils::GetOldFile({}, "filename").name.empty());
}
TEST_F(DeltaDiffUtilsTest, GetOldFileTest) {
@@ -569,24 +705,144 @@ TEST_F(DeltaDiffUtilsTest, GetOldFileTest) {
// Always return exact match if possible.
for (const auto& name : file_list)
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, name).name, name);
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, name).name, name);
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, "file_name").name,
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, "file_name").name,
"filename");
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, "filename_new.zip").name,
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, "filename_new.zip").name,
"filename.zip");
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, "version1.2").name,
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, "version1.2").name,
"version1.1");
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, "version3.0").name,
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, "version3.0").name,
"version2.0");
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, "_version").name, "version");
- EXPECT_EQ(
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, "_version").name, "version");
+ ASSERT_EQ(
diff_utils::GetOldFile(old_files_map, "update_engine_unittest").name,
"update_engine");
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, "bin/delta_generator").name,
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, "bin/delta_generator").name,
"delta_generator");
// Check file name with minimum size.
- EXPECT_EQ(diff_utils::GetOldFile(old_files_map, "a").name, "filename");
+ ASSERT_EQ(diff_utils::GetOldFile(old_files_map, "a").name, "filename");
+}
+
+TEST_F(DeltaDiffUtilsTest, XorOpsSourceNotAligned) {
+ ScopedTempFile patch_file;
+ bsdiff::BsdiffPatchWriter writer{patch_file.path()};
+ ASSERT_TRUE(writer.Init(kBlockSize * 10));
+ ASSERT_TRUE(writer.AddControlEntry(ControlEntry(0, 0, 123 + kBlockSize)));
+ ASSERT_TRUE(writer.AddControlEntry(ControlEntry(kBlockSize, 0, 0)));
+ ASSERT_TRUE(writer.Close());
+
+ std::string patch_data;
+ utils::ReadFile(patch_file.path(), &patch_data);
+
+ AnnotatedOperation aop;
+ *aop.op.add_src_extents() = ExtentForRange(50, 10);
+ *aop.op.add_dst_extents() = ExtentForRange(500, 10);
+
+ diff_utils::PopulateXorOps(
+ &aop,
+ reinterpret_cast<const uint8_t*>(patch_data.data()),
+ patch_data.size());
+ for (const auto& op : aop.xor_ops) {
+ ASSERT_EQ(op.type(), CowMergeOperation::COW_XOR);
+ }
+ ASSERT_EQ(aop.xor_ops.size(), 1UL) << "Only 1 block can possibly be XORed";
+ ASSERT_EQ(aop.xor_ops[0].src_extent().num_blocks(), 1UL);
+ ASSERT_EQ(aop.xor_ops[0].src_extent().start_block(), 51UL);
+ ASSERT_EQ(aop.xor_ops[0].src_offset(), 123UL);
+
+ ASSERT_EQ(aop.xor_ops[0].dst_extent().num_blocks(), 1UL);
+ ASSERT_EQ(aop.xor_ops[0].dst_extent().start_block(), 500UL);
+}
+
+TEST_F(DeltaDiffUtilsTest, XorOpsTargetNotAligned) {
+ ScopedTempFile patch_file;
+ bsdiff::BsdiffPatchWriter writer{patch_file.path()};
+ ASSERT_TRUE(writer.Init(kBlockSize * 10));
+ ASSERT_TRUE(writer.AddControlEntry(
+ ControlEntry(0, kBlockSize - 456, 123 + kBlockSize)));
+ ASSERT_TRUE(writer.AddControlEntry(ControlEntry(kBlockSize + 456, 0, 0)));
+ ASSERT_TRUE(writer.Close());
+
+ std::string patch_data;
+ utils::ReadFile(patch_file.path(), &patch_data);
+
+ AnnotatedOperation aop;
+ *aop.op.add_src_extents() = ExtentForRange(50, 10);
+ *aop.op.add_dst_extents() = ExtentForRange(500, 10);
+
+ diff_utils::PopulateXorOps(
+ &aop,
+ reinterpret_cast<const uint8_t*>(patch_data.data()),
+ patch_data.size());
+ for (const auto& op : aop.xor_ops) {
+ ASSERT_EQ(op.type(), CowMergeOperation::COW_XOR);
+ }
+ ASSERT_EQ(aop.xor_ops.size(), 1UL) << "Only 1 block can possibly be XORed";
+ ASSERT_EQ(aop.xor_ops[0].src_extent().num_blocks(), 1UL);
+ ASSERT_EQ(aop.xor_ops[0].src_extent().start_block(), 51UL);
+ ASSERT_EQ(aop.xor_ops[0].src_offset(), 123UL + 456UL);
+
+ ASSERT_EQ(aop.xor_ops[0].dst_extent().num_blocks(), 1UL);
+ ASSERT_EQ(aop.xor_ops[0].dst_extent().start_block(), 501UL);
+}
+
+TEST_F(DeltaDiffUtilsTest, XorOpsStrided) {
+ ScopedTempFile patch_file;
+ bsdiff::BsdiffPatchWriter writer{patch_file.path()};
+ ASSERT_TRUE(writer.Init(kBlockSize * 10));
+ ASSERT_TRUE(writer.AddControlEntry(ControlEntry(0, kBlockSize - 456, 123)));
+ ASSERT_TRUE(
+ writer.AddControlEntry(ControlEntry(kBlockSize * 10 + 456, 0, 0)));
+ ASSERT_TRUE(writer.Close());
+
+ std::string patch_data;
+ utils::ReadFile(patch_file.path(), &patch_data);
+
+ AnnotatedOperation aop;
+ *aop.op.add_src_extents() = ExtentForRange(50, 5);
+ *aop.op.add_src_extents() = ExtentForRange(60, 5);
+
+ *aop.op.add_dst_extents() = ExtentForRange(500, 2);
+ *aop.op.add_dst_extents() = ExtentForRange(600, 2);
+ *aop.op.add_dst_extents() = ExtentForRange(700, 7);
+
+ diff_utils::PopulateXorOps(
+ &aop,
+ reinterpret_cast<const uint8_t*>(patch_data.data()),
+ patch_data.size());
+ ASSERT_EQ(aop.xor_ops.size(), 4UL);
+ for (const auto& op : aop.xor_ops) {
+ ASSERT_EQ(op.type(), CowMergeOperation::COW_XOR);
+ }
+ for (const auto& op : aop.xor_ops) {
+ ASSERT_EQ(op.src_offset(), 123UL + 456UL);
+ LOG(INFO) << op.src_extent() << ", " << op.dst_extent();
+ }
+ ASSERT_EQ(aop.xor_ops[0].src_extent().num_blocks(), 2UL);
+ ASSERT_EQ(aop.xor_ops[0].src_extent().start_block(), 50UL);
+
+ ASSERT_EQ(aop.xor_ops[0].dst_extent().num_blocks(), 1UL);
+ ASSERT_EQ(aop.xor_ops[0].dst_extent().start_block(), 501UL);
+
+ ASSERT_EQ(aop.xor_ops[1].src_extent().num_blocks(), 3UL);
+ ASSERT_EQ(aop.xor_ops[1].src_extent().start_block(), 51UL);
+
+ ASSERT_EQ(aop.xor_ops[1].dst_extent().num_blocks(), 2UL);
+ ASSERT_EQ(aop.xor_ops[1].dst_extent().start_block(), 600UL);
+
+ ASSERT_EQ(aop.xor_ops[2].src_extent().num_blocks(), 3UL);
+ ASSERT_EQ(aop.xor_ops[2].src_extent().start_block(), 53UL);
+
+ ASSERT_EQ(aop.xor_ops[2].dst_extent().num_blocks(), 2UL);
+ ASSERT_EQ(aop.xor_ops[2].dst_extent().start_block(), 700UL);
+
+ ASSERT_EQ(aop.xor_ops[3].src_extent().num_blocks(), 6UL);
+ ASSERT_EQ(aop.xor_ops[3].src_extent().start_block(), 60UL);
+
+ ASSERT_EQ(aop.xor_ops[3].dst_extent().num_blocks(), 5UL);
+ ASSERT_EQ(aop.xor_ops[3].dst_extent().start_block(), 702UL);
}
} // namespace chromeos_update_engine
diff --git a/payload_generator/erofs_filesystem.cc b/payload_generator/erofs_filesystem.cc
new file mode 100644
index 00000000..677b473a
--- /dev/null
+++ b/payload_generator/erofs_filesystem.cc
@@ -0,0 +1,241 @@
+//
+// Copyright (C) 2021 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/payload_generator/erofs_filesystem.h"
+
+#include <time.h>
+
+#include <string>
+#include <mutex>
+
+#include <erofs/internal.h>
+#include <erofs/dir.h>
+#include <erofs/io.h>
+
+#include "erofs_iterate.h"
+#include "lz4diff/lz4diff.pb.h"
+#include "lz4diff/lz4patch.h"
+#include "lz4diff/lz4diff.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
+#include "update_engine/payload_generator/extent_utils.h"
+#include "update_engine/payload_generator/filesystem_interface.h"
+
+namespace chromeos_update_engine {
+
+namespace {
+
+static constexpr int GetOccupiedSize(const struct erofs_inode* inode,
+ erofs_off_t* size) {
+ *size = 0;
+ switch (inode->datalayout) {
+ case EROFS_INODE_FLAT_INLINE:
+ case EROFS_INODE_FLAT_PLAIN:
+ case EROFS_INODE_CHUNK_BASED:
+ *size = inode->i_size;
+ break;
+ case EROFS_INODE_FLAT_COMPRESSION_LEGACY:
+ case EROFS_INODE_FLAT_COMPRESSION:
+ *size = inode->u.i_blocks * EROFS_BLKSIZ;
+ break;
+ default:
+ LOG(ERROR) << "unknown datalayout " << inode->datalayout;
+ return -1;
+ }
+ return 0;
+}
+
+static int ErofsMapBlocks(struct erofs_inode* inode,
+ struct erofs_map_blocks* map,
+ int flags) {
+ if (erofs_inode_is_data_compressed(inode->datalayout)) {
+ return z_erofs_map_blocks_iter(inode, map, flags);
+ }
+ return erofs_map_blocks(inode, map, flags);
+}
+
+static constexpr bool IsBlockCompressed(const struct erofs_map_blocks& block) {
+ // Z_EROFS_COMPRESSION_SHIFTED means data inside this block are merely
+ // memmove()'ed in place, instead of going through some compression function
+ // like LZ4 or LZMA
+ return block.m_flags & EROFS_MAP_ENCODED &&
+ block.m_algorithmformat != Z_EROFS_COMPRESSION_SHIFTED;
+}
+
+static void FillCompressedBlockInfo(FilesystemInterface::File* p_file,
+ std::string_view image_filename,
+ struct erofs_inode* inode) {
+ auto& file = *p_file;
+ if (!file.is_compressed) {
+ return;
+ }
+
+ struct erofs_map_blocks block {};
+ block.m_la = 0;
+ block.index = UINT_MAX;
+
+ const erofs_off_t uncompressed_size = file.file_stat.st_size;
+ auto& compressed_blocks = file.compressed_file_info.blocks;
+ auto last_pa = block.m_pa;
+ auto last_plen = 0;
+ while (block.m_la < uncompressed_size) {
+ auto error = ErofsMapBlocks(inode, &block, EROFS_GET_BLOCKS_FIEMAP);
+ if (error) {
+ LOG(FATAL) << "Failed to map blocks for " << file.name << " in "
+ << image_filename;
+ }
+ // Certain uncompressed blocks have physical size > logical size. Usually
+ // the physical block contains bunch of trailing zeros. Include thees
+ // bytes in the logical size as well.
+ if (!IsBlockCompressed(block)) {
+ CHECK_LE(block.m_llen, block.m_plen);
+ block.m_llen = block.m_plen;
+ }
+
+ if (last_pa + last_plen != block.m_pa) {
+ if (last_plen != 0) {
+ file.extents.push_back(ExtentForRange(
+ last_pa / kBlockSize, utils::DivRoundUp(last_plen, kBlockSize)));
+ }
+ last_pa = block.m_pa;
+ last_plen = block.m_plen;
+ } else {
+ last_plen += block.m_plen;
+ }
+ // If logical size and physical size are the same, this block is
+ // uncompressed. Join consecutive uncompressed blocks to save a bit memory
+ // storing metadata.
+ if (block.m_llen == block.m_plen && !compressed_blocks.empty() &&
+ !compressed_blocks.back().IsCompressed()) {
+ compressed_blocks.back().compressed_length += block.m_llen;
+ compressed_blocks.back().uncompressed_length += block.m_llen;
+ } else {
+ compressed_blocks.push_back(
+ CompressedBlock(block.m_la, block.m_plen, block.m_llen));
+ }
+
+ block.m_la += block.m_llen;
+ }
+ file.extents.push_back(ExtentForRange(
+ last_pa / kBlockSize, utils::DivRoundUp(last_plen, kBlockSize)));
+ return;
+}
+
+} // namespace
+
+static_assert(kBlockSize == EROFS_BLKSIZ);
+
+std::unique_ptr<ErofsFilesystem> ErofsFilesystem::CreateFromFile(
+ const std::string& filename, const CompressionAlgorithm& algo) {
+ // erofs-utils makes heavy use of global variables. Hence its functions aren't
+ // thread safe. For example, it stores a global int holding file descriptors
+ // to the opened EROFS image. It doesn't even support opening more than 1
+ // imaeg at a time.
+ // TODO(b/202784930) Replace erofs-utils with a cleaner and more C++ friendly
+ // library. (Or turn erofs-utils into one)
+ static std::mutex m;
+ std::lock_guard g{m};
+
+ if (const auto err = dev_open_ro(filename.c_str()); err) {
+ PLOG(INFO) << "Failed to open " << filename;
+ return nullptr;
+ }
+ DEFER { dev_close(); };
+
+ if (const auto err = erofs_read_superblock(); err) {
+ PLOG(INFO) << "Failed to parse " << filename << " as EROFS image";
+ return nullptr;
+ }
+ struct stat st;
+ if (const auto err = fstat(erofs_devfd, &st); err) {
+ PLOG(ERROR) << "Failed to stat() " << filename;
+ return nullptr;
+ }
+ const time_t time = sbi.build_time;
+ LOG(INFO) << "Parsed EROFS image of size " << st.st_size << " built in "
+ << ctime(&time) << " " << filename;
+ std::vector<File> files;
+ if (!ErofsFilesystem::GetFiles(filename, &files, algo)) {
+ return nullptr;
+ }
+ LOG(INFO) << "Using compression algo " << algo << " for " << filename;
+ // private ctor doesn't work with make_unique
+ return std::unique_ptr<ErofsFilesystem>(
+ new ErofsFilesystem(filename, st.st_size, std::move(files)));
+}
+
+bool ErofsFilesystem::GetFiles(std::vector<File>* files) const {
+ *files = files_;
+ return true;
+}
+
+bool ErofsFilesystem::GetFiles(const std::string& filename,
+ std::vector<File>* files,
+ const CompressionAlgorithm& algo) {
+ erofs_iterate_root_dir(&sbi, [&](struct erofs_iterate_dir_context* p_info) {
+ const auto& info = *p_info;
+ if (info.ctx.de_ftype != EROFS_FT_REG_FILE) {
+ return 0;
+ }
+ struct erofs_inode inode;
+ inode.nid = info.ctx.de_nid;
+ int err = erofs_read_inode_from_disk(&inode);
+ if (err) {
+ LOG(ERROR) << "Failed to read inode " << inode.nid;
+ return err;
+ }
+ const auto uncompressed_size = inode.i_size;
+ erofs_off_t compressed_size = 0;
+ if (uncompressed_size == 0) {
+ return 0;
+ }
+ err = GetOccupiedSize(&inode, &compressed_size);
+ if (err) {
+ LOG(FATAL) << "Failed to get occupied size for " << filename;
+ return err;
+ }
+ // If data is packed inline, likely this node is stored on block unalighed
+ // addresses. OTA doesn't work for non-block aligned files. All blocks not
+ // reported by |GetFiles| will be updated in 1 operation. Ignore inline
+ // files for now.
+ // TODO(b/206729162) Support un-aligned files.
+ if (inode.datalayout == EROFS_INODE_FLAT_INLINE) {
+ return 0;
+ }
+
+ File file;
+ file.name = info.path;
+ file.compressed_file_info.zero_padding_enabled =
+ erofs_sb_has_lz4_0padding();
+ file.is_compressed = compressed_size != uncompressed_size;
+
+ file.file_stat.st_size = uncompressed_size;
+ file.file_stat.st_ino = inode.nid;
+ FillCompressedBlockInfo(&file, filename, &inode);
+ file.compressed_file_info.algo = algo;
+
+ files->emplace_back(std::move(file));
+ return 0;
+ });
+
+ for (auto& file : *files) {
+ NormalizeExtents(&file.extents);
+ }
+ return true;
+}
+
+} // namespace chromeos_update_engine \ No newline at end of file
diff --git a/payload_generator/erofs_filesystem.h b/payload_generator/erofs_filesystem.h
new file mode 100644
index 00000000..0863b50f
--- /dev/null
+++ b/payload_generator/erofs_filesystem.h
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2021 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_PAYLOAD_GENERATOR_EROFS_FILESYSTEM_H_
+#define UPDATE_ENGINE_PAYLOAD_GENERATOR_EROFS_FILESYSTEM_H_
+
+#include "update_engine/payload_generator/filesystem_interface.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
+
+namespace chromeos_update_engine {
+
+class ErofsFilesystem final : public FilesystemInterface {
+ public:
+ // Creates an ErofsFilesystem from a erofs formatted filesystem stored in a
+ // file. The file doesn't need to be loop-back mounted. Since erofs-utils
+ // library functions are not concurrency safe(can't be used in multi-threaded
+ // context, can't even work with multiple EROFS images concurrently on 1
+ // thread), this function takes a global mutex.
+ static std::unique_ptr<ErofsFilesystem> CreateFromFile(
+ const std::string& filename,
+ const CompressionAlgorithm& algo =
+ PartitionConfig::GetDefaultCompressionParam());
+ virtual ~ErofsFilesystem() = default;
+
+ // FilesystemInterface overrides.
+ size_t GetBlockSize() const override { return kBlockSize; }
+ size_t GetBlockCount() const override { return fs_size_ / kBlockSize; }
+
+ // GetFiles will return one FilesystemInterface::File for every file and every
+ // directory in the filesystem. Hard-linked files will appear in the list
+ // several times with the same list of blocks.
+ // On addition to actual files, it also returns these pseudo-files:
+ // <free-space>: With all the unallocated data-blocks.
+ // <inode-blocks>: Will all the data-blocks for second and third level inodes
+ // of all the files.
+ // <group-descriptors>: With the block group descriptor and their reserved
+ // space.
+ // <metadata>: With the rest of ext2 metadata blocks, such as superblocks
+ // and bitmap tables.
+ static bool GetFiles(const std::string& filename,
+ std::vector<File>* files,
+ const CompressionAlgorithm& algo);
+
+ bool GetFiles(std::vector<File>* files) const override;
+
+ bool LoadSettings(
+ [[maybe_unused]] brillo::KeyValueStore* store) const override {
+ return true;
+ }
+
+ private:
+ ErofsFilesystem(std::string filename, size_t fs_size, std::vector<File> files)
+ : filename_(filename), fs_size_(fs_size), files_(std::move(files)) {}
+
+ // The file where the filesystem is stored.
+ const std::string filename_;
+ const size_t fs_size_;
+ const std::vector<File> files_;
+}; // namespace chromeos_update_engine
+
+} // namespace chromeos_update_engine
+
+#endif \ No newline at end of file
diff --git a/payload_generator/erofs_filesystem_unittest.cc b/payload_generator/erofs_filesystem_unittest.cc
new file mode 100644
index 00000000..e6a89291
--- /dev/null
+++ b/payload_generator/erofs_filesystem_unittest.cc
@@ -0,0 +1,127 @@
+//
+// Copyright (C) 2021 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/payload_generator/erofs_filesystem.h"
+
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+#include <base/format_macros.h>
+#include <base/logging.h>
+#include <base/strings/string_number_conversions.h>
+#include <base/strings/string_util.h>
+#include <base/strings/stringprintf.h>
+#include <gtest/gtest.h>
+
+#include "payload_generator/delta_diff_generator.h"
+#include "update_engine/common/test_utils.h"
+#include "update_engine/common/utils.h"
+#include "update_engine/payload_generator/extent_utils.h"
+
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+namespace {
+
+class ErofsFilesystemTest : public ::testing::Test {};
+
+} // namespace
+
+namespace chromeos_update_engine {
+
+using test_utils::GetBuildArtifactsPath;
+
+TEST_F(ErofsFilesystemTest, InvalidFilesystem) {
+ ScopedTempFile fs_filename_{"ErofsFilesystemTest-XXXXXX"};
+ ASSERT_EQ(0, truncate(fs_filename_.path().c_str(), kBlockSize));
+ unique_ptr<ErofsFilesystem> fs =
+ ErofsFilesystem::CreateFromFile(fs_filename_.path());
+ ASSERT_EQ(nullptr, fs.get());
+
+ fs = ErofsFilesystem::CreateFromFile("/path/to/invalid/file");
+ ASSERT_EQ(nullptr, fs.get());
+}
+
+TEST_F(ErofsFilesystemTest, EmptyFilesystem) {
+ unique_ptr<ErofsFilesystem> fs = ErofsFilesystem::CreateFromFile(
+ GetBuildArtifactsPath("gen/erofs_empty.img"));
+
+ ASSERT_NE(nullptr, fs);
+ ASSERT_EQ(kBlockSize, fs->GetBlockSize());
+
+ vector<FilesystemInterface::File> files;
+ ASSERT_TRUE(fs->GetFiles(&files));
+ ASSERT_EQ(files.size(), 0UL);
+}
+
+// This test parses the sample images generated during build time with the
+// "generate_image.sh" script. The expected conditions of each file in these
+// images is encoded in the file name, as defined in the mentioned script.
+TEST_F(ErofsFilesystemTest, ParseGeneratedImages) {
+ const auto build_path = GetBuildArtifactsPath("gen/erofs.img");
+ auto fs = ErofsFilesystem::CreateFromFile(build_path);
+ ASSERT_NE(fs, nullptr);
+ ASSERT_EQ(kBlockSize, fs->GetBlockSize());
+
+ vector<ErofsFilesystem::File> files;
+ ASSERT_TRUE(fs->GetFiles(&files));
+
+ std::sort(files.begin(), files.end(), [](const auto& a, const auto& b) {
+ return a.name < b.name;
+ });
+ vector<string> filenames;
+ filenames.resize(files.size());
+ std::transform(
+ files.begin(), files.end(), filenames.begin(), [](const auto& file) {
+ return file.name;
+ });
+ const std::vector<std::string> expected_filenames = {
+ "/delta_generator",
+ "/dir1/dir2/dir123/chunks_of_zero",
+ // Empty files are ignored
+ // "/dir1/dir2/dir123/empty",
+ "/dir1/dir2/file0",
+ "/dir1/dir2/file1",
+ "/dir1/dir2/file2",
+ "/dir1/dir2/file4",
+ "/dir1/file0",
+ "/dir1/file2",
+ "/file1",
+ // Files < 4K are stored inline, and therefore ignored, as they are often
+ // stored not on block boundary.
+ // "/generate_test_erofs_images.sh"
+ };
+ ASSERT_EQ(filenames, expected_filenames);
+ const auto delta_generator = files[0];
+ ASSERT_GT(delta_generator.compressed_file_info.blocks.size(), 0UL);
+ size_t compressed_size = 0;
+ size_t uncompressed_size = 0;
+ for (const auto& block : delta_generator.compressed_file_info.blocks) {
+ compressed_size += block.compressed_length;
+ uncompressed_size += block.uncompressed_length;
+ }
+ ASSERT_GE(uncompressed_size,
+ static_cast<size_t>(delta_generator.file_stat.st_size))
+ << "Uncompressed data should be at least as big as original file, plus "
+ "possible trailing data.";
+ const auto total_blocks = utils::BlocksInExtents(delta_generator.extents);
+ ASSERT_EQ(compressed_size, total_blocks * kBlockSize);
+}
+
+} // namespace chromeos_update_engine
diff --git a/payload_generator/erofs_iterate.h b/payload_generator/erofs_iterate.h
new file mode 100644
index 00000000..ac9d67e1
--- /dev/null
+++ b/payload_generator/erofs_iterate.h
@@ -0,0 +1,76 @@
+//
+// Copyright (C) 2021 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 <string>
+
+#include <erofs/dir.h>
+
+#include "update_engine/common/utils.h"
+
+// The only way to pass extra information to callback function is to use a
+// wrapper type for erofs_dir_context. So here we go
+struct erofs_iterate_dir_context {
+ struct erofs_dir_context ctx;
+ std::string path;
+ void* arg;
+};
+
+// Dear compiler, please don't reoder fields inside erofs_iterate_dir_context.
+// Because EROFS expects us to pass a wrapper type. So |ctx| member of
+// erofs_iterate_dir_context must be put at 0 offset.
+static_assert(offsetof(erofs_iterate_dir_context, ctx) == 0);
+
+// Callable shold be a functor like
+// std::function<int(struct erofs_inode_info *)>
+template <typename Callable>
+int erofs_iterate_root_dir(const struct erofs_sb_info* sbi, Callable cb) {
+ struct erofs_inode dir {
+ .nid = sbi->root_nid
+ };
+ int err = erofs_read_inode_from_disk(&dir);
+ if (err) {
+ LOG(ERROR) << "Failed to read inode " << sbi->root_nid << " from disk";
+ return err;
+ }
+ struct erofs_iterate_dir_context param {
+ .ctx.dir = &dir, .ctx.pnid = sbi->root_nid,
+ .ctx.cb = [](struct erofs_dir_context* arg) -> int {
+ auto ctx = reinterpret_cast<erofs_iterate_dir_context*>(arg);
+ auto& path = ctx->path;
+ const auto len = path.size();
+ path.push_back('/');
+ path.insert(
+ path.end(), ctx->ctx.dname, ctx->ctx.dname + ctx->ctx.de_namelen);
+ auto cb = static_cast<Callable*>(ctx->arg);
+ const auto err = (*cb)(ctx);
+ if (!err && !ctx->ctx.dot_dotdot && ctx->ctx.de_ftype == EROFS_FT_DIR) {
+ // recursively walk into subdirectories
+ erofs_inode dir{.nid = ctx->ctx.de_nid};
+ if (const int err = erofs_read_inode_from_disk(&dir); err) {
+ return err;
+ }
+ ctx->ctx.dir = &dir;
+ if (const auto err = erofs_iterate_dir(&ctx->ctx, false); err) {
+ return err;
+ }
+ }
+ path.resize(len);
+ return err;
+ },
+ .arg = &cb,
+ };
+ return erofs_iterate_dir(&param.ctx, false);
+}
diff --git a/payload_generator/ext2_filesystem_unittest.cc b/payload_generator/ext2_filesystem_unittest.cc
index 88e15383..8fa5080e 100644
--- a/payload_generator/ext2_filesystem_unittest.cc
+++ b/payload_generator/ext2_filesystem_unittest.cc
@@ -57,10 +57,10 @@ void ExpectBlocksInRange(const vector<Extent>& extents, uint64_t total_blocks) {
}
}
-} // namespace
-
class Ext2FilesystemTest : public ::testing::Test {};
+} // namespace
+
TEST_F(Ext2FilesystemTest, InvalidFilesystem) {
ScopedTempFile fs_filename_{"Ext2FilesystemTest-XXXXXX"};
ASSERT_EQ(0, truncate(fs_filename_.path().c_str(), kDefaultFilesystemSize));
diff --git a/payload_generator/extent_ranges.cc b/payload_generator/extent_ranges.cc
index 2098639b..eecc8b32 100644
--- a/payload_generator/extent_ranges.cc
+++ b/payload_generator/extent_ranges.cc
@@ -45,7 +45,7 @@ bool ExtentRanges::ExtentsOverlapOrTouch(const Extent& a, const Extent& b) {
bool ExtentRanges::ExtentsOverlap(const Extent& a, const Extent& b) {
if (a.start_block() == b.start_block())
- return true;
+ return a.num_blocks() != 0;
if (a.start_block() == kSparseHole || b.start_block() == kSparseHole)
return false;
if (a.start_block() < b.start_block()) {
@@ -56,6 +56,7 @@ bool ExtentRanges::ExtentsOverlap(const Extent& a, const Extent& b) {
}
void ExtentRanges::AddBlock(uint64_t block) {
+ // Remember to respect |merge_touching_extents_| setting
AddExtent(ExtentForRange(block, 1));
}
@@ -86,7 +87,10 @@ void ExtentRanges::AddExtent(Extent extent) {
for (ExtentSet::iterator it = extent_set_.begin(), e = extent_set_.end();
it != e;
++it) {
- if (ExtentsOverlapOrTouch(*it, extent)) {
+ const bool should_merge = merge_touching_extents_
+ ? ExtentsOverlapOrTouch(*it, extent)
+ : ExtentsOverlap(*it, extent);
+ if (should_merge) {
end_del = it;
++end_del;
del_blocks += it->num_blocks();
@@ -155,6 +159,7 @@ void ExtentRanges::SubtractExtent(const Extent& extent) {
}
void ExtentRanges::AddRanges(const ExtentRanges& ranges) {
+ // Remember to respect |merge_touching_extents_| setting
for (ExtentSet::const_iterator it = ranges.extent_set_.begin(),
e = ranges.extent_set_.end();
it != e;
@@ -173,6 +178,7 @@ void ExtentRanges::SubtractRanges(const ExtentRanges& ranges) {
}
void ExtentRanges::AddExtents(const vector<Extent>& extents) {
+ // Remember to respect |merge_touching_extents_| setting
for (vector<Extent>::const_iterator it = extents.begin(), e = extents.end();
it != e;
++it) {
@@ -190,6 +196,7 @@ void ExtentRanges::SubtractExtents(const vector<Extent>& extents) {
void ExtentRanges::AddRepeatedExtents(
const ::google::protobuf::RepeatedPtrField<Extent>& exts) {
+ // Remember to respect |merge_touching_extents_| setting
for (int i = 0, e = exts.size(); i != e; ++i) {
AddExtent(exts.Get(i));
}
@@ -203,7 +210,7 @@ void ExtentRanges::SubtractRepeatedExtents(
}
bool ExtentRanges::OverlapsWithExtent(const Extent& extent) const {
- for (const auto& entry : extent_set_) {
+ for (const auto& entry : GetCandidateRange(extent)) {
if (ExtentsOverlap(entry, extent)) {
return true;
}
@@ -281,6 +288,31 @@ vector<Extent> ExtentRanges::GetExtentsForBlockCount(uint64_t count) const {
return out;
}
+Range<ExtentRanges::ExtentSet::const_iterator> ExtentRanges::GetCandidateRange(
+ const Extent& extent) const {
+ auto lower_it = extent_set_.lower_bound(extent);
+ if (lower_it != extent_set_.begin()) {
+ --lower_it;
+ }
+
+ const auto upper_it = extent_set_.upper_bound(
+ ExtentForRange(extent.start_block() + extent.num_blocks(), 1));
+ return {lower_it, upper_it};
+}
+
+std::vector<Extent> ExtentRanges::GetIntersectingExtents(
+ const Extent& extent) const {
+ const auto candidates = GetCandidateRange(extent);
+ std::vector<Extent> result;
+ for (const auto& ext : candidates) {
+ if (auto intersection = GetOverlapExtent(ext, extent);
+ intersection.num_blocks() != 0) {
+ result.emplace_back(std::move(intersection));
+ }
+ }
+ return result;
+}
+
vector<Extent> FilterExtentRanges(const vector<Extent>& extents,
const ExtentRanges& ranges) {
vector<Extent> result;
@@ -331,4 +363,15 @@ vector<Extent> FilterExtentRanges(const vector<Extent>& extents,
return result;
}
+Extent GetOverlapExtent(const Extent& extent1, const Extent& extent2) {
+ if (!ExtentRanges::ExtentsOverlap(extent1, extent2)) {
+ return {};
+ }
+ const auto start_block =
+ std::max(extent1.start_block(), extent2.start_block());
+ const auto end_block = std::min(extent1.start_block() + extent1.num_blocks(),
+ extent2.start_block() + extent2.num_blocks());
+ return ExtentForRange(start_block, end_block - start_block);
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_generator/extent_ranges.h b/payload_generator/extent_ranges.h
index 68aa27f8..08cf5fe1 100644
--- a/payload_generator/extent_ranges.h
+++ b/payload_generator/extent_ranges.h
@@ -23,6 +23,7 @@
#include <base/macros.h>
+#include "update_engine/common/utils.h"
#include "update_engine/update_metadata.pb.h"
// An ExtentRanges object represents an unordered collection of extents (and
@@ -36,6 +37,9 @@ namespace chromeos_update_engine {
struct ExtentLess {
bool operator()(const Extent& x, const Extent& y) const {
+ if (x.start_block() == y.start_block()) {
+ return x.num_blocks() < y.num_blocks();
+ }
return x.start_block() < y.start_block();
}
};
@@ -49,7 +53,14 @@ class ExtentRanges {
public:
typedef std::set<Extent, ExtentLess> ExtentSet;
- ExtentRanges() : blocks_(0) {}
+ ExtentRanges() = default;
+ // When |merge_touching_extents| is set to false, extents that are only
+ // touching but not overlapping won't be merged. This slightly decreases
+ // space/time efficiency, but should not impact correctness.
+ // Only intended usecase is for VABC XOR.
+ // E.g. [5-9] and [10-14] will be merged iff |merge_touching_extents| is true
+ explicit ExtentRanges(bool merge_touching_extents)
+ : merge_touching_extents_(merge_touching_extents) {}
void AddBlock(uint64_t block);
void SubtractBlock(uint64_t block);
void AddExtent(Extent extent);
@@ -84,9 +95,22 @@ class ExtentRanges {
// the number of blocks in this extent set.
std::vector<Extent> GetExtentsForBlockCount(uint64_t count) const;
+ // Compute the intersection between this ExtentRange and the |extent|
+ // parameter. Return results in a vector. If there's no intersection, an empty
+ // vector is returned.
+ std::vector<Extent> GetIntersectingExtents(const Extent& extent) const;
+
+ // Get a range of extents that possibly intersect with |extent|. (Returned
+ // extents do not necessarily intersect!). It is perfectly acceptable to just
+ // return all extents in this set, though more efficient solution using binary
+ // search is preferred.
+ Range<ExtentSet::const_iterator> GetCandidateRange(
+ const Extent& extent) const;
+
private:
ExtentSet extent_set_;
- uint64_t blocks_;
+ uint64_t blocks_ = 0;
+ bool merge_touching_extents_ = true;
};
// Filters out from the passed list of extents |extents| all the blocks in the
@@ -95,6 +119,8 @@ class ExtentRanges {
std::vector<Extent> FilterExtentRanges(const std::vector<Extent>& extents,
const ExtentRanges& ranges);
+Extent GetOverlapExtent(const Extent& extent1, const Extent& extent2);
+
} // namespace chromeos_update_engine
#endif // UPDATE_ENGINE_PAYLOAD_GENERATOR_EXTENT_RANGES_H_
diff --git a/payload_generator/extent_ranges_unittest.cc b/payload_generator/extent_ranges_unittest.cc
index f55bb737..f7a4cd22 100644
--- a/payload_generator/extent_ranges_unittest.cc
+++ b/payload_generator/extent_ranges_unittest.cc
@@ -40,30 +40,28 @@ void ExpectRangeEq(const ExtentRanges& ranges,
for (size_t i = 1; i < sz; i += 2) {
blocks += expected[i];
}
- EXPECT_EQ(blocks, ranges.blocks()) << "line: " << line;
+ ASSERT_EQ(blocks, ranges.blocks()) << "line: " << line;
const ExtentRanges::ExtentSet& result = ranges.extent_set();
ExtentRanges::ExtentSet::const_iterator it = result.begin();
for (size_t i = 0; i < sz; i += 2) {
- EXPECT_FALSE(it == result.end()) << "line: " << line;
- EXPECT_EQ(expected[i], it->start_block()) << "line: " << line;
- EXPECT_EQ(expected[i + 1], it->num_blocks()) << "line: " << line;
+ ASSERT_FALSE(it == result.end()) << "line: " << line;
+ ASSERT_EQ(expected[i], it->start_block()) << "line: " << line;
+ ASSERT_EQ(expected[i + 1], it->num_blocks()) << "line: " << line;
++it;
}
}
-#define EXPECT_RANGE_EQ(ranges, var) \
- do { \
- ExpectRangeEq(ranges, var, base::size(var), __LINE__); \
- } while (0)
+#define ASSERT_RANGE_EQ(ranges, var) \
+ ASSERT_NO_FATAL_FAILURE(ExpectRangeEq(ranges, var, base::size(var), __LINE__))
void ExpectRangesOverlapOrTouch(uint64_t a_start,
uint64_t a_num,
uint64_t b_start,
uint64_t b_num) {
- EXPECT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
+ ASSERT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
ExtentForRange(a_start, a_num), ExtentForRange(b_start, b_num)));
- EXPECT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
+ ASSERT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
ExtentForRange(b_start, b_num), ExtentForRange(a_start, a_num)));
}
@@ -71,13 +69,13 @@ void ExpectFalseRangesOverlapOrTouch(uint64_t a_start,
uint64_t a_num,
uint64_t b_start,
uint64_t b_num) {
- EXPECT_FALSE(ExtentRanges::ExtentsOverlapOrTouch(
+ ASSERT_FALSE(ExtentRanges::ExtentsOverlapOrTouch(
ExtentForRange(a_start, a_num), ExtentForRange(b_start, b_num)));
- EXPECT_FALSE(ExtentRanges::ExtentsOverlapOrTouch(
+ ASSERT_FALSE(ExtentRanges::ExtentsOverlapOrTouch(
ExtentForRange(b_start, b_num), ExtentForRange(a_start, a_num)));
- EXPECT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(a_start, a_num),
+ ASSERT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(a_start, a_num),
ExtentForRange(b_start, b_num)));
- EXPECT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(b_start, b_num),
+ ASSERT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(b_start, b_num),
ExtentForRange(a_start, a_num)));
}
@@ -85,13 +83,13 @@ void ExpectRangesOverlap(uint64_t a_start,
uint64_t a_num,
uint64_t b_start,
uint64_t b_num) {
- EXPECT_TRUE(ExtentRanges::ExtentsOverlap(ExtentForRange(a_start, a_num),
+ ASSERT_TRUE(ExtentRanges::ExtentsOverlap(ExtentForRange(a_start, a_num),
ExtentForRange(b_start, b_num)));
- EXPECT_TRUE(ExtentRanges::ExtentsOverlap(ExtentForRange(b_start, b_num),
+ ASSERT_TRUE(ExtentRanges::ExtentsOverlap(ExtentForRange(b_start, b_num),
ExtentForRange(a_start, a_num)));
- EXPECT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
+ ASSERT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
ExtentForRange(a_start, a_num), ExtentForRange(b_start, b_num)));
- EXPECT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
+ ASSERT_TRUE(ExtentRanges::ExtentsOverlapOrTouch(
ExtentForRange(b_start, b_num), ExtentForRange(a_start, a_num)));
}
@@ -99,41 +97,44 @@ void ExpectFalseRangesOverlap(uint64_t a_start,
uint64_t a_num,
uint64_t b_start,
uint64_t b_num) {
- EXPECT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(a_start, a_num),
+ ASSERT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(a_start, a_num),
ExtentForRange(b_start, b_num)));
- EXPECT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(b_start, b_num),
+ ASSERT_FALSE(ExtentRanges::ExtentsOverlap(ExtentForRange(b_start, b_num),
ExtentForRange(a_start, a_num)));
}
} // namespace
TEST(ExtentRangesTest, ExtentsOverlapTest) {
- ExpectRangesOverlapOrTouch(10, 20, 30, 10);
- ExpectRangesOverlap(10, 20, 25, 10);
- ExpectFalseRangesOverlapOrTouch(10, 20, 35, 10);
- ExpectFalseRangesOverlap(10, 20, 30, 10);
- ExpectRangesOverlap(12, 4, 12, 3);
-
- ExpectRangesOverlapOrTouch(kSparseHole, 2, kSparseHole, 3);
- ExpectRangesOverlap(kSparseHole, 2, kSparseHole, 3);
- ExpectFalseRangesOverlapOrTouch(kSparseHole, 2, 10, 3);
- ExpectFalseRangesOverlapOrTouch(10, 2, kSparseHole, 3);
- ExpectFalseRangesOverlap(kSparseHole, 2, 10, 3);
- ExpectFalseRangesOverlap(10, 2, kSparseHole, 3);
+ ASSERT_NO_FATAL_FAILURE(ExpectRangesOverlapOrTouch(10, 20, 30, 10));
+ ASSERT_NO_FATAL_FAILURE(ExpectRangesOverlap(10, 20, 25, 10));
+ ASSERT_NO_FATAL_FAILURE(ExpectFalseRangesOverlapOrTouch(10, 20, 35, 10));
+ ASSERT_NO_FATAL_FAILURE(ExpectFalseRangesOverlap(10, 20, 30, 10));
+ ASSERT_NO_FATAL_FAILURE(ExpectRangesOverlap(12, 4, 12, 3));
+
+ ASSERT_NO_FATAL_FAILURE(
+ ExpectRangesOverlapOrTouch(kSparseHole, 2, kSparseHole, 3));
+ ASSERT_NO_FATAL_FAILURE(ExpectRangesOverlap(kSparseHole, 2, kSparseHole, 3));
+ ASSERT_NO_FATAL_FAILURE(
+ ExpectFalseRangesOverlapOrTouch(kSparseHole, 2, 10, 3));
+ ASSERT_NO_FATAL_FAILURE(
+ ExpectFalseRangesOverlapOrTouch(10, 2, kSparseHole, 3));
+ ASSERT_NO_FATAL_FAILURE(ExpectFalseRangesOverlap(kSparseHole, 2, 10, 3));
+ ASSERT_NO_FATAL_FAILURE(ExpectFalseRangesOverlap(10, 2, kSparseHole, 3));
}
TEST(ExtentRangesTest, SimpleTest) {
ExtentRanges ranges;
{
- static const uint64_t expected[] = {};
+ static constexpr uint64_t expected[] = {};
// Can't use arraysize() on 0-length arrays:
- ExpectRangeEq(ranges, expected, 0, __LINE__);
+ ASSERT_NO_FATAL_FAILURE(ExpectRangeEq(ranges, expected, 0, __LINE__));
}
ranges.SubtractBlock(2);
{
- static const uint64_t expected[] = {};
+ static constexpr uint64_t expected[] = {};
// Can't use arraysize() on 0-length arrays:
- ExpectRangeEq(ranges, expected, 0, __LINE__);
+ ASSERT_NO_FATAL_FAILURE(ExpectRangeEq(ranges, expected, 0, __LINE__));
}
ranges.AddBlock(0);
@@ -142,54 +143,54 @@ TEST(ExtentRangesTest, SimpleTest) {
ranges.AddBlock(3);
{
- static const uint64_t expected[] = {0, 2, 3, 1};
- EXPECT_RANGE_EQ(ranges, expected);
+ static constexpr uint64_t expected[] = {0, 2, 3, 1};
+ ASSERT_RANGE_EQ(ranges, expected);
}
ranges.AddBlock(2);
{
- static const uint64_t expected[] = {0, 4};
- EXPECT_RANGE_EQ(ranges, expected);
+ static constexpr uint64_t expected[] = {0, 4};
+ ASSERT_RANGE_EQ(ranges, expected);
ranges.AddBlock(kSparseHole);
- EXPECT_RANGE_EQ(ranges, expected);
+ ASSERT_RANGE_EQ(ranges, expected);
ranges.SubtractBlock(kSparseHole);
- EXPECT_RANGE_EQ(ranges, expected);
+ ASSERT_RANGE_EQ(ranges, expected);
}
ranges.SubtractBlock(2);
{
- static const uint64_t expected[] = {0, 2, 3, 1};
- EXPECT_RANGE_EQ(ranges, expected);
+ static constexpr uint64_t expected[] = {0, 2, 3, 1};
+ ASSERT_RANGE_EQ(ranges, expected);
}
for (uint64_t i = 100; i < 1000; i += 100) {
ranges.AddExtent(ExtentForRange(i, 50));
}
{
- static const uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200, 50,
- 300, 50, 400, 50, 500, 50, 600, 50,
- 700, 50, 800, 50, 900, 50};
- EXPECT_RANGE_EQ(ranges, expected);
+ static constexpr uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200, 50,
+ 300, 50, 400, 50, 500, 50, 600, 50,
+ 700, 50, 800, 50, 900, 50};
+ ASSERT_RANGE_EQ(ranges, expected);
}
ranges.SubtractExtent(ExtentForRange(210, 410 - 210));
{
- static const uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200,
- 10, 410, 40, 500, 50, 600, 50,
- 700, 50, 800, 50, 900, 50};
- EXPECT_RANGE_EQ(ranges, expected);
+ static constexpr uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200,
+ 10, 410, 40, 500, 50, 600, 50,
+ 700, 50, 800, 50, 900, 50};
+ ASSERT_RANGE_EQ(ranges, expected);
}
ranges.AddExtent(ExtentForRange(100000, 0));
{
- static const uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200,
- 10, 410, 40, 500, 50, 600, 50,
- 700, 50, 800, 50, 900, 50};
- EXPECT_RANGE_EQ(ranges, expected);
+ static constexpr uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200,
+ 10, 410, 40, 500, 50, 600, 50,
+ 700, 50, 800, 50, 900, 50};
+ ASSERT_RANGE_EQ(ranges, expected);
}
ranges.SubtractExtent(ExtentForRange(3, 0));
{
- static const uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200,
- 10, 410, 40, 500, 50, 600, 50,
- 700, 50, 800, 50, 900, 50};
- EXPECT_RANGE_EQ(ranges, expected);
+ static constexpr uint64_t expected[] = {0, 2, 3, 1, 100, 50, 200,
+ 10, 410, 40, 500, 50, 600, 50,
+ 700, 50, 800, 50, 900, 50};
+ ASSERT_RANGE_EQ(ranges, expected);
}
}
@@ -199,22 +200,22 @@ TEST(ExtentRangesTest, MultipleRanges) {
ranges_b.AddBlock(4);
ranges_b.AddBlock(3);
{
- uint64_t expected[] = {3, 2};
- EXPECT_RANGE_EQ(ranges_b, expected);
+ constexpr uint64_t expected[] = {3, 2};
+ ASSERT_RANGE_EQ(ranges_b, expected);
}
ranges_a.AddRanges(ranges_b);
{
- uint64_t expected[] = {0, 1, 3, 2};
- EXPECT_RANGE_EQ(ranges_a, expected);
+ constexpr uint64_t expected[] = {0, 1, 3, 2};
+ ASSERT_RANGE_EQ(ranges_a, expected);
}
ranges_a.SubtractRanges(ranges_b);
{
- uint64_t expected[] = {0, 1};
- EXPECT_RANGE_EQ(ranges_a, expected);
+ constexpr uint64_t expected[] = {0, 1};
+ ASSERT_RANGE_EQ(ranges_a, expected);
}
{
- uint64_t expected[] = {3, 2};
- EXPECT_RANGE_EQ(ranges_b, expected);
+ constexpr uint64_t expected[] = {3, 2};
+ ASSERT_RANGE_EQ(ranges_b, expected);
}
}
@@ -223,7 +224,7 @@ TEST(ExtentRangesTest, GetExtentsForBlockCountTest) {
ranges.AddExtents(vector<Extent>(1, ExtentForRange(10, 30)));
{
vector<Extent> zero_extents = ranges.GetExtentsForBlockCount(0);
- EXPECT_TRUE(zero_extents.empty());
+ ASSERT_TRUE(zero_extents.empty());
}
::google::protobuf::RepeatedPtrField<Extent> rep_field;
*rep_field.Add() = ExtentForRange(30, 40);
@@ -231,7 +232,7 @@ TEST(ExtentRangesTest, GetExtentsForBlockCountTest) {
ranges.SubtractExtents(vector<Extent>(1, ExtentForRange(20, 10)));
*rep_field.Mutable(0) = ExtentForRange(50, 10);
ranges.SubtractRepeatedExtents(rep_field);
- EXPECT_EQ(40U, ranges.blocks());
+ ASSERT_EQ(40U, ranges.blocks());
for (int i = 0; i < 2; i++) {
vector<Extent> expected(2);
@@ -239,11 +240,11 @@ TEST(ExtentRangesTest, GetExtentsForBlockCountTest) {
expected[1] = ExtentForRange(30, i == 0 ? 10 : 20);
vector<Extent> actual =
ranges.GetExtentsForBlockCount(10 + expected[1].num_blocks());
- EXPECT_EQ(expected.size(), actual.size());
+ ASSERT_EQ(expected.size(), actual.size());
for (vector<Extent>::size_type j = 0, e = expected.size(); j != e; ++j) {
- EXPECT_EQ(expected[j].start_block(), actual[j].start_block())
+ ASSERT_EQ(expected[j].start_block(), actual[j].start_block())
<< "j = " << j;
- EXPECT_EQ(expected[j].num_blocks(), actual[j].num_blocks())
+ ASSERT_EQ(expected[j].num_blocks(), actual[j].num_blocks())
<< "j = " << j;
}
}
@@ -251,30 +252,30 @@ TEST(ExtentRangesTest, GetExtentsForBlockCountTest) {
TEST(ExtentRangesTest, ContainsBlockTest) {
ExtentRanges ranges;
- EXPECT_FALSE(ranges.ContainsBlock(123));
+ ASSERT_FALSE(ranges.ContainsBlock(123));
ranges.AddExtent(ExtentForRange(10, 10));
ranges.AddExtent(ExtentForRange(100, 1));
- EXPECT_FALSE(ranges.ContainsBlock(9));
- EXPECT_TRUE(ranges.ContainsBlock(10));
- EXPECT_TRUE(ranges.ContainsBlock(15));
- EXPECT_TRUE(ranges.ContainsBlock(19));
- EXPECT_FALSE(ranges.ContainsBlock(20));
+ ASSERT_FALSE(ranges.ContainsBlock(9));
+ ASSERT_TRUE(ranges.ContainsBlock(10));
+ ASSERT_TRUE(ranges.ContainsBlock(15));
+ ASSERT_TRUE(ranges.ContainsBlock(19));
+ ASSERT_FALSE(ranges.ContainsBlock(20));
// Test for an extent with just the block we are requesting.
- EXPECT_FALSE(ranges.ContainsBlock(99));
- EXPECT_TRUE(ranges.ContainsBlock(100));
- EXPECT_FALSE(ranges.ContainsBlock(101));
+ ASSERT_FALSE(ranges.ContainsBlock(99));
+ ASSERT_TRUE(ranges.ContainsBlock(100));
+ ASSERT_FALSE(ranges.ContainsBlock(101));
}
TEST(ExtentRangesTest, FilterExtentRangesEmptyRanges) {
ExtentRanges ranges;
- EXPECT_EQ(vector<Extent>(), FilterExtentRanges(vector<Extent>(), ranges));
- EXPECT_EQ(vector<Extent>{ExtentForRange(50, 10)},
+ ASSERT_EQ(vector<Extent>(), FilterExtentRanges(vector<Extent>(), ranges));
+ ASSERT_EQ(vector<Extent>{ExtentForRange(50, 10)},
FilterExtentRanges(vector<Extent>{ExtentForRange(50, 10)}, ranges));
// Check that the empty Extents are ignored.
- EXPECT_EQ((vector<Extent>{ExtentForRange(10, 10), ExtentForRange(20, 10)}),
+ ASSERT_EQ((vector<Extent>{ExtentForRange(10, 10), ExtentForRange(20, 10)}),
FilterExtentRanges(vector<Extent>{ExtentForRange(10, 10),
ExtentForRange(3, 0),
ExtentForRange(20, 10)},
@@ -291,7 +292,7 @@ TEST(ExtentRangesTest, FilterExtentRangesMultipleRanges) {
ranges.AddExtent(ExtentForRange(70, 10));
// This overlaps the end of the second extent.
ranges.AddExtent(ExtentForRange(108, 6));
- EXPECT_EQ((vector<Extent>{// For the first extent:
+ ASSERT_EQ((vector<Extent>{// For the first extent:
ExtentForRange(10, 18),
ExtentForRange(31, 19),
ExtentForRange(60, 10),
@@ -309,10 +310,84 @@ TEST(ExtentRangesTest, FilterExtentRangesOvelapping) {
ranges.AddExtent(ExtentForRange(10, 3));
ranges.AddExtent(ExtentForRange(20, 5));
// Requested extent overlaps with one of the ranges.
- EXPECT_EQ(vector<Extent>(),
+ ASSERT_EQ(vector<Extent>(),
FilterExtentRanges(
vector<Extent>{ExtentForRange(10, 1), ExtentForRange(22, 1)},
ranges));
}
+TEST(ExtentRangesTest, GetOverlapExtent) {
+ const auto ret1 =
+ GetOverlapExtent(ExtentForRange(5, 5), ExtentForRange(10, 10));
+ ASSERT_EQ(ret1.num_blocks(), 0UL) << ret1;
+ const auto ret2 =
+ GetOverlapExtent(ExtentForRange(5, 5), ExtentForRange(9, 10));
+ ASSERT_EQ(ret2, ExtentForRange(9, 1));
+
+ const auto ret3 =
+ GetOverlapExtent(ExtentForRange(7, 5), ExtentForRange(3, 10));
+ ASSERT_EQ(ret3, ExtentForRange(7, 5));
+ const auto ret4 =
+ GetOverlapExtent(ExtentForRange(7, 5), ExtentForRange(3, 3));
+ ASSERT_EQ(ret4.num_blocks(), 0UL);
+}
+
+TEST(ExtentRangesTest, ContainsBlockSameStart) {
+ ExtentRanges ranges{false};
+ ranges.AddExtent(ExtentForRange(5, 4));
+ ranges.AddExtent(ExtentForRange(10, 5));
+ ranges.AddExtent(ExtentForRange(15, 5));
+ ranges.AddExtent(ExtentForRange(20, 5));
+ ranges.AddExtent(ExtentForRange(25, 5));
+
+ ASSERT_TRUE(ranges.ContainsBlock(10));
+ ASSERT_TRUE(ranges.ContainsBlock(15));
+ ASSERT_TRUE(ranges.ContainsBlock(20));
+ ASSERT_TRUE(ranges.ContainsBlock(25));
+ ASSERT_TRUE(ranges.ContainsBlock(29));
+ ASSERT_FALSE(ranges.ContainsBlock(30));
+ ASSERT_FALSE(ranges.ContainsBlock(9));
+}
+
+TEST(ExtentRangesTest, OverlapsWithExtentSameStart) {
+ ExtentRanges ranges{false};
+ ranges.AddExtent(ExtentForRange(5, 4));
+ ranges.AddExtent(ExtentForRange(10, 5));
+ ranges.AddExtent(ExtentForRange(15, 5));
+ ranges.AddExtent(ExtentForRange(20, 5));
+ ranges.AddExtent(ExtentForRange(25, 5));
+
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(9, 2)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(12, 5)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(14, 5)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(10, 9)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(11, 20)));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(0, 5)));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(30, 20)));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(9, 1)));
+
+ ranges.SubtractExtent(ExtentForRange(12, 5));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(12, 5)));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(13, 3)));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(15, 2)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(14, 5)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(17, 1)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(8, 5)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(8, 4)));
+}
+
+TEST(ExtentRangesTest, OverlapsWithExtent) {
+ ExtentRanges ranges;
+ ranges.AddExtent(ExtentForRange(5, 5));
+ ranges.AddExtent(ExtentForRange(15, 5));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(3, 10)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(17, 10)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(0, 10)));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(10, 5)));
+ ASSERT_FALSE(ranges.OverlapsWithExtent(ExtentForRange(20, 5)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(7, 1)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(0, 100)));
+ ASSERT_TRUE(ranges.OverlapsWithExtent(ExtentForRange(19, 1)));
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_generator/extent_utils.cc b/payload_generator/extent_utils.cc
index 2efef120..612fd672 100644
--- a/payload_generator/extent_utils.cc
+++ b/payload_generator/extent_utils.cc
@@ -26,6 +26,7 @@
#include <base/macros.h>
#include <base/strings/stringprintf.h>
+#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_generator/annotated_operation.h"
#include "update_engine/payload_generator/extent_ranges.h"
@@ -87,7 +88,8 @@ void ExtentsToVector(const google::protobuf::RepeatedPtrField<Extent>& extents,
}
}
-string ExtentsToString(const vector<Extent>& extents) {
+template <typename Container>
+string ExtentsToStringTemplate(const Container& extents) {
string ext_str;
for (const Extent& e : extents)
ext_str += base::StringPrintf("[%" PRIu64 ", %" PRIu64 "] ",
@@ -96,6 +98,15 @@ string ExtentsToString(const vector<Extent>& extents) {
return ext_str;
}
+std::string ExtentsToString(const std::vector<Extent>& extents) {
+ return ExtentsToStringTemplate(extents);
+}
+
+std::string ExtentsToString(
+ const google::protobuf::RepeatedPtrField<Extent>& extents) {
+ return ExtentsToStringTemplate(extents);
+}
+
void NormalizeExtents(vector<Extent>* extents) {
vector<Extent> new_extents;
for (const Extent& curr_ext : *extents) {
@@ -151,14 +162,44 @@ vector<Extent> ExtentsSublist(const vector<Extent>& extents,
return result;
}
-bool operator==(const Extent& a, const Extent& b) {
+bool operator==(const Extent& a, const Extent& b) noexcept {
return a.start_block() == b.start_block() && a.num_blocks() == b.num_blocks();
}
+bool operator!=(const Extent& a, const Extent& b) noexcept {
+ return !(a == b);
+}
+
std::ostream& operator<<(std::ostream& out, const Extent& extent) {
out << "[" << extent.start_block() << " - "
<< extent.start_block() + extent.num_blocks() - 1 << "]";
return out;
}
+template <typename T>
+std::ostream& PrintExtents(std::ostream& out, const T& extents) {
+ if (extents.begin() == extents.end()) {
+ out << "{}";
+ return out;
+ }
+ out << "{";
+ auto begin = extents.begin();
+ out << *begin;
+ for (const auto& ext : Range{++begin, extents.end()}) {
+ out << ", " << ext;
+ }
+ out << "}";
+ return out;
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const std::vector<Extent>& extents) {
+ return PrintExtents(out, extents);
+}
+std::ostream& operator<<(
+ std::ostream& out,
+ const google::protobuf::RepeatedPtrField<Extent>& extents) {
+ return PrintExtents(out, extents);
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_generator/extent_utils.h b/payload_generator/extent_utils.h
index 7aa614a1..bd9fc8b1 100644
--- a/payload_generator/extent_utils.h
+++ b/payload_generator/extent_utils.h
@@ -17,11 +17,13 @@
#ifndef UPDATE_ENGINE_PAYLOAD_GENERATOR_EXTENT_UTILS_H_
#define UPDATE_ENGINE_PAYLOAD_GENERATOR_EXTENT_UTILS_H_
+#include <limits>
#include <string>
#include <vector>
#include <base/logging.h>
+#include "google/protobuf/repeated_field.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/update_metadata.pb.h"
@@ -63,6 +65,8 @@ void ExtentsToVector(const google::protobuf::RepeatedPtrField<Extent>& extents,
// Returns a string representing all extents in |extents|.
std::string ExtentsToString(const std::vector<Extent>& extents);
+std::string ExtentsToString(
+ const google::protobuf::RepeatedPtrField<Extent>& extents);
// Takes a pointer to extents |extents| and extents |extents_to_add|, and
// merges them by adding |extents_to_add| to |extents| and normalizing.
@@ -83,7 +87,9 @@ std::vector<Extent> ExtentsSublist(const std::vector<Extent>& extents,
uint64_t block_offset,
uint64_t block_count);
-bool operator==(const Extent& a, const Extent& b);
+bool operator==(const Extent& a, const Extent& b) noexcept;
+
+bool operator!=(const Extent& a, const Extent& b) noexcept;
// TODO(zhangkelvin) This is ugly. Rewrite using C++20's coroutine once
// that's available. Unfortunately with C++17 this is the best I could do.
@@ -123,6 +129,27 @@ struct BlockIterator {
};
std::ostream& operator<<(std::ostream& out, const Extent& extent);
+std::ostream& operator<<(std::ostream& out, const std::vector<Extent>& extent);
+std::ostream& operator<<(
+ std::ostream& out,
+ const google::protobuf::RepeatedPtrField<Extent>& extent);
+
+template <typename Container>
+size_t GetNthBlock(const Container& extents, const size_t n) {
+ size_t cur_block_count = 0;
+ for (const auto& extent : extents) {
+ if (n - cur_block_count < extent.num_blocks()) {
+ return extent.start_block() + (n - cur_block_count);
+ }
+ cur_block_count += extent.num_blocks();
+ }
+ return std::numeric_limits<size_t>::max();
+}
+
+constexpr bool ExtentContains(const Extent& extent, size_t block) {
+ return extent.start_block() <= block &&
+ block < extent.start_block() + extent.num_blocks();
+}
} // namespace chromeos_update_engine
diff --git a/payload_generator/filesystem_interface.h b/payload_generator/filesystem_interface.h
index 05d387f6..0c2f05e3 100644
--- a/payload_generator/filesystem_interface.h
+++ b/payload_generator/filesystem_interface.h
@@ -31,10 +31,11 @@
#include <string>
#include <vector>
-#include <base/macros.h>
#include <brillo/key_value_store.h>
#include <puffin/utils.h>
+#include "update_engine/lz4diff/lz4diff_format.h"
+#include "update_engine/lz4diff/lz4diff.h"
#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
@@ -44,12 +45,13 @@ class FilesystemInterface {
// This represents a file or pseudo-file in the filesystem. It can include
// all sort of files, like symlinks, hardlinks, directories and even a file
// entry representing the metadata, free space, journaling data, etc.
+
struct File {
File() { memset(&file_stat, 0, sizeof(file_stat)); }
// The stat struct for the file. This is invalid (inode 0) for some
// pseudo-files.
- struct stat file_stat;
+ struct stat file_stat = {};
// The absolute path to the file inside the filesystem, for example,
// "/usr/bin/bash". For pseudo-files, like blocks associated to internal
@@ -72,6 +74,8 @@ class FilesystemInterface {
// All the deflate locations in the file. These locations are not relative
// to the extents. They are relative to the file system itself.
std::vector<puffin::BitExtent> deflates;
+
+ CompressedFile compressed_file_info;
};
virtual ~FilesystemInterface() = default;
diff --git a/payload_generator/generate_delta_main.cc b/payload_generator/generate_delta_main.cc
index b04fec0b..ef36a6de 100644
--- a/payload_generator/generate_delta_main.cc
+++ b/payload_generator/generate_delta_main.cc
@@ -425,8 +425,29 @@ int Main(int argc, char** argv) {
disable_vabc,
false,
"Whether to disable Virtual AB Compression when installing the OTA");
+ DEFINE_bool(enable_vabc_xor,
+ false,
+ "Whether to use Virtual AB Compression XOR feature");
DEFINE_string(
apex_info_file, "", "Path to META/apex_info.pb found in target build");
+ DEFINE_string(compressor_types,
+ "bz2:brotli",
+ "Colon ':' separated list of compressors. Allowed valures are "
+ "bz2 and brotli.");
+ DEFINE_bool(
+ enable_lz4diff,
+ false,
+ "Whether to enable LZ4diff feature when processing EROFS images.");
+
+ DEFINE_bool(
+ enable_zucchini,
+ true,
+ "Whether to enable zucchini feature when processing executable files.");
+
+ DEFINE_string(erofs_compression_param,
+ "",
+ "Compression parameter passed to mkfs.erofs's -z option. "
+ "Example: lz4 lz4hc,9");
brillo::FlagHelper::Init(
argc,
@@ -543,6 +564,12 @@ int Main(int argc, char** argv) {
payload_config.apex_info_file = FLAGS_apex_info_file;
}
+ payload_config.enable_vabc_xor = FLAGS_enable_vabc_xor;
+ payload_config.enable_lz4diff = FLAGS_enable_lz4diff;
+ payload_config.enable_zucchini = FLAGS_enable_zucchini;
+
+ payload_config.ParseCompressorTypes(FLAGS_compressor_types);
+
if (!FLAGS_new_partitions.empty()) {
LOG_IF(FATAL, !FLAGS_new_image.empty() || !FLAGS_new_kernel.empty())
<< "--new_image and --new_kernel are deprecated, please use "
@@ -572,6 +599,10 @@ int Main(int argc, char** argv) {
payload_config.target.partitions.back().path = new_partitions[i];
payload_config.target.partitions.back().disable_fec_computation =
FLAGS_disable_fec_computation;
+ if (!FLAGS_erofs_compression_param.empty()) {
+ payload_config.target.partitions.back().erofs_compression_param =
+ PartitionConfig::ParseCompressionParam(FLAGS_erofs_compression_param);
+ }
if (i < new_mapfiles.size())
payload_config.target.partitions.back().mapfile_path = new_mapfiles[i];
}
diff --git a/payload_generator/merge_sequence_generator.cc b/payload_generator/merge_sequence_generator.cc
index 289e2f86..cb43221b 100644
--- a/payload_generator/merge_sequence_generator.cc
+++ b/payload_generator/merge_sequence_generator.cc
@@ -17,17 +17,24 @@
#include "update_engine/payload_generator/merge_sequence_generator.h"
#include <algorithm>
+#include <limits>
+#include "update_engine/payload_generator/delta_diff_generator.h"
+#include "update_engine/payload_generator/extent_ranges.h"
#include "update_engine/payload_generator/extent_utils.h"
+#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
CowMergeOperation CreateCowMergeOperation(const Extent& src_extent,
- const Extent& dst_extent) {
+ const Extent& dst_extent,
+ CowMergeOperation::Type op_type,
+ uint32_t src_offset) {
CowMergeOperation ret;
- ret.set_type(CowMergeOperation::COW_COPY);
+ ret.set_type(op_type);
*ret.mutable_src_extent() = src_extent;
*ret.mutable_dst_extent() = dst_extent;
+ ret.set_src_offset(src_offset);
return ret;
}
@@ -36,6 +43,17 @@ std::ostream& operator<<(std::ostream& os,
os << "CowMergeOperation src extent: "
<< ExtentsToString({merge_operation.src_extent()})
<< ", dst extent: " << ExtentsToString({merge_operation.dst_extent()});
+ if (merge_operation.has_src_offset()) {
+ os << ", src offset: " << merge_operation.src_offset();
+ }
+ os << " op_type: ";
+ if (merge_operation.type() == CowMergeOperation::COW_COPY) {
+ os << "COW_COPY";
+ } else if (merge_operation.type() == CowMergeOperation::COW_XOR) {
+ os << "COW_XOR";
+ } else {
+ os << merge_operation.type();
+ }
return os;
}
@@ -56,12 +74,27 @@ constexpr T GetDifference(T first, T second) {
return abs_diff;
}
+CowMergeOperation::Type GetCowOpType(InstallOperation::Type install_op_type) {
+ switch (install_op_type) {
+ case InstallOperation::SOURCE_COPY:
+ return CowMergeOperation::COW_COPY;
+ case InstallOperation::SOURCE_BSDIFF:
+ case InstallOperation::BROTLI_BSDIFF:
+ case InstallOperation::PUFFDIFF:
+ return CowMergeOperation::COW_XOR;
+ default:
+ CHECK(false) << "Unknown install op type: " << install_op_type;
+ return CowMergeOperation::COW_REPLACE;
+ }
+}
+
void SplitSelfOverlapping(const Extent& src_extent,
const Extent& dst_extent,
std::vector<CowMergeOperation>* sequence) {
CHECK_EQ(src_extent.num_blocks(), dst_extent.num_blocks());
if (src_extent.start_block() == dst_extent.start_block()) {
- sequence->emplace_back(CreateCowMergeOperation(src_extent, dst_extent));
+ sequence->emplace_back(CreateCowMergeOperation(
+ src_extent, dst_extent, CowMergeOperation::COW_COPY));
return;
}
@@ -71,51 +104,91 @@ void SplitSelfOverlapping(const Extent& src_extent,
auto num_blocks = std::min<size_t>(diff, src_extent.num_blocks() - i);
sequence->emplace_back(CreateCowMergeOperation(
ExtentForRange(i + src_extent.start_block(), num_blocks),
- ExtentForRange(i + dst_extent.start_block(), num_blocks)));
+ ExtentForRange(i + dst_extent.start_block(), num_blocks),
+ CowMergeOperation::COW_COPY));
+ }
+}
+
+static bool ProcessXorOps(std::vector<CowMergeOperation>* sequence,
+ const AnnotatedOperation& aop) {
+ const auto size_before = sequence->size();
+ sequence->insert(sequence->end(), aop.xor_ops.begin(), aop.xor_ops.end());
+ std::for_each(
+ sequence->begin() + size_before,
+ sequence->end(),
+ [](CowMergeOperation& op) {
+ CHECK_EQ(op.type(), CowMergeOperation::COW_XOR);
+ // If |src_offset| is greater than 0, then we are reading 1
+ // extra block at the end of src_extent. This dependency must
+ // be honored during merge sequence generation, or we can end
+ // up with a corrupted device after merge.
+ if (op.src_offset() > 0) {
+ if (op.src_extent().num_blocks() == op.dst_extent().num_blocks()) {
+ op.mutable_src_extent()->set_num_blocks(
+ op.src_extent().num_blocks() + 1);
+ }
+ CHECK_EQ(op.src_extent().num_blocks(),
+ op.dst_extent().num_blocks() + 1);
+ }
+ CHECK_NE(op.src_extent().start_block(),
+ std::numeric_limits<uint64_t>::max());
+ });
+ return true;
+}
+
+static bool ProcessCopyOps(std::vector<CowMergeOperation>* sequence,
+ const AnnotatedOperation& aop) {
+ CHECK_EQ(GetCowOpType(aop.op.type()), CowMergeOperation::COW_COPY);
+ if (aop.op.dst_extents().size() != 1) {
+ std::vector<Extent> out_extents;
+ ExtentsToVector(aop.op.dst_extents(), &out_extents);
+ LOG(ERROR)
+ << "The dst extents for source_copy are expected to be contiguous,"
+ << " dst extents: " << ExtentsToString(out_extents);
+ return false;
+ }
+ // Split the source extents.
+ size_t used_blocks = 0;
+ for (const auto& src_extent : aop.op.src_extents()) {
+ // The dst_extent in the merge sequence will be a subset of
+ // InstallOperation's dst_extent. This will simplify the OTA -> COW
+ // conversion when we install the payload.
+ Extent dst_extent =
+ ExtentForRange(aop.op.dst_extents(0).start_block() + used_blocks,
+ src_extent.num_blocks());
+ // Self-overlapping operation, must split into multiple non
+ // self-overlapping ops
+ if (ExtentRanges::ExtentsOverlap(src_extent, dst_extent)) {
+ SplitSelfOverlapping(src_extent, dst_extent, sequence);
+ } else {
+ sequence->emplace_back(CreateCowMergeOperation(
+ src_extent, dst_extent, CowMergeOperation::COW_COPY));
+ }
+ used_blocks += src_extent.num_blocks();
+ }
+
+ if (used_blocks != aop.op.dst_extents(0).num_blocks()) {
+ LOG(ERROR) << "Number of blocks in src extents doesn't equal to the"
+ << " ones in the dst extents, src blocks " << used_blocks
+ << ", dst blocks " << aop.op.dst_extents(0).num_blocks();
+ return false;
}
+ return true;
}
std::unique_ptr<MergeSequenceGenerator> MergeSequenceGenerator::Create(
const std::vector<AnnotatedOperation>& aops) {
std::vector<CowMergeOperation> sequence;
- for (const auto& aop : aops) {
- // Only handle SOURCE_COPY now for the cow size optimization.
- if (aop.op.type() != InstallOperation::SOURCE_COPY) {
- continue;
- }
- if (aop.op.dst_extents().size() != 1) {
- std::vector<Extent> out_extents;
- ExtentsToVector(aop.op.dst_extents(), &out_extents);
- LOG(ERROR) << "The dst extents for source_copy expects to be contiguous,"
- << " dst extents: " << ExtentsToString(out_extents);
- return nullptr;
- }
- // Split the source extents.
- size_t used_blocks = 0;
- for (const auto& src_extent : aop.op.src_extents()) {
- // The dst_extent in the merge sequence will be a subset of
- // InstallOperation's dst_extent. This will simplify the OTA -> COW
- // conversion when we install the payload.
- Extent dst_extent =
- ExtentForRange(aop.op.dst_extents(0).start_block() + used_blocks,
- src_extent.num_blocks());
-
- // Self-overlapping SOURCE_COPY, must split into multiple non
- // self-overlapping ops
- if (ExtentRanges::ExtentsOverlap(src_extent, dst_extent)) {
- SplitSelfOverlapping(src_extent, dst_extent, &sequence);
- } else {
- sequence.emplace_back(CreateCowMergeOperation(src_extent, dst_extent));
+ for (const auto& aop : aops) {
+ if (aop.op.type() == InstallOperation::SOURCE_COPY) {
+ if (!ProcessCopyOps(&sequence, aop)) {
+ return nullptr;
+ }
+ } else if (!aop.xor_ops.empty()) {
+ if (!ProcessXorOps(&sequence, aop)) {
+ return nullptr;
}
- used_blocks += src_extent.num_blocks();
- }
-
- if (used_blocks != aop.op.dst_extents(0).num_blocks()) {
- LOG(ERROR) << "Number of blocks in src extents doesn't equal to the"
- << " ones in the dst extents, src blocks " << used_blocks
- << ", dst blocks " << aop.op.dst_extents(0).num_blocks();
- return nullptr;
}
}
@@ -167,7 +240,7 @@ bool MergeSequenceGenerator::FindDependency(
}
auto ret = merge_after.emplace(op, std::move(operations));
// Check the insertion indeed happens.
- CHECK(ret.second);
+ CHECK(ret.second) << op;
}
}
@@ -197,6 +270,11 @@ bool MergeSequenceGenerator::Generate(
}
}
+ // Technically, we can use std::unordered_set or just a std::vector. but
+ // std::set gives the benefit where operations are sorted by dst blocks. This
+ // will ensure that operations that do not have dependency constraints appear
+ // in increasing block order. Such order would help snapuserd batch merges and
+ // improve boot time, but isn't strictly needed for correctness.
std::set<CowMergeOperation> free_operations;
for (const auto& op : operations_) {
if (incoming_edges.find(op) == incoming_edges.end()) {
@@ -221,9 +299,9 @@ bool MergeSequenceGenerator::Generate(
for (const auto& op : free_operations) {
incoming_edges.erase(op);
- // Now that this particular operation is merged, other operations blocked
- // by this one may be free. Decrement the count of blocking operations,
- // and set up the free operations for the next iteration.
+ // Now that this particular operation is merged, other operations
+ // blocked by this one may be free. Decrement the count of blocking
+ // operations, and set up the free operations for the next iteration.
for (const auto& blocked : merge_after[op]) {
auto it = incoming_edges.find(blocked);
if (it == incoming_edges.end()) {
@@ -271,6 +349,7 @@ bool MergeSequenceGenerator::Generate(
LOG(INFO) << "Blocks in merge sequence " << blocks_in_sequence
<< ", blocks in raw " << blocks_in_raw;
if (!ValidateSequence(merge_sequence)) {
+ LOG(ERROR) << "Invalid Sequence";
return false;
}
@@ -283,6 +362,16 @@ bool MergeSequenceGenerator::ValidateSequence(
LOG(INFO) << "Validating merge sequence";
ExtentRanges visited;
for (const auto& op : sequence) {
+ // If |src_offset| is greater than zero, dependency should include 1 extra
+ // block at end of src_extent, as the OP actually references data past
+ // original src_extent.
+ if (op.src_offset() > 0) {
+ CHECK_EQ(op.src_extent().num_blocks(), op.dst_extent().num_blocks() + 1)
+ << op;
+ } else {
+ CHECK_EQ(op.src_extent().num_blocks(), op.dst_extent().num_blocks())
+ << op;
+ }
if (visited.OverlapsWithExtent(op.src_extent())) {
LOG(ERROR) << "Transfer violates the merge sequence " << op
<< "Visited extent ranges: ";
diff --git a/payload_generator/merge_sequence_generator.h b/payload_generator/merge_sequence_generator.h
index 385fcc3c..d3b5eb94 100644
--- a/payload_generator/merge_sequence_generator.h
+++ b/payload_generator/merge_sequence_generator.h
@@ -31,7 +31,9 @@
namespace chromeos_update_engine {
// Constructs CowMergeOperation from src & dst extents
CowMergeOperation CreateCowMergeOperation(const Extent& src_extent,
- const Extent& dst_extent);
+ const Extent& dst_extent,
+ CowMergeOperation::Type op_type,
+ uint32_t src_offset = 0);
// Comparator for CowMergeOperation.
bool operator<(const CowMergeOperation& op1, const CowMergeOperation& op2);
@@ -67,7 +69,7 @@ class MergeSequenceGenerator {
bool FindDependency(std::map<CowMergeOperation, std::set<CowMergeOperation>>*
merge_after) const;
// The list of CowMergeOperations to sort.
- std::vector<CowMergeOperation> operations_;
+ const std::vector<CowMergeOperation> operations_;
};
void SplitSelfOverlapping(const Extent& src_extent,
diff --git a/payload_generator/merge_sequence_generator_unittest.cc b/payload_generator/merge_sequence_generator_unittest.cc
index b8507ed9..86d4fdd1 100644
--- a/payload_generator/merge_sequence_generator_unittest.cc
+++ b/payload_generator/merge_sequence_generator_unittest.cc
@@ -20,11 +20,18 @@
#include <gtest/gtest.h>
#include "update_engine/payload_consumer/payload_constants.h"
+#include "update_engine/payload_generator/delta_diff_generator.h"
#include "update_engine/payload_generator/extent_ranges.h"
#include "update_engine/payload_generator/extent_utils.h"
#include "update_engine/payload_generator/merge_sequence_generator.h"
+#include "update_engine/update_metadata.pb.h"
namespace chromeos_update_engine {
+CowMergeOperation CreateCowMergeOperation(const Extent& src_extent,
+ const Extent& dst_extent) {
+ return CreateCowMergeOperation(
+ src_extent, dst_extent, CowMergeOperation::COW_COPY);
+}
class MergeSequenceGeneratorTest : public ::testing::Test {
protected:
void VerifyTransfers(MergeSequenceGenerator* generator,
@@ -51,7 +58,7 @@ class MergeSequenceGeneratorTest : public ::testing::Test {
};
TEST_F(MergeSequenceGeneratorTest, Create) {
- std::vector<AnnotatedOperation> aops{{"file1", {}}, {"file2", {}}};
+ std::vector<AnnotatedOperation> aops{{"file1", {}, {}}, {"file2", {}, {}}};
aops[0].op.set_type(InstallOperation::SOURCE_COPY);
*aops[0].op.add_src_extents() = ExtentForRange(10, 10);
*aops[0].op.add_dst_extents() = ExtentForRange(30, 10);
@@ -81,7 +88,7 @@ TEST_F(MergeSequenceGeneratorTest, Create_SplitSource) {
*(op.add_src_extents()) = ExtentForRange(8, 4);
*(op.add_dst_extents()) = ExtentForRange(10, 8);
- AnnotatedOperation aop{"file1", op};
+ AnnotatedOperation aop{"file1", op, {}};
auto generator = MergeSequenceGenerator::Create({aop});
ASSERT_TRUE(generator);
std::vector<CowMergeOperation> expected = {
@@ -183,8 +190,8 @@ TEST_F(MergeSequenceGeneratorTest, GenerateSequenceWithCycles) {
CreateCowMergeOperation(ExtentForRange(10, 10), ExtentForRange(15, 10)),
};
- // file 1,2,3 form a cycle. And file3, whose dst ext has smallest offset, will
- // be converted to raw blocks
+ // file 1,2,3 form a cycle. And file3, whose dst ext has smallest offset,
+ // will be converted to raw blocks
std::vector<CowMergeOperation> expected{
transfers[3], transfers[1], transfers[0]};
GenerateSequence(transfers, expected);
@@ -247,4 +254,174 @@ TEST_F(MergeSequenceGeneratorTest, SplitSelfOverlappingTest) {
ValidateSplitSequence(b, a);
}
+TEST_F(MergeSequenceGeneratorTest, GenerateSequenceWithXor) {
+ std::vector<CowMergeOperation> transfers = {
+ // cycle 1
+ CreateCowMergeOperation(ExtentForRange(10, 10),
+ ExtentForRange(25, 10),
+ CowMergeOperation::COW_XOR),
+ CreateCowMergeOperation(ExtentForRange(24, 5), ExtentForRange(35, 5)),
+ CreateCowMergeOperation(ExtentForRange(30, 10),
+ ExtentForRange(15, 10),
+ CowMergeOperation::COW_XOR),
+ // cycle 2
+ CreateCowMergeOperation(ExtentForRange(55, 10), ExtentForRange(60, 10)),
+ CreateCowMergeOperation(ExtentForRange(60, 10),
+ ExtentForRange(70, 10),
+ CowMergeOperation::COW_XOR),
+ CreateCowMergeOperation(ExtentForRange(70, 10), ExtentForRange(55, 10)),
+ };
+
+ // file 3, 6 will be converted to raw.
+ std::vector<CowMergeOperation> expected{
+ transfers[1], transfers[0], transfers[4], transfers[3]};
+ GenerateSequence(transfers, expected);
+}
+
+TEST_F(MergeSequenceGeneratorTest, CreateGeneratorWithXor) {
+ std::vector<AnnotatedOperation> aops;
+ auto& aop = aops.emplace_back();
+ aop.op.set_type(InstallOperation::SOURCE_BSDIFF);
+ *aop.op.mutable_src_extents()->Add() = ExtentForRange(10, 5);
+ *aop.op.mutable_dst_extents()->Add() = ExtentForRange(20, 5);
+ auto& xor_map = aop.xor_ops;
+ {
+ // xor_map[i] = i * kBlockSize + 123;
+ auto& op = xor_map.emplace_back();
+ *op.mutable_src_extent() = ExtentForRange(10, 5);
+ *op.mutable_dst_extent() = ExtentForRange(20, 5);
+ op.set_src_offset(123);
+ op.set_type(CowMergeOperation::COW_XOR);
+ }
+ auto generator = MergeSequenceGenerator::Create(aops);
+ ASSERT_NE(generator, nullptr);
+ std::vector<CowMergeOperation> sequence;
+ ASSERT_TRUE(generator->Generate(&sequence));
+ ASSERT_EQ(sequence.size(), 1UL);
+ ASSERT_EQ(sequence[0].src_extent().start_block(), 10UL);
+ ASSERT_EQ(sequence[0].dst_extent().start_block(), 20UL);
+ ASSERT_EQ(sequence[0].src_extent().num_blocks(), 6UL);
+ ASSERT_EQ(sequence[0].dst_extent().num_blocks(), 5UL);
+ ASSERT_EQ(sequence[0].type(), CowMergeOperation::COW_XOR);
+ ASSERT_EQ(sequence[0].src_offset(), 123UL);
+
+ ASSERT_TRUE(generator->ValidateSequence(sequence));
+}
+
+TEST_F(MergeSequenceGeneratorTest, CreateGeneratorWithXorMultipleExtents) {
+ std::vector<AnnotatedOperation> aops;
+ auto& aop = aops.emplace_back();
+ aop.op.set_type(InstallOperation::SOURCE_BSDIFF);
+ *aop.op.mutable_src_extents()->Add() = ExtentForRange(10, 10);
+ *aop.op.mutable_dst_extents()->Add() = ExtentForRange(30, 5);
+ *aop.op.mutable_dst_extents()->Add() = ExtentForRange(45, 5);
+ auto& xor_map = aop.xor_ops;
+ {
+ // xor_map[i] = i * kBlockSize + 123;
+ auto& op = xor_map.emplace_back();
+ *op.mutable_src_extent() = ExtentForRange(10, 5);
+ *op.mutable_dst_extent() = ExtentForRange(30, 5);
+ op.set_src_offset(123);
+ op.set_type(CowMergeOperation::COW_XOR);
+ }
+ {
+ // xor_map[i] = i * kBlockSize + 123;
+ auto& op = xor_map.emplace_back();
+ *op.mutable_src_extent() = ExtentForRange(15, 5);
+ *op.mutable_dst_extent() = ExtentForRange(45, 5);
+ op.set_src_offset(123);
+ op.set_type(CowMergeOperation::COW_XOR);
+ }
+ auto generator = MergeSequenceGenerator::Create(aops);
+ ASSERT_NE(generator, nullptr);
+ std::vector<CowMergeOperation> sequence;
+ ASSERT_TRUE(generator->Generate(&sequence));
+ ASSERT_EQ(sequence.size(), 2UL);
+ ASSERT_EQ(sequence[0].src_extent().start_block(), 10UL);
+ ASSERT_EQ(sequence[0].dst_extent().start_block(), 30UL);
+ ASSERT_EQ(sequence[0].src_extent().num_blocks(), 6UL);
+ ASSERT_EQ(sequence[0].dst_extent().num_blocks(), 5UL);
+ ASSERT_EQ(sequence[0].type(), CowMergeOperation::COW_XOR);
+ ASSERT_EQ(sequence[0].src_offset(), 123UL);
+
+ ASSERT_EQ(sequence[1].src_extent().start_block(), 15UL);
+ ASSERT_EQ(sequence[1].dst_extent().start_block(), 45UL);
+ ASSERT_EQ(sequence[1].src_extent().num_blocks(), 6UL);
+ ASSERT_EQ(sequence[1].dst_extent().num_blocks(), 5UL);
+ ASSERT_EQ(sequence[1].type(), CowMergeOperation::COW_XOR);
+ ASSERT_EQ(sequence[1].src_offset(), 123UL);
+
+ ASSERT_TRUE(generator->ValidateSequence(sequence));
+}
+
+TEST_F(MergeSequenceGeneratorTest, CreateGeneratorXorAppendBlock) {
+ std::vector<AnnotatedOperation> aops;
+ auto& aop = aops.emplace_back();
+ aop.op.set_type(InstallOperation::SOURCE_BSDIFF);
+ *aop.op.mutable_src_extents()->Add() = ExtentForRange(10, 10);
+ *aop.op.mutable_dst_extents()->Add() = ExtentForRange(20, 10);
+ auto& xor_map = aop.xor_ops;
+ {
+ auto& op = xor_map.emplace_back();
+ *op.mutable_src_extent() = ExtentForRange(10, 5);
+ *op.mutable_dst_extent() = ExtentForRange(20, 5);
+ op.set_type(CowMergeOperation::COW_XOR);
+ }
+ {
+ auto& op = xor_map.emplace_back();
+ *op.mutable_src_extent() = ExtentForRange(15, 5);
+ *op.mutable_dst_extent() = ExtentForRange(25, 5);
+ op.set_src_offset(123);
+ op.set_type(CowMergeOperation::COW_XOR);
+ }
+ auto generator = MergeSequenceGenerator::Create(aops);
+ ASSERT_NE(generator, nullptr);
+ std::vector<CowMergeOperation> sequence;
+ ASSERT_TRUE(generator->Generate(&sequence));
+ ASSERT_EQ(sequence.size(), 2UL);
+ ASSERT_EQ(sequence[0].src_extent().start_block(), 15UL);
+ ASSERT_EQ(sequence[0].dst_extent().start_block(), 25UL);
+ ASSERT_EQ(sequence[0].src_extent().num_blocks(), 6UL);
+ ASSERT_EQ(sequence[0].dst_extent().num_blocks(), 5UL);
+ ASSERT_EQ(sequence[0].type(), CowMergeOperation::COW_XOR);
+ ASSERT_EQ(sequence[0].src_offset(), 123UL);
+
+ ASSERT_EQ(sequence[1].src_extent().start_block(), 10UL);
+ ASSERT_EQ(sequence[1].dst_extent().start_block(), 20UL);
+ ASSERT_EQ(sequence[1].src_extent().num_blocks(), 5UL);
+ ASSERT_EQ(sequence[1].dst_extent().num_blocks(), 5UL);
+ ASSERT_EQ(sequence[1].type(), CowMergeOperation::COW_XOR);
+
+ ASSERT_TRUE(generator->ValidateSequence(sequence));
+}
+
+TEST_F(MergeSequenceGeneratorTest, CreateGeneratorXorAlreadyPlusOne) {
+ std::vector<AnnotatedOperation> aops;
+ auto& aop = aops.emplace_back();
+ aop.op.set_type(InstallOperation::SOURCE_BSDIFF);
+ *aop.op.mutable_src_extents()->Add() = ExtentForRange(10, 10);
+ *aop.op.mutable_dst_extents()->Add() = ExtentForRange(20, 10);
+ auto& xor_map = aop.xor_ops;
+ {
+ auto& op = xor_map.emplace_back();
+ *op.mutable_src_extent() = ExtentForRange(15, 6);
+ *op.mutable_dst_extent() = ExtentForRange(25, 5);
+ op.set_src_offset(123);
+ op.set_type(CowMergeOperation::COW_XOR);
+ }
+ auto generator = MergeSequenceGenerator::Create(aops);
+ ASSERT_NE(generator, nullptr);
+ std::vector<CowMergeOperation> sequence;
+ ASSERT_TRUE(generator->Generate(&sequence));
+ ASSERT_EQ(sequence.size(), 1UL);
+ ASSERT_EQ(sequence[0].src_extent().start_block(), 15UL);
+ ASSERT_EQ(sequence[0].dst_extent().start_block(), 25UL);
+ ASSERT_EQ(sequence[0].src_extent().num_blocks(), 6UL);
+ ASSERT_EQ(sequence[0].dst_extent().num_blocks(), 5UL);
+ ASSERT_EQ(sequence[0].type(), CowMergeOperation::COW_XOR);
+ ASSERT_EQ(sequence[0].src_offset(), 123UL);
+
+ ASSERT_TRUE(generator->ValidateSequence(sequence));
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_generator/payload_file.cc b/payload_generator/payload_file.cc
index 6ec219ff..129377aa 100644
--- a/payload_generator/payload_file.cc
+++ b/payload_generator/payload_file.cc
@@ -195,14 +195,28 @@ bool PayloadFile::WritePayload(const string& payload_file,
PayloadSigner::AddSignatureToManifest(
next_blob_offset, signature_blob_length, &manifest_);
}
+ WritePayload(payload_file,
+ ordered_blobs_file.path(),
+ private_key_path,
+ major_version_,
+ manifest_,
+ metadata_size_out);
+
+ ReportPayloadUsage(*metadata_size_out);
+ return true;
+}
- // Serialize protobuf
- string serialized_manifest;
- TEST_AND_RETURN_FALSE(manifest_.SerializeToString(&serialized_manifest));
+bool PayloadFile::WritePayload(const std::string& payload_file,
+ const std::string& ordered_blobs_file,
+ const std::string& private_key_path,
+ uint64_t major_version_,
+ const DeltaArchiveManifest& manifest,
+ uint64_t* metadata_size_out) {
+ std::string serialized_manifest;
+ TEST_AND_RETURN_FALSE(manifest.SerializeToString(&serialized_manifest));
uint64_t metadata_size =
sizeof(kDeltaMagic) + 2 * sizeof(uint64_t) + serialized_manifest.size();
-
LOG(INFO) << "Writing final delta file header...";
DirectFileWriter writer;
TEST_AND_RETURN_FALSE_ERRNO(writer.Open(payload_file.c_str(),
@@ -222,12 +236,16 @@ bool PayloadFile::WritePayload(const string& payload_file,
// Metadata signature has the same size as payload signature, because they
// are both the same kind of signature for the same kind of hash.
- uint32_t metadata_signature_size = htobe32(signature_blob_length);
- TEST_AND_RETURN_FALSE_ERRNO(
- writer.Write(&metadata_signature_size, sizeof(metadata_signature_size)));
- metadata_size += sizeof(metadata_signature_size);
- // Set correct size instead of big endian size.
- metadata_signature_size = signature_blob_length;
+ const auto signature_blob_length = manifest.signatures_size();
+ // Adding a new scope here so code down below can't access
+ // metadata_signature_size, as the integer is in big endian, not host
+ // endianess.
+ {
+ const uint32_t metadata_signature_size = htobe32(signature_blob_length);
+ TEST_AND_RETURN_FALSE_ERRNO(writer.Write(&metadata_signature_size,
+ sizeof(metadata_signature_size)));
+ metadata_size += sizeof(metadata_signature_size);
+ }
// Write protobuf
LOG(INFO) << "Writing final delta file protobuf... "
@@ -249,7 +267,7 @@ bool PayloadFile::WritePayload(const string& payload_file,
// Append the data blobs.
LOG(INFO) << "Writing final delta file data blobs...";
- int blobs_fd = open(ordered_blobs_file.path().c_str(), O_RDONLY, 0);
+ int blobs_fd = open(ordered_blobs_file.c_str(), O_RDONLY, 0);
ScopedFdCloser blobs_fd_closer(&blobs_fd);
TEST_AND_RETURN_FALSE(blobs_fd >= 0);
for (;;) {
@@ -262,7 +280,6 @@ bool PayloadFile::WritePayload(const string& payload_file,
TEST_AND_RETURN_FALSE_ERRNO(rc > 0);
TEST_AND_RETURN_FALSE_ERRNO(writer.Write(buf.data(), rc));
}
-
// Write payload signature blob.
if (!private_key_path.empty()) {
LOG(INFO) << "Signing the update...";
@@ -271,15 +288,15 @@ bool PayloadFile::WritePayload(const string& payload_file,
payload_file,
{private_key_path},
metadata_size,
- metadata_signature_size,
- metadata_size + metadata_signature_size + manifest_.signatures_offset(),
+ signature_blob_length,
+ metadata_size + signature_blob_length + manifest.signatures_offset(),
&signature));
TEST_AND_RETURN_FALSE_ERRNO(
writer.Write(signature.data(), signature.size()));
}
-
- ReportPayloadUsage(metadata_size);
- *metadata_size_out = metadata_size;
+ if (metadata_size_out) {
+ *metadata_size_out = metadata_size;
+ }
return true;
}
diff --git a/payload_generator/payload_file.h b/payload_generator/payload_file.h
index 3a457930..86bf2439 100644
--- a/payload_generator/payload_file.h
+++ b/payload_generator/payload_file.h
@@ -56,6 +56,13 @@ class PayloadFile {
const std::string& private_key_path,
uint64_t* metadata_size_out);
+ static bool WritePayload(const std::string& payload_file,
+ const std::string& ordered_blobs_file,
+ const std::string& private_key_path,
+ uint64_t major_version_,
+ const DeltaArchiveManifest& manifest,
+ uint64_t* out_metadata_size);
+
private:
FRIEND_TEST(PayloadFileTest, ReorderBlobsTest);
diff --git a/payload_generator/payload_generation_config.cc b/payload_generator/payload_generation_config.cc
index 2cd2ebcc..d520123b 100644
--- a/payload_generator/payload_generation_config.cc
+++ b/payload_generator/payload_generation_config.cc
@@ -17,6 +17,7 @@
#include "update_engine/payload_generator/payload_generation_config.h"
#include <algorithm>
+#include <charconv>
#include <map>
#include <utility>
@@ -25,11 +26,14 @@
#include <brillo/strings/string_utils.h>
#include <libsnapshot/cow_format.h>
+#include "bsdiff/constants.h"
+#include "payload_consumer/payload_constants.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/delta_performer.h"
#include "update_engine/payload_generator/boot_img_filesystem.h"
#include "update_engine/payload_generator/delta_diff_generator.h"
#include "update_engine/payload_generator/delta_diff_utils.h"
+#include "update_engine/payload_generator/erofs_filesystem.h"
#include "update_engine/payload_generator/ext2_filesystem.h"
#include "update_engine/payload_generator/mapfile_filesystem.h"
#include "update_engine/payload_generator/raw_filesystem.h"
@@ -73,6 +77,11 @@ bool PartitionConfig::OpenFilesystem() {
return true;
}
}
+ fs_interface = ErofsFilesystem::CreateFromFile(path, erofs_compression_param);
+ if (fs_interface) {
+ TEST_AND_RETURN_FALSE(fs_interface->GetBlockSize() == kBlockSize);
+ return true;
+ }
if (!mapfile_path.empty()) {
fs_interface = MapfileFilesystem::CreateFromFile(path, mapfile_path);
@@ -185,7 +194,15 @@ bool ImageConfig::LoadDynamicPartitionMetadata(
}
// We use "gz" compression by default for VABC.
if (metadata->vabc_enabled()) {
- metadata->set_vabc_compression_param("gz");
+ std::string compression_method;
+ if (store.GetString("virtual_ab_compression_method", &compression_method)) {
+ LOG(INFO) << "Using VABC compression method '" << compression_method
+ << "'";
+ } else {
+ LOG(INFO) << "No VABC compression method specified. Defaulting to 'gz'";
+ compression_method = "gz";
+ }
+ metadata->set_vabc_compression_param(compression_method);
metadata->set_cow_version(android::snapshot::kCowVersionManifest);
}
dynamic_partition_metadata = std::move(metadata);
@@ -238,7 +255,9 @@ bool PayloadVersion::Validate() const {
minor == kBrotliBsdiffMinorPayloadVersion ||
minor == kPuffdiffMinorPayloadVersion ||
minor == kVerityMinorPayloadVersion ||
- minor == kPartialUpdateMinorPayloadVersion);
+ minor == kPartialUpdateMinorPayloadVersion ||
+ minor == kZucchiniMinorPayloadVersion ||
+ minor == kLZ4DIFFMinorPayloadVersion);
return true;
}
@@ -270,6 +289,12 @@ bool PayloadVersion::OperationAllowed(InstallOperation::Type operation) const {
case InstallOperation::PUFFDIFF:
return minor >= kPuffdiffMinorPayloadVersion;
+ case InstallOperation::ZUCCHINI:
+ return minor >= kZucchiniMinorPayloadVersion;
+ case InstallOperation::LZ4DIFF_BSDIFF:
+ case InstallOperation::LZ4DIFF_PUFFDIFF:
+ return minor >= kLZ4DIFFMinorPayloadVersion;
+
case InstallOperation::MOVE:
case InstallOperation::BSDIFF:
NOTREACHED();
@@ -322,4 +347,70 @@ bool PayloadGenerationConfig::Validate() const {
return true;
}
+void PayloadGenerationConfig::ParseCompressorTypes(
+ const std::string& compressor_types) {
+ auto types = brillo::string_utils::Split(compressor_types, ":");
+ CHECK_LE(types.size(), 2UL)
+ << "Only two compressor types are allowed: bz2 and brotli";
+ CHECK_GT(types.size(), 0UL) << "Please pass in at least 1 valid compressor. "
+ "Allowed values are bz2 and brotli.";
+ compressors.clear();
+ for (const auto& type : types) {
+ if (type == "bz2") {
+ compressors.emplace_back(bsdiff::CompressorType::kBZ2);
+ } else if (type == "brotli") {
+ compressors.emplace_back(bsdiff::CompressorType::kBrotli);
+ } else {
+ LOG(FATAL) << "Unknown compressor type: " << type;
+ }
+ }
+}
+
+bool PayloadGenerationConfig::OperationEnabled(
+ InstallOperation::Type op) const noexcept {
+ if (!version.OperationAllowed(op)) {
+ return false;
+ }
+ switch (op) {
+ case InstallOperation::ZUCCHINI:
+ return enable_zucchini;
+ case InstallOperation::LZ4DIFF_BSDIFF:
+ case InstallOperation::LZ4DIFF_PUFFDIFF:
+ return enable_lz4diff;
+ default:
+ return true;
+ }
+}
+
+CompressionAlgorithm PartitionConfig::ParseCompressionParam(
+ std::string_view param) {
+ CompressionAlgorithm algo;
+ auto algo_name = param;
+ const auto pos = param.find_first_of(',');
+ if (pos != std::string::npos) {
+ algo_name = param.substr(0, pos);
+ }
+ if (algo_name == "lz4") {
+ algo.set_type(CompressionAlgorithm::LZ4);
+ CHECK_EQ(pos, std::string::npos)
+ << "Invalid compression param " << param
+ << ", compression level not supported for lz4";
+ } else if (algo_name == "lz4hc") {
+ algo.set_type(CompressionAlgorithm::LZ4HC);
+ if (pos != std::string::npos) {
+ const auto level = param.substr(pos + 1);
+ int level_num = 0;
+ const auto [ptr, ec] =
+ std::from_chars(level.data(), level.data() + level.size(), level_num);
+ CHECK_EQ(ec, std::errc()) << "Failed to parse compression level " << level
+ << ", compression param: " << param;
+ algo.set_level(level_num);
+ } else {
+ LOG(FATAL) << "Unrecognized compression type: " << algo_name
+ << ", param: " << param;
+ }
+ }
+ return algo;
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_generator/payload_generation_config.h b/payload_generator/payload_generation_config.h
index 9c8c59f9..7124cb0b 100644
--- a/payload_generator/payload_generation_config.h
+++ b/payload_generator/payload_generation_config.h
@@ -26,6 +26,7 @@
#include <brillo/key_value_store.h>
#include <brillo/secure_blob.h>
+#include "bsdiff/constants.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_generator/filesystem_interface.h"
#include "update_engine/update_metadata.pb.h"
@@ -82,6 +83,13 @@ struct VerityConfig {
struct PartitionConfig {
explicit PartitionConfig(std::string name) : name(name) {}
+ static CompressionAlgorithm ParseCompressionParam(std::string_view param);
+ static CompressionAlgorithm GetDefaultCompressionParam() {
+ CompressionAlgorithm algo;
+ algo.set_type(CompressionAlgorithm::LZ4HC);
+ algo.set_level(9);
+ return algo;
+ }
// Returns whether the PartitionConfig is not an empty image and all the
// fields are set correctly to a valid image file.
@@ -122,6 +130,12 @@ struct PartitionConfig {
// Per-partition version, usually a number representing timestamp.
std::string version;
+
+ // parameter passed to mkfs.erofs's -z option.
+ // In the format of "compressor,compression_level"
+ // Examples: lz4 lz4hc,9
+ // The default is usually lz4hc,9 for mkfs.erofs
+ CompressionAlgorithm erofs_compression_param = GetDefaultCompressionParam();
};
// The ImageConfig struct describes a pair of binaries kernel and rootfs and the
@@ -184,6 +198,8 @@ struct PayloadGenerationConfig {
// Returns whether the PayloadGenerationConfig is valid.
bool Validate() const;
+ void ParseCompressorTypes(const std::string& compressor_types);
+
// Image information about the new image that's the target of this payload.
ImageConfig target;
@@ -233,6 +249,20 @@ struct PayloadGenerationConfig {
// Path to apex_info.pb, extracted from target_file.zip
std::string apex_info_file;
+
+ // Whether to enable VABC xor op
+ bool enable_vabc_xor = false;
+
+ // Whether to enable LZ4diff ops
+ bool enable_lz4diff = false;
+
+ // Whether to enable zucchini ops
+ bool enable_zucchini = true;
+
+ std::vector<bsdiff::CompressorType> compressors{
+ bsdiff::CompressorType::kBZ2, bsdiff::CompressorType::kBrotli};
+
+ [[nodiscard]] bool OperationEnabled(InstallOperation::Type op) const noexcept;
};
} // namespace chromeos_update_engine
diff --git a/payload_generator/payload_signer_unittest.cc b/payload_generator/payload_signer_unittest.cc
index 2a0b394c..2bfc820c 100644
--- a/payload_generator/payload_signer_unittest.cc
+++ b/payload_generator/payload_signer_unittest.cc
@@ -25,6 +25,7 @@
#include "update_engine/common/hash_calculator.h"
#include "update_engine/common/test_utils.h"
+#include "update_engine/common/testing_constants.h"
#include "update_engine/common/utils.h"
#include "update_engine/payload_consumer/payload_constants.h"
#include "update_engine/payload_consumer/payload_verifier.h"
@@ -41,15 +42,6 @@ using std::vector;
namespace chromeos_update_engine {
-const char* kUnittestPrivateKeyPath = "unittest_key.pem";
-const char* kUnittestPublicKeyPath = "unittest_key.pub.pem";
-const char* kUnittestPrivateKey2Path = "unittest_key2.pem";
-const char* kUnittestPublicKey2Path = "unittest_key2.pub.pem";
-const char* kUnittestPrivateKeyRSA4096Path = "unittest_key_RSA4096.pem";
-const char* kUnittestPublicKeyRSA4096Path = "unittest_key_RSA4096.pub.pem";
-const char* kUnittestPrivateKeyECPath = "unittest_key_EC.pem";
-const char* kUnittestPublicKeyECPath = "unittest_key_EC.pub.pem";
-
// Some data and its corresponding hash and signature:
const char kDataToSign[] = "This is some data to sign.";
diff --git a/payload_generator/squashfs_filesystem.cc b/payload_generator/squashfs_filesystem.cc
index a41e2830..16b26eb7 100644
--- a/payload_generator/squashfs_filesystem.cc
+++ b/payload_generator/squashfs_filesystem.cc
@@ -76,12 +76,12 @@ bool GetFileMapContent(const string& sqfs_path, string* map) {
// Run unsquashfs to get the system file map.
// unsquashfs -m <map-file> <squashfs-file>
vector<string> cmd = {"unsquashfs", "-m", map_file.path(), sqfs_path};
- string stdout, stderr;
+ string stdout_str, stderr_str;
int exit_code;
- if (!Subprocess::SynchronousExec(cmd, &exit_code, &stdout, &stderr) ||
+ if (!Subprocess::SynchronousExec(cmd, &exit_code, &stdout_str, &stderr_str) ||
exit_code != 0) {
LOG(ERROR) << "Failed to run `unsquashfs -m` with stdout content: "
- << stdout << " and stderr content: " << stderr;
+ << stdout_str << " and stderr content: " << stderr_str;
return false;
}
TEST_AND_RETURN_FALSE(utils::ReadFile(map_file.path(), map));
@@ -104,12 +104,12 @@ bool GetUpdateEngineConfig(const std::string& sqfs_path, string* config) {
unsquash_dir.GetPath().value(),
sqfs_path,
kUpdateEngineConf};
- string stdout, stderr;
+ string stdout_str, stderr_str;
int exit_code;
- if (!Subprocess::SynchronousExec(cmd, &exit_code, &stdout, &stderr) ||
+ if (!Subprocess::SynchronousExec(cmd, &exit_code, &stdout_str, &stderr_str) ||
exit_code != 0) {
PLOG(ERROR) << "Failed to unsquashfs etc/update_engine.conf with stdout: "
- << stdout << " and stderr: " << stderr;
+ << stdout_str << " and stderr: " << stderr_str;
return false;
}
diff --git a/payload_generator/xz_android.cc b/payload_generator/xz_android.cc
index 41c55f79..9d157c41 100644
--- a/payload_generator/xz_android.cc
+++ b/payload_generator/xz_android.cc
@@ -61,7 +61,6 @@ struct BlobWriterStream : public ISeqOutStream {
size_t size) {
auto* self = static_cast<const BlobWriterStream*>(p);
const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf);
- self->data_->reserve(self->data_->size() + size);
self->data_->insert(self->data_->end(), buffer, buffer + size);
return size;
}
diff --git a/payload_generator/zip_unittest.cc b/payload_generator/zip_unittest.cc
index 10e899b0..6e1f5a3b 100644
--- a/payload_generator/zip_unittest.cc
+++ b/payload_generator/zip_unittest.cc
@@ -21,6 +21,7 @@
#include <string>
#include <vector>
+#include <brillo/secure_blob.h>
#include <gtest/gtest.h>
#include "update_engine/common/test_utils.h"
@@ -54,7 +55,6 @@ class MemoryExtentWriter : public ExtentWriter {
return true;
}
bool Write(const void* bytes, size_t count) override {
- data_->reserve(data_->size() + count);
data_->insert(data_->end(),
static_cast<const uint8_t*>(bytes),
static_cast<const uint8_t*>(bytes) + count);
@@ -67,6 +67,7 @@ class MemoryExtentWriter : public ExtentWriter {
template <typename W>
bool DecompressWithWriter(const brillo::Blob& in, brillo::Blob* out) {
+ out->reserve(in.size());
std::unique_ptr<ExtentWriter> writer(
new W(std::make_unique<MemoryExtentWriter>(out)));
// Init() parameters are ignored by the testing MemoryExtentWriter.
@@ -163,7 +164,7 @@ TYPED_TEST(ZipTest, EmptyInputsTest) {
TYPED_TEST(ZipTest, CompressELFTest) {
string path = test_utils::GetBuildArtifactsPath("delta_generator");
brillo::Blob in;
- utils::ReadFile(path, &in);
+ ASSERT_TRUE(utils::ReadFile(path, &in));
brillo::Blob out;
EXPECT_TRUE(this->ZipCompress(in, &out));
EXPECT_LT(out.size(), in.size());
diff --git a/run_unittests b/run_unittests
deleted file mode 100755
index f07078db..00000000
--- a/run_unittests
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/bash
-
-#
-# Copyright (C) 2012 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.
-#
-
-# Runs the update engine unit tests, including both userland and run-as-root
-# tests.
-
-if [ ! -e ./update_engine_unittests ]; then
- echo 'Error: unit test binary missing' >&2
- exit 1
-fi
-
-user_pass=0
-./update_engine_unittests --gtest_filter='-*.RunAsRoot*' && user_pass=1
-root_pass=0
-sudo ./update_engine_unittests --gtest_filter='*.RunAsRoot*' && root_pass=1
-
-echo -n "User tests: " && [ $user_pass == 1 ] && echo "PASSED" || echo "FAILED"
-echo -n "Root tests: " && [ $root_pass == 1 ] && echo "PASSED" || echo "FAILED"
-
-exit $((2 - user_pass - root_pass))
diff --git a/sample_images/generate_test_erofs_images.sh b/sample_images/generate_test_erofs_images.sh
new file mode 100755
index 00000000..b3b6aa74
--- /dev/null
+++ b/sample_images/generate_test_erofs_images.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+set -e
+
+sh_path=$0
+mkfs=$1
+output_image=$2
+delta_generator=$3
+compression_algo=$4
+
+if [ -z "$compression_algo" ]
+then
+ compression_algo="lz4hc,9"
+fi
+
+fs_root=$(mktemp -d -t erofs-XXXXXXXXXX)
+
+clean_up () {
+ ARG=$?
+ rm -rf $fs_root
+ echo "> clean_up"
+ exit $ARG
+}
+trap clean_up EXIT
+
+if [ ! -z "${delta_generator}" ]; then
+ mkdir -p ${fs_root}/dir1/dir2/dir123/nested_dir
+ mkdir -p ${fs_root}/etc/
+ cp ${sh_path} ${fs_root}/
+ truncate -s 1M ${fs_root}/file1
+ truncate -s 1M ${fs_root}/dir1/file2
+ truncate -s 1M ${fs_root}/dir1/file0
+ truncate -s 1M ${fs_root}/dir1/dir2/file0
+ truncate -s 1M ${fs_root}/dir1/dir2/file1
+ truncate -s 1M ${fs_root}/dir1/dir2/file2
+ truncate -s 1M ${fs_root}/dir1/dir2/file4
+ touch ${fs_root}/dir1/dir2/dir123/empty
+ cp ${delta_generator} ${fs_root}/delta_generator
+ truncate -s 8M ${fs_root}/delta_generator
+ echo "PAYLOAD_MINOR_VERSION=1234" > ${fs_root}/etc/update_engine.conf
+ truncate -s 16M ${fs_root}/dir1/dir2/dir123/chunks_of_zero
+fi
+
+${mkfs} -z $compression_algo ${output_image} ${fs_root}
diff --git a/scripts/brillo_update_payload b/scripts/brillo_update_payload
index 746cefba..b2d60801 100755
--- a/scripts/brillo_update_payload
+++ b/scripts/brillo_update_payload
@@ -38,6 +38,8 @@
# --disable_fec_computation Disable the on device fec data computation for
# incremental update. This feature is enabled by
# default
+# --force_minor_version Override the minor version used for delta
+# generation.
#
# Hash command arguments:
# --unsigned_payload the input unsigned payload to generate the hash from
@@ -204,6 +206,20 @@ a subset of partitions on device."
DEFINE_string full_boot "" "Will include full boot image"
DEFINE_string disable_vabc "" \
"Optional: Disables Virtual AB Compression when installing the OTA"
+ DEFINE_string enable_vabc_xor "" \
+ "Optional: Enable the use of Virtual AB Compression XOR feature"
+ DEFINE_string force_minor_version "" \
+ "Optional: Override the minor version for the delta generation."
+ DEFINE_string compressor_types "" \
+ "Optional: allowed compressor types. Colon separated, allowe values are bz2 and brotli"
+ DEFINE_string enable_zucchini "" \
+ "Optional: Whether to enable zucchini diffing"
+ DEFINE_string enable_lz4diff "" \
+ "Optional: Whether to enable lz4 diffing for EROFS"
+ DEFINE_string liblz4_path "" \
+ "Required if --enabled_lz4diff true is passed. Path to liblz4.so. delta_generator will use this copy of liblz4.so for compression. It is important that this copy of liblz4.so is the same as the one on source build."
+ DEFINE_string erofs_compression_param "" \
+ "Compression parameter passed to mkfs.erofs's -z option."
fi
if [[ "${COMMAND}" == "hash" || "${COMMAND}" == "sign" ]]; then
DEFINE_string unsigned_payload "" "Path to the input unsigned payload."
@@ -547,6 +563,9 @@ using payload minor version 2"
# old updater.
FORCE_MINOR_VERSION=$(read_option_uint "${ue_config}" \
"PAYLOAD_MINOR_VERSION" 2)
+ if [[ -n "${FLAGS_force_minor_version}" ]]; then
+ FORCE_MINOR_VERSION="${FLAGS_force_minor_version}"
+ fi
FORCE_MAJOR_VERSION=$(read_option_uint "${ue_config}" \
"PAYLOAD_MAJOR_VERSION" 2)
@@ -708,6 +727,31 @@ cmd_generate() {
GENERATOR_ARGS+=(
--disable_verity_computation="${FLAGS_disable_verity_computation}" )
fi
+ if [[ -n "${FLAGS_compressor_types}" ]]; then
+ GENERATOR_ARGS+=(
+ --compressor_types="${FLAGS_compressor_types}" )
+ fi
+ if [[ -n "${FLAGS_enable_zucchini}" ]]; then
+ GENERATOR_ARGS+=(
+ --enable_zucchini="${FLAGS_enable_zucchini}" )
+ fi
+ if [[ -n "${FLAGS_enable_lz4diff}" ]]; then
+ if [[ "${FLAGS_enable_lz4diff}" == "true" && -z "${FLAGS_liblz4_path}" ]]; then
+ echo "--liblz4_path is required when enable_lz4diff is set to true."
+ exit 1
+ fi
+ GENERATOR_ARGS+=(
+ --enable_lz4diff="${FLAGS_enable_lz4diff}" )
+ fi
+ if [[ -n "${FLAGS_erofs_compression_param}" ]]; then
+ GENERATOR_ARGS+=(
+ --erofs_compression_param="${FLAGS_erofs_compression_param}" )
+ fi
+ fi
+
+ if [[ -n "${FLAGS_enable_vabc_xor}" ]]; then
+ GENERATOR_ARGS+=(
+ --enable_vabc_xor="${FLAGS_enable_vabc_xor}" )
fi
if [[ -n "${FLAGS_disable_vabc}" ]]; then
@@ -754,7 +798,11 @@ cmd_generate() {
fi
echo "Running delta_generator with args: ${GENERATOR_ARGS[@]}"
- "${GENERATOR}" "${GENERATOR_ARGS[@]}"
+ if [[ -n "${FLAGS_enable_lz4diff}" ]]; then
+ LD_PRELOAD=${LD_PRELOAD}:${FLAGS_liblz4_path} "${GENERATOR}" "${GENERATOR_ARGS[@]}"
+ else
+ "${GENERATOR}" "${GENERATOR_ARGS[@]}"
+ fi
echo "Done generating ${payload_type} update."
}
diff --git a/scripts/scan_lz4.py b/scripts/scan_lz4.py
new file mode 100644
index 00000000..d2b4fb57
--- /dev/null
+++ b/scripts/scan_lz4.py
@@ -0,0 +1,82 @@
+# import mmap
+
+import struct
+
+LZ4_FRAME_MAGIC = b"\x04\x22\x4D\x18"
+
+
+def scan_legacy_lz4_frames(data):
+ LZ4_LEGACY_FRAME_MAGIC = b"\x02\x21\x4C\x18"
+ index = 0
+ while index < len(data):
+ try:
+ index = data.index(LZ4_LEGACY_FRAME_MAGIC, index)
+ print("Legacy Lz4 frame at {}".format(index))
+ index += 4
+ while index < len(data):
+ magic = data[index:index+4]
+ if magic == LZ4_LEGACY_FRAME_MAGIC or magic == LZ4_FRAME_MAGIC:
+ break
+ (csize,) = struct.unpack("<L", magic)
+ if index + 4 + csize >= len(data) or csize == 0:
+ break
+ print("Legacy lz4 block at {}, compressed data size {}".format(index, csize))
+ index += csize
+
+ except ValueError:
+ break
+
+
+def scan_lz4_frames(data):
+ index = 0
+ while index < len(data):
+ try:
+ index = data.index(LZ4_FRAME_MAGIC, index)
+ frame_offset = index
+ index += 4
+ flag = data[index]
+ block_descriptor = data[index+1]
+ block_checksum_present = flag & 0x10 != 0
+ content_size_present = flag & 0x8 != 0
+ content_checksum_present = flag & 0x4 != 0
+ dictionary_id = flag & 0x1 != 0
+ index += 2
+ content_size = None
+ if content_size_present:
+ content_size = struct.unpack("<Q", data[index:index+8])
+ index += 8
+ if dictionary_id:
+ dictionary_id = struct.unpack("<L", data[index:index+4])
+ index += 4
+ header_checksum = data[index:index+1]
+ index += 1
+ print("Lz4 frame at {}, content size: {}".format(
+ frame_offset, content_size))
+ while index < len(data):
+ (block_size,) = struct.unpack("<L", data[index:index+4])
+ uncompressed = block_size & 0x80000000 != 0
+ block_size &= 0x7FFFFFFF
+ index += 4
+ index += block_size
+ if index >= len(data) or block_size == 0:
+ break
+ print("Block uncompressed: {}, size: {}".format(uncompressed, block_size))
+ except ValueError:
+ break
+
+
+def main(argv):
+ if len(argv) != 2:
+ print("Usage:", argv[0], "<path to a file>")
+ return 1
+ path = argv[1]
+
+ with open(path, "rb") as fp:
+ data = fp.read()
+ scan_legacy_lz4_frames(data)
+ scan_lz4_frames(data)
+
+
+if __name__ == '__main__':
+ import sys
+ sys.exit(main(sys.argv))
diff --git a/scripts/simulate_ota.py b/scripts/simulate_ota.py
index 63499799..bf1fc984 100644
--- a/scripts/simulate_ota.py
+++ b/scripts/simulate_ota.py
@@ -41,28 +41,39 @@ def extract_file(zip_file_path, entry_name, target_file_path):
with open(os.path.join(zip_file_path, entry_name), "rb") as fp:
shutil.copyfileobj(fp, out_fp)
+
def is_sparse_image(filepath):
with open(filepath, 'rb') as fp:
# Magic for android sparse image format
# https://source.android.com/devices/bootloader/images
return fp.read(4) == b'\x3A\xFF\x26\xED'
-def extract_img(zip_archive, img_name, output_path):
+
+def extract_img(zip_archive: zipfile.ZipFile, img_name, output_path):
entry_name = "IMAGES/" + img_name + ".img"
- extract_file(zip_archive, entry_name, output_path)
+ try:
+ extract_file(zip_archive, entry_name, output_path)
+ except (KeyError, FileNotFoundError) as e:
+ print("Faild to extract", img_name, "from IMAGES/ dir, trying RADIO/", e)
+ extract_file(zip_archive, "RADIO/" + img_name + ".img", output_path)
if is_sparse_image(output_path):
raw_img_path = output_path + ".raw"
subprocess.check_output(["simg2img", output_path, raw_img_path])
os.rename(raw_img_path, output_path)
-def run_ota(source, target, payload_path, tempdir):
+
+def run_ota(source, target, payload_path, tempdir, output_dir):
"""Run an OTA on host side"""
payload = update_payload.Payload(payload_path)
payload.Init()
- if zipfile.is_zipfile(source):
+ if source and zipfile.is_zipfile(source):
source = zipfile.ZipFile(source)
- if zipfile.is_zipfile(target):
+ if target and zipfile.is_zipfile(target):
target = zipfile.ZipFile(target)
+ source_exist = source and (isinstance(
+ source, zipfile.ZipFile) or os.path.exists(source))
+ target_exist = target and (isinstance(
+ target, zipfile.ZipFile) or os.path.exists(target))
old_partitions = []
new_partitions = []
@@ -71,10 +82,15 @@ def run_ota(source, target, payload_path, tempdir):
name = part.partition_name
old_image = os.path.join(tempdir, "source_" + name + ".img")
new_image = os.path.join(tempdir, "target_" + name + ".img")
- print("Extracting source image for", name)
- extract_img(source, name, old_image)
- print("Extracting target image for", name)
- extract_img(target, name, new_image)
+ if part.HasField("old_partition_info"):
+ assert source_exist, \
+ "source target file must point to a valid zipfile or directory " + \
+ source
+ print("Extracting source image for", name)
+ extract_img(source, name, old_image)
+ if target_exist:
+ print("Extracting target image for", name)
+ extract_img(target, name, new_image)
old_partitions.append(old_image)
scratch_image_name = new_image + ".actual"
@@ -87,15 +103,24 @@ def run_ota(source, target, payload_path, tempdir):
partition_names = [
part.partition_name for part in payload.manifest.partitions
]
+ if payload.manifest.partial_update:
+ delta_generator_args.append("--is_partial_update")
+ if payload.is_incremental:
+ delta_generator_args.append("--old_partitions=" + ":".join(old_partitions))
delta_generator_args.append("--partition_names=" + ":".join(partition_names))
- delta_generator_args.append("--old_partitions=" + ":".join(old_partitions))
delta_generator_args.append("--new_partitions=" + ":".join(new_partitions))
+ print("Running ", " ".join(delta_generator_args))
subprocess.check_output(delta_generator_args)
valid = True
+ if not target_exist:
+ for part in new_partitions:
+ print("Output written to", part)
+ shutil.copy(part, output_dir)
+ return
for (expected_part, actual_part, part_name) in \
- zip(expected_new_partitions, new_partitions, partition_names):
+ zip(expected_new_partitions, new_partitions, partition_names):
if filecmp.cmp(expected_part, actual_part):
print("Partition `{}` is valid".format(part_name))
else:
@@ -114,11 +139,16 @@ def main():
parser.add_argument(
"--source",
help="Target file zip for the source build",
- required=True, nargs=1)
+ required=False)
parser.add_argument(
"--target",
help="Target file zip for the target build",
- required=True, nargs=1)
+ required=False)
+ parser.add_argument(
+ "-o",
+ dest="output_dir",
+ help="Output directory to put all images, current directory by default"
+ )
parser.add_argument(
"payload",
help="payload.bin for the OTA package, or a zip of OTA package itself",
@@ -126,11 +156,6 @@ def main():
args = parser.parse_args()
print(args)
- assert os.path.exists(args.source[0]), \
- "source target file must point to a valid zipfile or directory"
- assert os.path.exists(args.target[0]), \
- "target path must point to a valid zipfile or directory"
-
# pylint: disable=no-member
with tempfile.TemporaryDirectory() as tempdir:
payload_path = args.payload[0]
@@ -139,8 +164,12 @@ def main():
payload_entry_name = 'payload.bin'
zfp.extract(payload_entry_name, tempdir)
payload_path = os.path.join(tempdir, payload_entry_name)
-
- run_ota(args.source[0], args.target[0], payload_path, tempdir)
+ if args.output_dir is None:
+ args.output_dir = "."
+ if not os.path.exists(args.output_dir):
+ os.makedirs(args.output_dir, exist_ok=True)
+ assert os.path.isdir(args.output_dir)
+ run_ota(args.source, args.target, payload_path, tempdir, args.output_dir)
if __name__ == '__main__':
diff --git a/scripts/trim_ota_package.py b/scripts/trim_ota_package.py
new file mode 100644
index 00000000..df7f1703
--- /dev/null
+++ b/scripts/trim_ota_package.py
@@ -0,0 +1,38 @@
+#!/usr/bin/env python3
+
+import zipfile
+import struct
+
+
+def readPayloadMetadata(zfp: zipfile.ZipFile, entry):
+ _MAGIC = b'CrAU'
+ # 8 bytes for version, 8 bytes for manifest length, 4 bytes for metadata signature length
+ HEADER_STRUCT = ">4sQQL"
+ HEADER_LEN = struct.calcsize(HEADER_STRUCT)
+ with zfp.open(entry) as fp:
+ header = fp.read(HEADER_LEN)
+ (magic, version, manifest_length,
+ metadata_signature_len) = struct.unpack(HEADER_STRUCT, header)
+ assert magic == _MAGIC
+ assert version == 2, "Unsupported major payload version " + str(version)
+ print(f"{manifest_length} {metadata_signature_len}")
+ return header + fp.read(manifest_length + metadata_signature_len)
+
+
+def main(argv):
+ if len(argv) != 3:
+ print("Usage:", argv[0], "<input file> <output file>")
+ return 1
+ infile = argv[1]
+ outfile = argv[2]
+ with zipfile.ZipFile(infile, "r") as inzfp, zipfile.ZipFile(outfile, "w") as outzfp:
+ for entry in inzfp.infolist():
+ if entry.filename.startswith("META") or entry.filename.endswith(".map"):
+ outzfp.writestr(entry, inzfp.read(entry))
+ elif entry.filename == "payload.bin":
+ outzfp.writestr(entry, readPayloadMetadata(inzfp, entry))
+
+
+if __name__ == '__main__':
+ import sys
+ sys.exit(main(sys.argv))
diff --git a/scripts/update_device.py b/scripts/update_device.py
index f672cda0..72cee494 100755
--- a/scripts/update_device.py
+++ b/scripts/update_device.py
@@ -30,6 +30,7 @@ import subprocess
import sys
import struct
import tempfile
+import time
import threading
import xml.etree.ElementTree
import zipfile
@@ -437,10 +438,18 @@ def main():
help='Verify metadata then exit, instead of applying the OTA.')
parser.add_argument('--no-care-map', action='store_true',
help='Do not push care_map.pb to device.')
+ parser.add_argument('--perform-slot-switch', action='store_true',
+ help='Perform slot switch for this OTA package')
+ parser.add_argument('--perform-reset-slot-switch', action='store_true',
+ help='Perform reset slot switch for this OTA package')
+ parser.add_argument('--wipe-user-data', action='store_true',
+ help='Wipe userdata after installing OTA')
args = parser.parse_args()
logging.basicConfig(
level=logging.WARNING if args.no_verbose else logging.INFO)
+ start_time = time.perf_counter()
+
dut = AdbHost(args.s)
server_thread = None
@@ -471,11 +480,23 @@ def main():
# Return 0, as we are executing ADB commands here, no work needed after
# this point
return 0
+ if args.perform_slot_switch:
+ assert PushMetadata(dut, args.otafile, metadata_path)
+ dut.adb(["shell", "update_engine_client",
+ "--switch_slot=true", "--metadata={}".format(metadata_path), "--follow"])
+ return 0
+ if args.perform_reset_slot_switch:
+ assert PushMetadata(dut, args.otafile, metadata_path)
+ dut.adb(["shell", "update_engine_client",
+ "--switch_slot=false", "--metadata={}".format(metadata_path)])
+ return 0
if args.no_slot_switch:
args.extra_headers += "\nSWITCH_SLOT_ON_REBOOT=0"
if args.no_postinstall:
args.extra_headers += "\nRUN_POST_INSTALL=0"
+ if args.wipe_user_data:
+ args.extra_headers += "\nPOWERWASH=1"
with zipfile.ZipFile(args.otafile) as zfp:
CARE_MAP_ENTRY_NAME = "care_map.pb"
@@ -548,6 +569,7 @@ def main():
for cmd in finalize_cmds:
dut.adb(cmd, 5)
+ logging.info('Update took %.3f seconds', (time.perf_counter() - start_time))
return 0
diff --git a/scripts/update_payload/common.py b/scripts/update_payload/common.py
index b934cf88..7c6ec8fe 100644
--- a/scripts/update_payload/common.py
+++ b/scripts/update_payload/common.py
@@ -62,8 +62,9 @@ class OpType(object):
REPLACE_XZ = _CLASS.REPLACE_XZ
PUFFDIFF = _CLASS.PUFFDIFF
BROTLI_BSDIFF = _CLASS.BROTLI_BSDIFF
+ ZUCCHINI = _CLASS.ZUCCHINI
ALL = (REPLACE, REPLACE_BZ, SOURCE_COPY, SOURCE_BSDIFF, ZERO,
- DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF)
+ DISCARD, REPLACE_XZ, PUFFDIFF, BROTLI_BSDIFF, ZUCCHINI)
NAMES = {
REPLACE: 'REPLACE',
REPLACE_BZ: 'REPLACE_BZ',
@@ -74,6 +75,7 @@ class OpType(object):
REPLACE_XZ: 'REPLACE_XZ',
PUFFDIFF: 'PUFFDIFF',
BROTLI_BSDIFF: 'BROTLI_BSDIFF',
+ ZUCCHINI: 'ZUCCHINI',
}
def __init__(self):
diff --git a/scripts/update_payload/payload.py b/scripts/update_payload/payload.py
index 998703ad..86caef7d 100644
--- a/scripts/update_payload/payload.py
+++ b/scripts/update_payload/payload.py
@@ -127,7 +127,8 @@ class Payload(object):
self.payload_file = zfp.open("payload.bin", "r")
elif isinstance(payload_file, str):
payload_fp = open(payload_file, "rb")
- payload_bytes = mmap.mmap(payload_fp.fileno(), 0, access=mmap.ACCESS_READ)
+ payload_bytes = mmap.mmap(
+ payload_fp.fileno(), 0, access=mmap.ACCESS_READ)
self.payload_file = io.BytesIO(payload_bytes)
else:
self.payload_file = payload_file
@@ -138,8 +139,17 @@ class Payload(object):
self.manifest = None
self.data_offset = None
self.metadata_signature = None
+ self.payload_signature = None
self.metadata_size = None
+ @property
+ def is_incremental(self):
+ return any([part.HasField("old_partition_info") for part in self.manifest.partitions])
+
+ @property
+ def is_partial(self):
+ return self.manifest.partial_update
+
def _ReadHeader(self):
"""Reads and returns the payload header.
@@ -235,6 +245,13 @@ class Payload(object):
self.metadata_size = self.header.size + self.header.manifest_len
self.data_offset = self.metadata_size + self.header.metadata_signature_len
+ if self.manifest.signatures_offset and self.manifest.signatures_size:
+ payload_signature_blob = self.ReadDataBlob(
+ self.manifest.signatures_offset, self.manifest.signatures_size)
+ payload_signature = update_metadata_pb2.Signatures()
+ payload_signature.ParseFromString(payload_signature_blob)
+ self.payload_signature = payload_signature
+
self.is_init = True
def _AssertInit(self):
diff --git a/scripts/update_payload/update_metadata_pb2.py b/scripts/update_payload/update_metadata_pb2.py
index 9aef9f2f..b62a67a1 100644
--- a/scripts/update_payload/update_metadata_pb2.py
+++ b/scripts/update_payload/update_metadata_pb2.py
@@ -20,7 +20,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='chromeos_update_engine',
syntax='proto2',
serialized_options=_b('H\003'),
- serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"\x9f\x01\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1aO\n\tSignature\x12\x13\n\x07version\x18\x01 \x01(\rB\x02\x18\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x1f\n\x17unpadded_signature_size\x18\x03 \x01(\x07\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"\x8f\x01\n\tImageInfo\x12\x11\n\x05\x62oard\x18\x01 \x01(\tB\x02\x18\x01\x12\x0f\n\x03key\x18\x02 \x01(\tB\x02\x18\x01\x12\x13\n\x07\x63hannel\x18\x03 \x01(\tB\x02\x18\x01\x12\x13\n\x07version\x18\x04 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_channel\x18\x05 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_version\x18\x06 \x01(\tB\x02\x18\x01\"\xee\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xad\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\"\xcf\x01\n\x11\x43owMergeOperation\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromeos_update_engine.CowMergeOperation.Type\x12\x32\n\nsrc_extent\x18\x02 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\ndst_extent\x18\x03 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\"\x14\n\x04Type\x12\x0c\n\x08\x43OW_COPY\x10\x00\"\xc8\x06\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\x12\x0f\n\x07version\x18\x11 \x01(\t\x12\x43\n\x10merge_operations\x18\x12 \x03(\x0b\x32).chromeos_update_engine.CowMergeOperation\x12\x19\n\x11\x65stimate_cow_size\x18\x13 \x01(\x04\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"\xa9\x01\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\x12\x14\n\x0cvabc_enabled\x18\x03 \x01(\x08\x12\x1e\n\x16vabc_compression_param\x18\x04 \x01(\t\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"C\n\x0c\x41pexMetadata\x12\x33\n\tapex_info\x18\x01 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\"\x9e\x07\n\x14\x44\x65ltaArchiveManifest\x12H\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12O\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12\x42\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12=\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12=\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadata\x12\x16\n\x0epartial_update\x18\x10 \x01(\x08\x12\x33\n\tapex_info\x18\x11 \x03(\x0b\x32 .chromeos_update_engine.ApexInfoB\x02H\x03')
+ serialized_pb=_b('\n\x15update_metadata.proto\x12\x16\x63hromeos_update_engine\"1\n\x06\x45xtent\x12\x13\n\x0bstart_block\x18\x01 \x01(\x04\x12\x12\n\nnum_blocks\x18\x02 \x01(\x04\"\x9f\x01\n\nSignatures\x12@\n\nsignatures\x18\x01 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x1aO\n\tSignature\x12\x13\n\x07version\x18\x01 \x01(\rB\x02\x18\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x1f\n\x17unpadded_signature_size\x18\x03 \x01(\x07\"+\n\rPartitionInfo\x12\x0c\n\x04size\x18\x01 \x01(\x04\x12\x0c\n\x04hash\x18\x02 \x01(\x0c\"\x8f\x01\n\tImageInfo\x12\x11\n\x05\x62oard\x18\x01 \x01(\tB\x02\x18\x01\x12\x0f\n\x03key\x18\x02 \x01(\tB\x02\x18\x01\x12\x13\n\x07\x63hannel\x18\x03 \x01(\tB\x02\x18\x01\x12\x13\n\x07version\x18\x04 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_channel\x18\x05 \x01(\tB\x02\x18\x01\x12\x19\n\rbuild_version\x18\x06 \x01(\tB\x02\x18\x01\"\xfc\x03\n\x10InstallOperation\x12;\n\x04type\x18\x01 \x02(\x0e\x32-.chromeos_update_engine.InstallOperation.Type\x12\x13\n\x0b\x64\x61ta_offset\x18\x02 \x01(\x04\x12\x13\n\x0b\x64\x61ta_length\x18\x03 \x01(\x04\x12\x33\n\x0bsrc_extents\x18\x04 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_length\x18\x05 \x01(\x04\x12\x33\n\x0b\x64st_extents\x18\x06 \x03(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\ndst_length\x18\x07 \x01(\x04\x12\x18\n\x10\x64\x61ta_sha256_hash\x18\x08 \x01(\x0c\x12\x17\n\x0fsrc_sha256_hash\x18\t \x01(\x0c\"\xbb\x01\n\x04Type\x12\x0b\n\x07REPLACE\x10\x00\x12\x0e\n\nREPLACE_BZ\x10\x01\x12\x0c\n\x04MOVE\x10\x02\x1a\x02\x08\x01\x12\x0e\n\x06\x42SDIFF\x10\x03\x1a\x02\x08\x01\x12\x0f\n\x0bSOURCE_COPY\x10\x04\x12\x11\n\rSOURCE_BSDIFF\x10\x05\x12\x0e\n\nREPLACE_XZ\x10\x08\x12\x08\n\x04ZERO\x10\x06\x12\x0b\n\x07\x44ISCARD\x10\x07\x12\x11\n\rBROTLI_BSDIFF\x10\n\x12\x0c\n\x08PUFFDIFF\x10\t\x12\x0c\n\x08ZUCCHINI\x10\x0b\"\x81\x02\n\x11\x43owMergeOperation\x12<\n\x04type\x18\x01 \x01(\x0e\x32..chromeos_update_engine.CowMergeOperation.Type\x12\x32\n\nsrc_extent\x18\x02 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\ndst_extent\x18\x03 \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x12\n\nsrc_offset\x18\x04 \x01(\r\"2\n\x04Type\x12\x0c\n\x08\x43OW_COPY\x10\x00\x12\x0b\n\x07\x43OW_XOR\x10\x01\x12\x0f\n\x0b\x43OW_REPLACE\x10\x02\"\xc8\x06\n\x0fPartitionUpdate\x12\x16\n\x0epartition_name\x18\x01 \x02(\t\x12\x17\n\x0frun_postinstall\x18\x02 \x01(\x08\x12\x18\n\x10postinstall_path\x18\x03 \x01(\t\x12\x17\n\x0f\x66ilesystem_type\x18\x04 \x01(\t\x12M\n\x17new_partition_signature\x18\x05 \x03(\x0b\x32,.chromeos_update_engine.Signatures.Signature\x12\x41\n\x12old_partition_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12\x41\n\x12new_partition_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfo\x12<\n\noperations\x18\x08 \x03(\x0b\x32(.chromeos_update_engine.InstallOperation\x12\x1c\n\x14postinstall_optional\x18\t \x01(\x08\x12=\n\x15hash_tree_data_extent\x18\n \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x38\n\x10hash_tree_extent\x18\x0b \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x1b\n\x13hash_tree_algorithm\x18\x0c \x01(\t\x12\x16\n\x0ehash_tree_salt\x18\r \x01(\x0c\x12\x37\n\x0f\x66\x65\x63_data_extent\x18\x0e \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x32\n\nfec_extent\x18\x0f \x01(\x0b\x32\x1e.chromeos_update_engine.Extent\x12\x14\n\tfec_roots\x18\x10 \x01(\r:\x01\x32\x12\x0f\n\x07version\x18\x11 \x01(\t\x12\x43\n\x10merge_operations\x18\x12 \x03(\x0b\x32).chromeos_update_engine.CowMergeOperation\x12\x19\n\x11\x65stimate_cow_size\x18\x13 \x01(\x04\"L\n\x15\x44ynamicPartitionGroup\x12\x0c\n\x04name\x18\x01 \x02(\t\x12\x0c\n\x04size\x18\x02 \x01(\x04\x12\x17\n\x0fpartition_names\x18\x03 \x03(\t\"\xbe\x01\n\x18\x44ynamicPartitionMetadata\x12=\n\x06groups\x18\x01 \x03(\x0b\x32-.chromeos_update_engine.DynamicPartitionGroup\x12\x18\n\x10snapshot_enabled\x18\x02 \x01(\x08\x12\x14\n\x0cvabc_enabled\x18\x03 \x01(\x08\x12\x1e\n\x16vabc_compression_param\x18\x04 \x01(\t\x12\x13\n\x0b\x63ow_version\x18\x05 \x01(\r\"c\n\x08\x41pexInfo\x12\x14\n\x0cpackage_name\x18\x01 \x01(\t\x12\x0f\n\x07version\x18\x02 \x01(\x03\x12\x15\n\ris_compressed\x18\x03 \x01(\x08\x12\x19\n\x11\x64\x65\x63ompressed_size\x18\x04 \x01(\x03\"C\n\x0c\x41pexMetadata\x12\x33\n\tapex_info\x18\x01 \x03(\x0b\x32 .chromeos_update_engine.ApexInfo\"\x9e\x07\n\x14\x44\x65ltaArchiveManifest\x12H\n\x12install_operations\x18\x01 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12O\n\x19kernel_install_operations\x18\x02 \x03(\x0b\x32(.chromeos_update_engine.InstallOperationB\x02\x18\x01\x12\x18\n\nblock_size\x18\x03 \x01(\r:\x04\x34\x30\x39\x36\x12\x19\n\x11signatures_offset\x18\x04 \x01(\x04\x12\x17\n\x0fsignatures_size\x18\x05 \x01(\x04\x12\x42\n\x0fold_kernel_info\x18\x06 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_kernel_info\x18\x07 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fold_rootfs_info\x18\x08 \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12\x42\n\x0fnew_rootfs_info\x18\t \x01(\x0b\x32%.chromeos_update_engine.PartitionInfoB\x02\x18\x01\x12=\n\x0eold_image_info\x18\n \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12=\n\x0enew_image_info\x18\x0b \x01(\x0b\x32!.chromeos_update_engine.ImageInfoB\x02\x18\x01\x12\x18\n\rminor_version\x18\x0c \x01(\r:\x01\x30\x12;\n\npartitions\x18\r \x03(\x0b\x32\'.chromeos_update_engine.PartitionUpdate\x12\x15\n\rmax_timestamp\x18\x0e \x01(\x03\x12T\n\x1a\x64ynamic_partition_metadata\x18\x0f \x01(\x0b\x32\x30.chromeos_update_engine.DynamicPartitionMetadata\x12\x16\n\x0epartial_update\x18\x10 \x01(\x08\x12\x33\n\tapex_info\x18\x11 \x03(\x0b\x32 .chromeos_update_engine.ApexInfoB\x02H\x03')
)
@@ -75,11 +75,15 @@ _INSTALLOPERATION_TYPE = _descriptor.EnumDescriptor(
name='PUFFDIFF', index=10, number=9,
serialized_options=None,
type=None),
+ _descriptor.EnumValueDescriptor(
+ name='ZUCCHINI', index=11, number=11,
+ serialized_options=None,
+ type=None),
],
containing_type=None,
serialized_options=None,
serialized_start=775,
- serialized_end=948,
+ serialized_end=962,
)
_sym_db.RegisterEnumDescriptor(_INSTALLOPERATION_TYPE)
@@ -93,11 +97,19 @@ _COWMERGEOPERATION_TYPE = _descriptor.EnumDescriptor(
name='COW_COPY', index=0, number=0,
serialized_options=None,
type=None),
+ _descriptor.EnumValueDescriptor(
+ name='COW_XOR', index=1, number=1,
+ serialized_options=None,
+ type=None),
+ _descriptor.EnumValueDescriptor(
+ name='COW_REPLACE', index=2, number=2,
+ serialized_options=None,
+ type=None),
],
containing_type=None,
serialized_options=None,
- serialized_start=1138,
- serialized_end=1158,
+ serialized_start=1172,
+ serialized_end=1222,
)
_sym_db.RegisterEnumDescriptor(_COWMERGEOPERATION_TYPE)
@@ -403,7 +415,7 @@ _INSTALLOPERATION = _descriptor.Descriptor(
oneofs=[
],
serialized_start=454,
- serialized_end=948,
+ serialized_end=962,
)
@@ -435,6 +447,13 @@ _COWMERGEOPERATION = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='src_offset', full_name='chromeos_update_engine.CowMergeOperation.src_offset', index=3,
+ number=4, type=13, cpp_type=3, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@@ -448,8 +467,8 @@ _COWMERGEOPERATION = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=951,
- serialized_end=1158,
+ serialized_start=965,
+ serialized_end=1222,
)
@@ -605,8 +624,8 @@ _PARTITIONUPDATE = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=1161,
- serialized_end=2001,
+ serialized_start=1225,
+ serialized_end=2065,
)
@@ -650,8 +669,8 @@ _DYNAMICPARTITIONGROUP = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2003,
- serialized_end=2079,
+ serialized_start=2067,
+ serialized_end=2143,
)
@@ -690,6 +709,13 @@ _DYNAMICPARTITIONMETADATA = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='cow_version', full_name='chromeos_update_engine.DynamicPartitionMetadata.cow_version', index=4,
+ number=5, type=13, cpp_type=3, label=1,
+ has_default_value=False, default_value=0,
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@@ -702,8 +728,8 @@ _DYNAMICPARTITIONMETADATA = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2082,
- serialized_end=2251,
+ serialized_start=2146,
+ serialized_end=2336,
)
@@ -754,8 +780,8 @@ _APEXINFO = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2253,
- serialized_end=2352,
+ serialized_start=2338,
+ serialized_end=2437,
)
@@ -785,8 +811,8 @@ _APEXMETADATA = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2354,
- serialized_end=2421,
+ serialized_start=2439,
+ serialized_end=2506,
)
@@ -928,8 +954,8 @@ _DELTAARCHIVEMANIFEST = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
- serialized_start=2424,
- serialized_end=3350,
+ serialized_start=2509,
+ serialized_end=3435,
)
_SIGNATURES_SIGNATURE.containing_type = _SIGNATURES
diff --git a/stable/Android.bp b/stable/Android.bp
index 1573ebd2..73a9c373 100644
--- a/stable/Android.bp
+++ b/stable/Android.bp
@@ -68,7 +68,7 @@ cc_binary {
],
static_libs: [
"libgflags",
- "libupdate_engine_stable-V1-ndk_platform",
+ "libupdate_engine_stable-V1-ndk",
],
srcs: [
"update_engine_stable_client.cc",
diff --git a/test_http_server.cc b/test_http_server.cc
index a2f1e052..388949f1 100644
--- a/test_http_server.cc
+++ b/test_http_server.cc
@@ -253,14 +253,14 @@ size_t WritePayload(int fd,
if (start_modulo) {
string partial = line.substr(start_modulo, remaining_len);
ssize_t ret = WriteString(fd, partial);
- if ((success = (ret >= 0 && (size_t)ret == partial.length())))
+ if ((success = (ret >= 0 && static_cast<size_t>(ret) == partial.length())))
remaining_len -= partial.length();
}
// Output full lines up to the maximal line boundary below the end offset.
while (success && remaining_len >= line_len) {
ssize_t ret = WriteString(fd, line);
- if ((success = (ret >= 0 && (size_t)ret == line_len)))
+ if ((success = (ret >= 0 && static_cast<size_t>(ret) == line_len)))
remaining_len -= line_len;
}
@@ -268,7 +268,7 @@ size_t WritePayload(int fd,
if (success && remaining_len) {
string partial = line.substr(0, remaining_len);
ssize_t ret = WriteString(fd, partial);
- if ((success = (ret >= 0 && (size_t)ret == partial.length())))
+ if ((success = (ret >= 0 && static_cast<size_t>(ret) == partial.length())))
remaining_len -= partial.length();
}
diff --git a/update_engine.conf b/update_engine.conf
index b6ca3c47..2d3a6553 100644
--- a/update_engine.conf
+++ b/update_engine.conf
@@ -1,2 +1,2 @@
PAYLOAD_MAJOR_VERSION=2
-PAYLOAD_MINOR_VERSION=7
+PAYLOAD_MINOR_VERSION=8
diff --git a/update_engine.rc b/update_engine.rc
index b9f80fc1..bc6447b2 100644
--- a/update_engine.rc
+++ b/update_engine.rc
@@ -2,7 +2,7 @@ service update_engine /system/bin/update_engine --logtostderr --logtofile --fore
class late_start
user root
group root system wakelock inet cache media_rw
- writepid /dev/cpuset/system-background/tasks /dev/blkio/background/tasks
+ task_profiles OtaProfiles
disabled
on property:ro.boot.slot_suffix=*
diff --git a/update_manager/api_restricted_downloads_policy_impl.cc b/update_manager/api_restricted_downloads_policy_impl.cc
deleted file mode 100644
index d413ccab..00000000
--- a/update_manager/api_restricted_downloads_policy_impl.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-//
-// 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/update_manager/api_restricted_downloads_policy_impl.h"
-
-using chromeos_update_engine::ErrorCode;
-using std::string;
-using std::vector;
-
-namespace chromeos_update_manager {
-
-// Allow the API to restrict the downloading of updates.
-EvalStatus ApiRestrictedDownloadsPolicyImpl::UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const {
- // Next, check to see if updates can be applied (in general).
- const UpdateRestrictions* update_restrictions_p =
- ec->GetValue(state->updater_provider()->var_update_restrictions());
- if (update_restrictions_p) {
- if (*update_restrictions_p & UpdateRestrictions::kRestrictDownloading) {
- *result = ErrorCode::kOmahaUpdateDeferredPerPolicy;
- return EvalStatus::kSucceeded;
- }
- }
-
- // The API isn't restricting downloads, so implicitly allow them to happen
- // but don't explicitly return success from this policy implementation.
- return EvalStatus::kContinue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/api_restricted_downloads_policy_impl.h b/update_manager/api_restricted_downloads_policy_impl.h
deleted file mode 100644
index 21457a5d..00000000
--- a/update_manager/api_restricted_downloads_policy_impl.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// 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_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Allow the API to restrict the downloading of updates.
-class ApiRestrictedDownloadsPolicyImpl : public PolicyImplBase {
- public:
- ApiRestrictedDownloadsPolicyImpl() = default;
- ~ApiRestrictedDownloadsPolicyImpl() override = default;
-
- // Policy overrides.
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override;
-
- protected:
- std::string PolicyName() const override {
- return "ApiRestrictedDownloadsPolicyImpl";
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ApiRestrictedDownloadsPolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_API_RESTRICTED_DOWNLOADS_POLICY_IMPL_H_
diff --git a/update_manager/boxed_value.cc b/update_manager/boxed_value.cc
deleted file mode 100644
index 907eb959..00000000
--- a/update_manager/boxed_value.cc
+++ /dev/null
@@ -1,264 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/boxed_value.h"
-
-#include <stdint.h>
-
-#include <set>
-#include <string>
-
-#include <base/strings/string_number_conversions.h>
-#include <base/time/time.h>
-#include <base/version.h>
-
-#include "update_engine/common/connection_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/update_manager/rollback_prefs.h"
-#include "update_engine/update_manager/shill_provider.h"
-#include "update_engine/update_manager/updater_provider.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-using chromeos_update_engine::ConnectionTethering;
-using chromeos_update_engine::ConnectionType;
-using chromeos_update_engine::connection_utils::StringForConnectionType;
-using std::set;
-using std::string;
-
-namespace chromeos_update_manager {
-
-// Template instantiation for common types; used in BoxedValue::ToString().
-// Keep in sync with boxed_value_unitttest.cc.
-
-template <>
-string BoxedValue::ValuePrinter<string>(const void* value) {
- const string* val = reinterpret_cast<const string*>(value);
- return *val;
-}
-
-template <>
-string BoxedValue::ValuePrinter<int>(const void* value) {
- const int* val = reinterpret_cast<const int*>(value);
- return base::NumberToString(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<unsigned int>(const void* value) {
- const unsigned int* val = reinterpret_cast<const unsigned int*>(value);
- return base::NumberToString(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<int64_t>(const void* value) {
- const int64_t* val = reinterpret_cast<const int64_t*>(value);
- return base::NumberToString(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<uint64_t>(const void* value) {
- const uint64_t* val = reinterpret_cast<const uint64_t*>(value);
- return base::NumberToString(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<bool>(const void* value) {
- const bool* val = reinterpret_cast<const bool*>(value);
- return *val ? "true" : "false";
-}
-
-template <>
-string BoxedValue::ValuePrinter<double>(const void* value) {
- const double* val = reinterpret_cast<const double*>(value);
- return base::NumberToString(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<base::Time>(const void* value) {
- const base::Time* val = reinterpret_cast<const base::Time*>(value);
- return chromeos_update_engine::utils::ToString(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<base::TimeDelta>(const void* value) {
- const base::TimeDelta* val = reinterpret_cast<const base::TimeDelta*>(value);
- return chromeos_update_engine::utils::FormatTimeDelta(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<ConnectionType>(const void* value) {
- const ConnectionType* val = reinterpret_cast<const ConnectionType*>(value);
- return StringForConnectionType(*val);
-}
-
-template <>
-string BoxedValue::ValuePrinter<set<ConnectionType>>(const void* value) {
- string ret = "";
- const set<ConnectionType>* val =
- reinterpret_cast<const set<ConnectionType>*>(value);
- for (auto& it : *val) {
- ConnectionType type = it;
- if (ret.size() > 0)
- ret += ",";
- ret += StringForConnectionType(type);
- }
- return ret;
-}
-
-template <>
-string BoxedValue::ValuePrinter<ConnectionTethering>(const void* value) {
- const ConnectionTethering* val =
- reinterpret_cast<const ConnectionTethering*>(value);
- switch (*val) {
- case ConnectionTethering::kNotDetected:
- return "Not Detected";
- case ConnectionTethering::kSuspected:
- return "Suspected";
- case ConnectionTethering::kConfirmed:
- return "Confirmed";
- case ConnectionTethering::kUnknown:
- return "Unknown";
- }
- NOTREACHED();
- return "Unknown";
-}
-
-template <>
-string BoxedValue::ValuePrinter<RollbackToTargetVersion>(const void* value) {
- const RollbackToTargetVersion* val =
- reinterpret_cast<const RollbackToTargetVersion*>(value);
- switch (*val) {
- case RollbackToTargetVersion::kUnspecified:
- return "Unspecified";
- case RollbackToTargetVersion::kDisabled:
- return "Disabled";
- case RollbackToTargetVersion::kRollbackAndPowerwash:
- return "Rollback and powerwash";
- case RollbackToTargetVersion::kRollbackAndRestoreIfPossible:
- return "Rollback and restore if possible";
- case RollbackToTargetVersion::kMaxValue:
- NOTREACHED();
- return "Max value";
- }
- NOTREACHED();
- return "Unknown";
-}
-
-template <>
-string BoxedValue::ValuePrinter<Stage>(const void* value) {
- const Stage* val = reinterpret_cast<const Stage*>(value);
- switch (*val) {
- case Stage::kIdle:
- return "Idle";
- case Stage::kCheckingForUpdate:
- return "Checking For Update";
- case Stage::kUpdateAvailable:
- return "Update Available";
- case Stage::kDownloading:
- return "Downloading";
- case Stage::kVerifying:
- return "Verifying";
- case Stage::kFinalizing:
- return "Finalizing";
- case Stage::kUpdatedNeedReboot:
- return "Updated, Need Reboot";
- case Stage::kReportingErrorEvent:
- return "Reporting Error Event";
- case Stage::kAttemptingRollback:
- return "Attempting Rollback";
- case Stage::kCleanupPreviousUpdate:
- return "Cleanup Previous Update";
- }
- NOTREACHED();
- return "Unknown";
-}
-
-template <>
-string BoxedValue::ValuePrinter<UpdateRequestStatus>(const void* value) {
- const UpdateRequestStatus* val =
- reinterpret_cast<const UpdateRequestStatus*>(value);
- switch (*val) {
- case UpdateRequestStatus::kNone:
- return "None";
- case UpdateRequestStatus::kInteractive:
- return "Interactive";
- case UpdateRequestStatus::kPeriodic:
- return "Periodic";
- }
- NOTREACHED();
- return "Unknown";
-}
-
-template <>
-string BoxedValue::ValuePrinter<UpdateRestrictions>(const void* value) {
- const UpdateRestrictions* val =
- reinterpret_cast<const UpdateRestrictions*>(value);
-
- if (*val == UpdateRestrictions::kNone) {
- return "None";
- }
- string retval = "Flags:";
- if (*val & kRestrictDownloading) {
- retval += " RestrictDownloading";
- }
- return retval;
-}
-
-template <>
-string BoxedValue::ValuePrinter<WeeklyTimeInterval>(const void* value) {
- const WeeklyTimeInterval* val =
- reinterpret_cast<const WeeklyTimeInterval*>(value);
- return val->ToString();
-}
-
-template <>
-string BoxedValue::ValuePrinter<WeeklyTimeIntervalVector>(const void* value) {
- const WeeklyTimeIntervalVector* val =
- reinterpret_cast<const WeeklyTimeIntervalVector*>(value);
-
- string retval = "Disallowed intervals:\n";
- for (const auto& interval : *val) {
- retval += interval.ToString() + "\n";
- }
- 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/boxed_value.h b/update_manager/boxed_value.h
deleted file mode 100644
index 62b4b9d3..00000000
--- a/update_manager/boxed_value.h
+++ /dev/null
@@ -1,126 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_BOXED_VALUE_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_BOXED_VALUE_H_
-
-#include <memory>
-#include <string>
-
-#include <base/macros.h>
-
-namespace chromeos_update_manager {
-
-// BoxedValue is a class to hold pointers of a given type that deletes them when
-// the instance goes out of scope, as std::unique_ptr<T> does. The main
-// difference with it is that the type T is not part of the class, i.e., this
-// isn't a parametric class. The class has a parametric constructor that accepts
-// a const T* which will define the type of the object passed on delete.
-//
-// It is safe to use this class in linked containers such as std::list and
-// std::map but the object can't be copied. This means that you need to
-// construct the BoxedValue in place using a container method like emplace()
-// or move it with std::move().
-//
-// list<BoxedValue> lst;
-// lst.emplace_back(new const int(42));
-// lst.emplace_back(new const string("Hello world!"));
-//
-// map<int, BoxedValue> m;
-// m.emplace(123, std::move(BoxedValue(new const string("Hola mundo!"))));
-//
-// auto it = m.find(42);
-// if (it != m.end())
-// cout << "m[42] points to " << it->second.value() << endl;
-// cout << "m[33] points to " << m[33].value() << endl;
-//
-// Since copy and assign are not allowed, you can't create a copy of the
-// BoxedValue which means that you can only use a reference to it.
-//
-
-class BoxedValue {
- public:
- // Creates an empty BoxedValue. Since the pointer can't be assigned from other
- // BoxedValues or pointers, this is only useful in places where a default
- // constructor is required, such as std::map::operator[].
- BoxedValue() : value_(nullptr), deleter_(nullptr), printer_(nullptr) {}
-
- // Creates a BoxedValue for the passed pointer |value|. The BoxedValue keeps
- // the ownership of this pointer and can't be released.
- template <typename T>
- explicit BoxedValue(const T* value)
- : value_(static_cast<const void*>(value)),
- deleter_(ValueDeleter<T>),
- printer_(ValuePrinter<T>) {}
-
- // The move constructor takes ownership of the pointer since the semantics of
- // it allows to render the passed BoxedValue undefined. You need to use the
- // move constructor explicitly preventing it from accidental references,
- // like in:
- // BoxedValue new_box(std::move(other_box));
- BoxedValue(BoxedValue&& other) noexcept
- : value_(other.value_),
- deleter_(other.deleter_),
- printer_(other.printer_) {
- other.value_ = nullptr;
- other.deleter_ = nullptr;
- other.printer_ = nullptr;
- }
-
- // Deletes the |value| passed on construction using the delete for the passed
- // type.
- ~BoxedValue() {
- if (deleter_)
- deleter_(value_);
- }
-
- const void* value() const { return value_; }
-
- std::string ToString() const {
- if (!printer_)
- return "(no printer)";
- if (!value_)
- return "(no value)";
- return printer_(value_);
- }
-
- // Static method to call the destructor of the right type.
- template <typename T>
- static void ValueDeleter(const void* value) {
- delete reinterpret_cast<const T*>(value);
- }
-
- // Static method to print a type. See boxed_value.cc for common
- // instantiations.
- template <typename T>
- static std::string ValuePrinter(const void* value);
-
- private:
- // A pointer to the cached value.
- const void* value_;
-
- // A function that calls delete for the right type of value_.
- void (*deleter_)(const void*);
-
- // A function that converts value_ to a string.
- std::string (*printer_)(const void*);
-
- DISALLOW_COPY_AND_ASSIGN(BoxedValue);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_BOXED_VALUE_H_
diff --git a/update_manager/boxed_value_unittest.cc b/update_manager/boxed_value_unittest.cc
deleted file mode 100644
index 5b87a7b6..00000000
--- a/update_manager/boxed_value_unittest.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/boxed_value.h"
-
-#include <gtest/gtest.h>
-#include <list>
-#include <map>
-#include <set>
-#include <string>
-#include <utility>
-
-#include <base/strings/stringprintf.h>
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/rollback_prefs.h"
-#include "update_engine/update_manager/shill_provider.h"
-#include "update_engine/update_manager/umtest_utils.h"
-#include "update_engine/update_manager/updater_provider.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::ConnectionTethering;
-using chromeos_update_engine::ConnectionType;
-using std::list;
-using std::map;
-using std::set;
-using std::string;
-
-namespace chromeos_update_manager {
-
-// The DeleterMarker flags a bool variable when the class is destroyed.
-class DeleterMarker {
- public:
- explicit DeleterMarker(bool* marker) : marker_(marker) { *marker_ = false; }
-
- ~DeleterMarker() { *marker_ = true; }
-
- private:
- friend string BoxedValue::ValuePrinter<DeleterMarker>(const void*);
-
- // Pointer to the bool marker.
- bool* marker_;
-};
-
-template <>
-string BoxedValue::ValuePrinter<DeleterMarker>(const void* value) {
- const DeleterMarker* val = reinterpret_cast<const DeleterMarker*>(value);
- return base::StringPrintf("DeleterMarker:%s",
- *val->marker_ ? "true" : "false");
-}
-
-TEST(UmBoxedValueTest, Deleted) {
- bool marker = true;
- const DeleterMarker* deleter_marker = new DeleterMarker(&marker);
-
- EXPECT_FALSE(marker);
- BoxedValue* box = new BoxedValue(deleter_marker);
- EXPECT_FALSE(marker);
- delete box;
- EXPECT_TRUE(marker);
-}
-
-TEST(UmBoxedValueTest, MoveConstructor) {
- bool marker = true;
- const DeleterMarker* deleter_marker = new DeleterMarker(&marker);
-
- BoxedValue* box = new BoxedValue(deleter_marker);
- BoxedValue* new_box = new BoxedValue(std::move(*box));
- // box is now undefined but valid.
- delete box;
- EXPECT_FALSE(marker);
- // The deleter_marker gets deleted at this point.
- delete new_box;
- EXPECT_TRUE(marker);
-}
-
-TEST(UmBoxedValueTest, MixedList) {
- list<BoxedValue> lst;
- // This is mostly a compile test.
- lst.emplace_back(new const int{42});
- lst.emplace_back(new const string("Hello world!"));
- bool marker;
- lst.emplace_back(new const DeleterMarker(&marker));
- EXPECT_FALSE(marker);
- lst.clear();
- EXPECT_TRUE(marker);
-}
-
-TEST(UmBoxedValueTest, MixedMap) {
- map<int, BoxedValue> m;
- m.emplace(42, BoxedValue(new const string("Hola mundo!")));
-
- auto it = m.find(42);
- ASSERT_NE(it, m.end());
- EXPECT_NE(nullptr, it->second.value());
- EXPECT_EQ(nullptr, m[33].value());
-}
-
-TEST(UmBoxedValueTest, StringToString) {
- EXPECT_EQ("Hej Verden!", BoxedValue(new string("Hej Verden!")).ToString());
-}
-
-TEST(UmBoxedValueTest, IntToString) {
- EXPECT_EQ("42", BoxedValue(new int(42)).ToString());
-}
-
-TEST(UmBoxedValueTest, Int64ToString) {
- // -123456789012345 doesn't fit in 32-bit integers.
- EXPECT_EQ("-123456789012345",
- BoxedValue(new int64_t(-123456789012345LL)).ToString());
-}
-
-TEST(UmBoxedValueTest, UnsignedIntToString) {
- // 4294967295 is the biggest possible 32-bit unsigned integer.
- EXPECT_EQ("4294967295",
- BoxedValue(new unsigned int(4294967295U)).ToString()); // NOLINT
-}
-
-TEST(UmBoxedValueTest, UnsignedInt64ToString) {
- // 18446744073709551615 is the biggest possible 64-bit unsigned integer.
- EXPECT_EQ("18446744073709551615",
- BoxedValue(new uint64_t(18446744073709551615ULL)).ToString());
-}
-
-TEST(UmBoxedValueTest, BoolToString) {
- EXPECT_EQ("false", BoxedValue(new bool(false)).ToString());
- EXPECT_EQ("true", BoxedValue(new bool(true)).ToString());
-}
-
-TEST(UmBoxedValueTest, DoubleToString) {
- EXPECT_EQ("1.501", BoxedValue(new double(1.501)).ToString());
-}
-
-TEST(UmBoxedValueTest, TimeToString) {
- // Tue Apr 29 22:30:55 UTC 2014 is 1398810655 seconds since the Unix Epoch.
- EXPECT_EQ("4/29/2014 22:30:55 GMT",
- BoxedValue(new Time(Time::FromTimeT(1398810655))).ToString());
-}
-
-TEST(UmBoxedValueTest, TimeDeltaToString) {
- // 12345 seconds is 3 hours, 25 minutes and 45 seconds.
- EXPECT_EQ(
- "3h25m45s",
- BoxedValue(new TimeDelta(TimeDelta::FromSeconds(12345))).ToString());
-}
-
-TEST(UmBoxedValueTest, ConnectionTypeToString) {
- EXPECT_EQ(
- "Disconnected",
- BoxedValue(new ConnectionType(ConnectionType::kDisconnected)).ToString());
- EXPECT_EQ(
- "ethernet",
- BoxedValue(new ConnectionType(ConnectionType::kEthernet)).ToString());
- EXPECT_EQ("wifi",
- BoxedValue(new ConnectionType(ConnectionType::kWifi)).ToString());
- EXPECT_EQ(
- "cellular",
- BoxedValue(new ConnectionType(ConnectionType::kCellular)).ToString());
- EXPECT_EQ(
- "Unknown",
- BoxedValue(new ConnectionType(ConnectionType::kUnknown)).ToString());
-}
-
-TEST(UmBoxedValueTest, ConnectionTetheringToString) {
- EXPECT_EQ(
- "Not Detected",
- BoxedValue(new ConnectionTethering(ConnectionTethering::kNotDetected))
- .ToString());
- EXPECT_EQ("Suspected",
- BoxedValue(new ConnectionTethering(ConnectionTethering::kSuspected))
- .ToString());
- EXPECT_EQ("Confirmed",
- BoxedValue(new ConnectionTethering(ConnectionTethering::kConfirmed))
- .ToString());
- EXPECT_EQ("Unknown",
- BoxedValue(new ConnectionTethering(ConnectionTethering::kUnknown))
- .ToString());
-}
-
-TEST(UmBoxedValueTest, RollbackToTargetVersionToString) {
- EXPECT_EQ("Unspecified",
- BoxedValue(new RollbackToTargetVersion(
- RollbackToTargetVersion::kUnspecified))
- .ToString());
- EXPECT_EQ("Disabled",
- BoxedValue(
- new RollbackToTargetVersion(RollbackToTargetVersion::kDisabled))
- .ToString());
- EXPECT_EQ("Rollback and powerwash",
- BoxedValue(new RollbackToTargetVersion(
- RollbackToTargetVersion::kRollbackAndPowerwash))
- .ToString());
- EXPECT_EQ(
- "Rollback and restore if possible",
- BoxedValue(new RollbackToTargetVersion(
- RollbackToTargetVersion::kRollbackAndRestoreIfPossible))
- .ToString());
-}
-
-TEST(UmBoxedValueTest, SetConnectionTypeToString) {
- set<ConnectionType>* set1 = new set<ConnectionType>;
- set1->insert(ConnectionType::kCellular);
- set1->insert(ConnectionType::kEthernet);
- EXPECT_EQ("ethernet,cellular", BoxedValue(set1).ToString());
-
- set<ConnectionType>* set2 = new set<ConnectionType>;
- set2->insert(ConnectionType::kWifi);
- EXPECT_EQ("wifi", BoxedValue(set2).ToString());
-}
-
-TEST(UmBoxedValueTest, StageToString) {
- EXPECT_EQ("Idle", BoxedValue(new Stage(Stage::kIdle)).ToString());
- EXPECT_EQ("Checking For Update",
- BoxedValue(new Stage(Stage::kCheckingForUpdate)).ToString());
- EXPECT_EQ("Update Available",
- BoxedValue(new Stage(Stage::kUpdateAvailable)).ToString());
- EXPECT_EQ("Downloading",
- BoxedValue(new Stage(Stage::kDownloading)).ToString());
- EXPECT_EQ("Verifying", BoxedValue(new Stage(Stage::kVerifying)).ToString());
- EXPECT_EQ("Finalizing", BoxedValue(new Stage(Stage::kFinalizing)).ToString());
- EXPECT_EQ("Updated, Need Reboot",
- BoxedValue(new Stage(Stage::kUpdatedNeedReboot)).ToString());
- EXPECT_EQ("Reporting Error Event",
- BoxedValue(new Stage(Stage::kReportingErrorEvent)).ToString());
- EXPECT_EQ("Attempting Rollback",
- BoxedValue(new Stage(Stage::kAttemptingRollback)).ToString());
-}
-
-TEST(UmBoxedValueTest, DeleterMarkerToString) {
- bool marker = false;
- BoxedValue value = BoxedValue(new DeleterMarker(&marker));
- EXPECT_EQ("DeleterMarker:false", value.ToString());
- marker = true;
- EXPECT_EQ("DeleterMarker:true", value.ToString());
-}
-
-TEST(UmBoxedValueTest, UpdateRestrictionsToString) {
- EXPECT_EQ(
- "None",
- BoxedValue(new UpdateRestrictions(UpdateRestrictions::kNone)).ToString());
- EXPECT_EQ("Flags: RestrictDownloading",
- BoxedValue(new UpdateRestrictions(
- UpdateRestrictions::kRestrictDownloading))
- .ToString());
-}
-
-TEST(UmBoxedValueTest, WeeklyTimeIntervalToString) {
- EXPECT_EQ("Start: day_of_week=2 time=100\nEnd: day_of_week=4 time=200",
- BoxedValue(new WeeklyTimeInterval(
- WeeklyTime(2, TimeDelta::FromMinutes(100)),
- WeeklyTime(4, TimeDelta::FromMinutes(200))))
- .ToString());
- EXPECT_EQ("Start: day_of_week=1 time=10\nEnd: day_of_week=1 time=20",
- BoxedValue(new WeeklyTimeInterval(
- WeeklyTime(1, TimeDelta::FromMinutes(10)),
- WeeklyTime(1, TimeDelta::FromMinutes(20))))
- .ToString());
-}
-
-TEST(UmBoxedValueTest, WeeklyTimeIntervalVectorToString) {
- WeeklyTimeIntervalVector intervals;
- intervals.emplace_back(WeeklyTime(5, TimeDelta::FromMinutes(10)),
- WeeklyTime(1, TimeDelta::FromMinutes(30)));
- EXPECT_EQ(
- "Disallowed intervals:\nStart: day_of_week=5 time=10\nEnd: "
- "day_of_week=1 time=30\n",
- BoxedValue(new WeeklyTimeIntervalVector(intervals)).ToString());
- intervals.emplace_back(WeeklyTime(1, TimeDelta::FromMinutes(5)),
- WeeklyTime(6, TimeDelta::FromMinutes(1000)));
- EXPECT_EQ(
- "Disallowed intervals:\nStart: day_of_week=5 time=10\nEnd: "
- "day_of_week=1 time=30\nStart: day_of_week=1 time=5\nEnd: day_of_week=6 "
- "time=1000\n",
- BoxedValue(new WeeklyTimeIntervalVector(intervals)).ToString());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/chromeos_policy.cc b/update_manager/chromeos_policy.cc
deleted file mode 100644
index 24b8293e..00000000
--- a/update_manager/chromeos_policy.cc
+++ /dev/null
@@ -1,794 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/chromeos_policy.h"
-
-#include <algorithm>
-#include <memory>
-#include <set>
-#include <string>
-#include <vector>
-
-#include <base/logging.h>
-#include <base/strings/string_util.h>
-#include <base/time/time.h>
-
-#include "update_engine/common/error_code.h"
-#include "update_engine/common/error_code_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/update_manager/device_policy_provider.h"
-#include "update_engine/update_manager/enough_slots_ab_updates_policy_impl.h"
-#include "update_engine/update_manager/enterprise_device_policy_impl.h"
-#include "update_engine/update_manager/interactive_update_policy_impl.h"
-#include "update_engine/update_manager/official_build_check_policy_impl.h"
-#include "update_engine/update_manager/out_of_box_experience_policy_impl.h"
-#include "update_engine/update_manager/policy_utils.h"
-#include "update_engine/update_manager/shill_provider.h"
-#include "update_engine/update_manager/update_time_restrictions_policy_impl.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::ConnectionTethering;
-using chromeos_update_engine::ConnectionType;
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-using std::get;
-using std::min;
-using std::set;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-
-namespace {
-
-// Examines |err_code| and decides whether the URL index needs to be advanced,
-// the error count for the URL incremented, or none of the above. In the first
-// case, returns true; in the second case, increments |*url_num_error_p| and
-// returns false; otherwise just returns false.
-//
-// TODO(garnold) Adapted from PayloadState::UpdateFailed() (to be retired).
-bool HandleErrorCode(ErrorCode err_code, int* url_num_error_p) {
- err_code = chromeos_update_engine::utils::GetBaseErrorCode(err_code);
- switch (err_code) {
- // Errors which are good indicators of a problem with a particular URL or
- // the protocol used in the URL or entities in the communication channel
- // (e.g. proxies). We should try the next available URL in the next update
- // check to quickly recover from these errors.
- case ErrorCode::kPayloadHashMismatchError:
- case ErrorCode::kPayloadSizeMismatchError:
- case ErrorCode::kDownloadPayloadVerificationError:
- case ErrorCode::kDownloadPayloadPubKeyVerificationError:
- case ErrorCode::kSignedDeltaPayloadExpectedError:
- case ErrorCode::kDownloadInvalidMetadataMagicString:
- case ErrorCode::kDownloadSignatureMissingInManifest:
- case ErrorCode::kDownloadManifestParseError:
- case ErrorCode::kDownloadMetadataSignatureError:
- case ErrorCode::kDownloadMetadataSignatureVerificationError:
- case ErrorCode::kDownloadMetadataSignatureMismatch:
- case ErrorCode::kDownloadOperationHashVerificationError:
- case ErrorCode::kDownloadOperationExecutionError:
- case ErrorCode::kDownloadOperationHashMismatch:
- case ErrorCode::kDownloadInvalidMetadataSize:
- case ErrorCode::kDownloadInvalidMetadataSignature:
- case ErrorCode::kDownloadOperationHashMissingError:
- case ErrorCode::kDownloadMetadataSignatureMissingError:
- case ErrorCode::kPayloadMismatchedType:
- case ErrorCode::kUnsupportedMajorPayloadVersion:
- case ErrorCode::kUnsupportedMinorPayloadVersion:
- case ErrorCode::kPayloadTimestampError:
- case ErrorCode::kVerityCalculationError:
- LOG(INFO) << "Advancing download URL due to error "
- << chromeos_update_engine::utils::ErrorCodeToString(err_code)
- << " (" << static_cast<int>(err_code) << ")";
- return true;
-
- // Errors which seem to be just transient network/communication related
- // failures and do not indicate any inherent problem with the URL itself.
- // So, we should keep the current URL but just increment the
- // failure count to give it more chances. This way, while we maximize our
- // chances of downloading from the URLs that appear earlier in the response
- // (because download from a local server URL that appears earlier in a
- // response is preferable than downloading from the next URL which could be
- // an Internet URL and thus could be more expensive).
- case ErrorCode::kError:
- case ErrorCode::kDownloadTransferError:
- case ErrorCode::kDownloadWriteError:
- case ErrorCode::kDownloadStateInitializationError:
- case ErrorCode::kOmahaErrorInHTTPResponse: // Aggregate for HTTP errors.
- LOG(INFO) << "Incrementing URL failure count due to error "
- << chromeos_update_engine::utils::ErrorCodeToString(err_code)
- << " (" << static_cast<int>(err_code) << ")";
- *url_num_error_p += 1;
- return false;
-
- // Errors which are not specific to a URL and hence shouldn't result in
- // the URL being penalized. This can happen in two cases:
- // 1. We haven't started downloading anything: These errors don't cost us
- // anything in terms of actual payload bytes, so we should just do the
- // regular retries at the next update check.
- // 2. We have successfully downloaded the payload: In this case, the
- // payload attempt number would have been incremented and would take care
- // of the back-off at the next update check.
- // In either case, there's no need to update URL index or failure count.
- case ErrorCode::kOmahaRequestError:
- case ErrorCode::kOmahaResponseHandlerError:
- case ErrorCode::kPostinstallRunnerError:
- case ErrorCode::kFilesystemCopierError:
- case ErrorCode::kInstallDeviceOpenError:
- case ErrorCode::kKernelDeviceOpenError:
- case ErrorCode::kDownloadNewPartitionInfoError:
- case ErrorCode::kNewRootfsVerificationError:
- case ErrorCode::kNewKernelVerificationError:
- case ErrorCode::kPostinstallBootedFromFirmwareB:
- case ErrorCode::kPostinstallFirmwareRONotUpdatable:
- case ErrorCode::kOmahaRequestEmptyResponseError:
- case ErrorCode::kOmahaRequestXMLParseError:
- case ErrorCode::kOmahaResponseInvalid:
- case ErrorCode::kOmahaUpdateIgnoredPerPolicy:
- case ErrorCode::kOmahaUpdateDeferredPerPolicy:
- case ErrorCode::kNonCriticalUpdateInOOBE:
- case ErrorCode::kOmahaUpdateDeferredForBackoff:
- case ErrorCode::kPostinstallPowerwashError:
- case ErrorCode::kUpdateCanceledByChannelChange:
- case ErrorCode::kOmahaRequestXMLHasEntityDecl:
- case ErrorCode::kFilesystemVerifierError:
- case ErrorCode::kUserCanceled:
- case ErrorCode::kOmahaUpdateIgnoredOverCellular:
- case ErrorCode::kUpdatedButNotActive:
- case ErrorCode::kNoUpdate:
- case ErrorCode::kRollbackNotPossible:
- case ErrorCode::kFirstActiveOmahaPingSentPersistenceError:
- case ErrorCode::kInternalLibCurlError:
- case ErrorCode::kUnresolvedHostError:
- 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) << ")";
- return false;
-
- case ErrorCode::kSuccess: // success code
- case ErrorCode::kUmaReportedMax: // not an error code
- case ErrorCode::kOmahaRequestHTTPResponseBase: // aggregated already
- case ErrorCode::kDevModeFlag: // not an error code
- case ErrorCode::kResumedFlag: // not an error code
- case ErrorCode::kTestImageFlag: // not an error code
- case ErrorCode::kTestOmahaUrlFlag: // not an error code
- case ErrorCode::kSpecialFlags: // not an error code
- // These shouldn't happen. Enumerating these explicitly here so that we
- // can let the compiler warn about new error codes that are added to
- // action_processor.h but not added here.
- LOG(WARNING) << "Unexpected error "
- << chromeos_update_engine::utils::ErrorCodeToString(err_code)
- << " (" << static_cast<int>(err_code) << ")";
- // Note: Not adding a default here so as to let the compiler warn us of
- // any new enums that were added in the .h but not listed in this switch.
- }
- return false;
-}
-
-// Checks whether |url| can be used under given download restrictions.
-bool IsUrlUsable(const string& url, bool http_allowed) {
- return http_allowed ||
- !base::StartsWith(
- url, "http://", base::CompareCase::INSENSITIVE_ASCII);
-}
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-unique_ptr<Policy> GetSystemPolicy() {
- return std::make_unique<ChromeOSPolicy>();
-}
-
-const NextUpdateCheckPolicyConstants
- ChromeOSPolicy::kNextUpdateCheckPolicyConstants = {
- .timeout_initial_interval = 7 * 60,
- .timeout_periodic_interval = 45 * 60,
- .timeout_max_backoff_interval = 4 * 60 * 60,
- .timeout_regular_fuzz = 10 * 60,
- .attempt_backoff_max_interval_in_days = 16,
- .attempt_backoff_fuzz_in_hours = 12,
-};
-
-const int ChromeOSPolicy::kMaxP2PAttempts = 10;
-const int ChromeOSPolicy::kMaxP2PAttemptsPeriodInSeconds = 5 * 24 * 60 * 60;
-
-EvalStatus ChromeOSPolicy::UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- string* error,
- UpdateCheckParams* result) const {
- // 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;
- result->rollback_on_channel_downgrade = false;
- result->interactive = false;
- result->quick_fix_build_token.clear();
-
- EnoughSlotsAbUpdatesPolicyImpl enough_slots_ab_updates_policy;
- EnterpriseDevicePolicyImpl enterprise_device_policy;
- OnlyUpdateOfficialBuildsPolicyImpl only_update_official_builds_policy;
- InteractiveUpdatePolicyImpl interactive_update_policy;
- OobePolicyImpl oobe_policy;
- NextUpdateCheckTimePolicyImpl next_update_check_time_policy(
- kNextUpdateCheckPolicyConstants);
-
- vector<Policy const*> policies_to_consult = {
- // Do not perform any updates if there are not enough slots to do A/B
- // updates.
- &enough_slots_ab_updates_policy,
-
- // Check to see if Enterprise-managed (has DevicePolicy) and/or
- // Kiosk-mode. If so, then defer to those settings.
- &enterprise_device_policy,
-
- // Check to see if an interactive update was requested.
- &interactive_update_policy,
-
- // Unofficial builds should not perform periodic update checks.
- &only_update_official_builds_policy,
-
- // If OOBE is enabled, wait until it is completed.
- &oobe_policy,
-
- // Ensure that periodic update checks are timed properly.
- &next_update_check_time_policy,
- };
-
- // Now that the list of policy implementations, and the order to consult them,
- // has been setup, consult the policies. If none of the policies make a
- // definitive decisions about whether or not to check for updates, then allow
- // the update check to happen.
- EvalStatus status = ConsultPolicies(policies_to_consult,
- &Policy::UpdateCheckAllowed,
- ec,
- state,
- error,
- result);
- if (EvalStatus::kContinue != status) {
- return status;
- } else {
- // It is time to check for an update.
- LOG(INFO) << "Allowing update check.";
- return EvalStatus::kSucceeded;
- }
-}
-
-EvalStatus ChromeOSPolicy::UpdateCanBeApplied(EvaluationContext* ec,
- State* state,
- std::string* error,
- ErrorCode* result,
- InstallPlan* install_plan) const {
- UpdateTimeRestrictionsPolicyImpl update_time_restrictions_policy;
- InteractiveUpdatePolicyImpl interactive_update_policy;
-
- vector<Policy const*> policies_to_consult = {
- // Check to see if an interactive update has been requested.
- &interactive_update_policy,
-
- // Do not apply or download an update if we are inside one of the
- // restricted times.
- &update_time_restrictions_policy,
- };
-
- EvalStatus status = ConsultPolicies(policies_to_consult,
- &Policy::UpdateCanBeApplied,
- ec,
- state,
- error,
- result,
- install_plan);
- if (EvalStatus::kContinue != status) {
- return status;
- } else {
- // The update can proceed.
- LOG(INFO) << "Allowing update to be applied.";
- *result = ErrorCode::kSuccess;
- return EvalStatus::kSucceeded;
- }
-}
-
-EvalStatus ChromeOSPolicy::UpdateCanStart(
- EvaluationContext* ec,
- State* state,
- string* error,
- UpdateDownloadParams* result,
- const UpdateState update_state) const {
- // Set the default return values. Note that we set persisted values (backoff,
- // scattering) to the same values presented in the update state. The reason is
- // that preemptive returns, such as the case where an update check is due,
- // should not clear off the said values; rather, it is the deliberate
- // inference of new values that should cause them to be reset.
- result->update_can_start = false;
- result->cannot_start_reason = UpdateCannotStartReason::kUndefined;
- result->download_url_idx = -1;
- result->download_url_allowed = true;
- result->download_url_num_errors = 0;
- result->p2p_downloading_allowed = false;
- result->p2p_sharing_allowed = false;
- result->do_increment_failures = false;
- result->backoff_expiry = update_state.backoff_expiry;
- result->scatter_wait_period = update_state.scatter_wait_period;
- result->scatter_check_threshold = update_state.scatter_check_threshold;
-
- // Make sure that we're not due for an update check.
- UpdateCheckParams check_result;
- EvalStatus check_status = UpdateCheckAllowed(ec, state, error, &check_result);
- if (check_status == EvalStatus::kFailed)
- return EvalStatus::kFailed;
- bool is_check_due = (check_status == EvalStatus::kSucceeded &&
- check_result.updates_enabled == true);
-
- // Check whether backoff applies, and if not then which URL can be used for
- // downloading. These require scanning the download error log, and so they are
- // done together.
- UpdateBackoffAndDownloadUrlResult backoff_url_result;
- EvalStatus backoff_url_status = UpdateBackoffAndDownloadUrl(
- ec, state, error, &backoff_url_result, update_state);
- if (backoff_url_status == EvalStatus::kFailed)
- return EvalStatus::kFailed;
- result->download_url_idx = backoff_url_result.url_idx;
- result->download_url_num_errors = backoff_url_result.url_num_errors;
- result->do_increment_failures = backoff_url_result.do_increment_failures;
- result->backoff_expiry = backoff_url_result.backoff_expiry;
- bool is_backoff_active =
- (backoff_url_status == EvalStatus::kAskMeAgainLater) ||
- !backoff_url_result.backoff_expiry.is_null();
-
- DevicePolicyProvider* const dp_provider = state->device_policy_provider();
- bool is_scattering_active = false;
- EvalStatus scattering_status = EvalStatus::kSucceeded;
-
- const bool* device_policy_is_loaded_p =
- ec->GetValue(dp_provider->var_device_policy_is_loaded());
- if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
- // Check whether scattering applies to this update attempt. We should not be
- // scattering if this is an interactive update check, or if OOBE is enabled
- // but not completed.
- //
- // Note: current code further suppresses scattering if a "deadline"
- // attribute is found in the Omaha response. However, it appears that the
- // presence of this attribute is merely indicative of an OOBE update, during
- // which we suppress scattering anyway.
- bool is_scattering_applicable = false;
- result->scatter_wait_period = kZeroInterval;
- result->scatter_check_threshold = 0;
- if (!update_state.interactive) {
- const bool* is_oobe_enabled_p =
- ec->GetValue(state->config_provider()->var_is_oobe_enabled());
- if (is_oobe_enabled_p && !(*is_oobe_enabled_p)) {
- is_scattering_applicable = true;
- } else {
- const bool* is_oobe_complete_p =
- ec->GetValue(state->system_provider()->var_is_oobe_complete());
- is_scattering_applicable = (is_oobe_complete_p && *is_oobe_complete_p);
- }
- }
-
- // Compute scattering values.
- if (is_scattering_applicable) {
- UpdateScatteringResult scatter_result;
- scattering_status =
- UpdateScattering(ec, state, error, &scatter_result, update_state);
- if (scattering_status == EvalStatus::kFailed) {
- return EvalStatus::kFailed;
- } else {
- result->scatter_wait_period = scatter_result.wait_period;
- result->scatter_check_threshold = scatter_result.check_threshold;
- if (scattering_status == EvalStatus::kAskMeAgainLater ||
- scatter_result.is_scattering)
- is_scattering_active = true;
- }
- }
- }
-
- // Find out whether P2P is globally enabled.
- bool p2p_enabled;
- EvalStatus p2p_enabled_status = P2PEnabled(ec, state, error, &p2p_enabled);
- if (p2p_enabled_status != EvalStatus::kSucceeded)
- return EvalStatus::kFailed;
-
- // Is P2P is enabled, consider allowing it for downloading and/or sharing.
- if (p2p_enabled) {
- // Sharing via P2P is allowed if not disabled by Omaha.
- if (update_state.p2p_sharing_disabled) {
- LOG(INFO) << "Blocked P2P sharing because it is disabled by Omaha.";
- } else {
- result->p2p_sharing_allowed = true;
- }
-
- // Downloading via P2P is allowed if not disabled by Omaha, an update is not
- // interactive, and other limits haven't been reached.
- if (update_state.p2p_downloading_disabled) {
- LOG(INFO) << "Blocked P2P downloading because it is disabled by Omaha.";
- } else if (update_state.interactive) {
- LOG(INFO) << "Blocked P2P downloading because update is interactive.";
- } else if (update_state.p2p_num_attempts >= kMaxP2PAttempts) {
- LOG(INFO) << "Blocked P2P downloading as it was attempted too many "
- "times.";
- } else if (!update_state.p2p_first_attempted.is_null() &&
- ec->IsWallclockTimeGreaterThan(
- update_state.p2p_first_attempted +
- TimeDelta::FromSeconds(kMaxP2PAttemptsPeriodInSeconds))) {
- LOG(INFO) << "Blocked P2P downloading as its usage timespan exceeds "
- "limit.";
- } else {
- // P2P download is allowed; if backoff or scattering are active, be sure
- // to suppress them, yet prevent any download URL from being used.
- result->p2p_downloading_allowed = true;
- if (is_backoff_active || is_scattering_active) {
- is_backoff_active = is_scattering_active = false;
- result->download_url_allowed = false;
- }
- }
- }
-
- // Check for various deterrents.
- if (is_check_due) {
- result->cannot_start_reason = UpdateCannotStartReason::kCheckDue;
- return EvalStatus::kSucceeded;
- }
- if (is_backoff_active) {
- result->cannot_start_reason = UpdateCannotStartReason::kBackoff;
- return backoff_url_status;
- }
- if (is_scattering_active) {
- result->cannot_start_reason = UpdateCannotStartReason::kScattering;
- return scattering_status;
- }
- if (result->download_url_idx < 0 && !result->p2p_downloading_allowed) {
- result->cannot_start_reason = UpdateCannotStartReason::kCannotDownload;
- return EvalStatus::kSucceeded;
- }
-
- // Update is good to go.
- result->update_can_start = true;
- return EvalStatus::kSucceeded;
-}
-
-EvalStatus ChromeOSPolicy::P2PEnabled(EvaluationContext* ec,
- State* state,
- string* error,
- bool* result) const {
- bool enabled = false;
-
- // Determine whether use of P2P is allowed by policy. Even if P2P is not
- // explicitly allowed, we allow it if the device is enterprise enrolled (that
- // is, missing or empty owner string).
- DevicePolicyProvider* const dp_provider = state->device_policy_provider();
- const bool* device_policy_is_loaded_p =
- ec->GetValue(dp_provider->var_device_policy_is_loaded());
- if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
- const bool* policy_au_p2p_enabled_p =
- ec->GetValue(dp_provider->var_au_p2p_enabled());
- if (policy_au_p2p_enabled_p) {
- enabled = *policy_au_p2p_enabled_p;
- } else {
- const bool* policy_has_owner_p =
- ec->GetValue(dp_provider->var_has_owner());
- if (!policy_has_owner_p || !*policy_has_owner_p)
- enabled = true;
- }
- }
-
- // Enable P2P, if so mandated by the updater configuration. This is additive
- // to whether or not P2P is enabled by device policy.
- if (!enabled) {
- const bool* updater_p2p_enabled_p =
- ec->GetValue(state->updater_provider()->var_p2p_enabled());
- enabled = updater_p2p_enabled_p && *updater_p2p_enabled_p;
- }
-
- *result = enabled;
- return EvalStatus::kSucceeded;
-}
-
-EvalStatus ChromeOSPolicy::P2PEnabledChanged(EvaluationContext* ec,
- State* state,
- string* error,
- bool* result,
- bool prev_result) const {
- EvalStatus status = P2PEnabled(ec, state, error, result);
- if (status == EvalStatus::kSucceeded && *result == prev_result)
- return EvalStatus::kAskMeAgainLater;
- return status;
-}
-
-EvalStatus ChromeOSPolicy::UpdateBackoffAndDownloadUrl(
- EvaluationContext* ec,
- State* state,
- string* error,
- UpdateBackoffAndDownloadUrlResult* result,
- const UpdateState& update_state) const {
- DCHECK_GE(update_state.download_errors_max, 0);
-
- // Set default result values.
- result->do_increment_failures = false;
- result->backoff_expiry = update_state.backoff_expiry;
- result->url_idx = -1;
- result->url_num_errors = 0;
-
- const bool* is_official_build_p =
- ec->GetValue(state->system_provider()->var_is_official_build());
- bool is_official_build = (is_official_build_p ? *is_official_build_p : true);
-
- // Check whether backoff is enabled.
- bool may_backoff = false;
- if (update_state.is_backoff_disabled) {
- LOG(INFO) << "Backoff disabled by Omaha.";
- } else if (update_state.interactive) {
- LOG(INFO) << "No backoff for interactive updates.";
- } else if (update_state.is_delta_payload) {
- LOG(INFO) << "No backoff for delta payloads.";
- } else if (!is_official_build) {
- LOG(INFO) << "No backoff for unofficial builds.";
- } else {
- may_backoff = true;
- }
-
- // If previous backoff still in effect, block.
- if (may_backoff && !update_state.backoff_expiry.is_null() &&
- !ec->IsWallclockTimeGreaterThan(update_state.backoff_expiry)) {
- LOG(INFO) << "Previous backoff has not expired, waiting.";
- return EvalStatus::kAskMeAgainLater;
- }
-
- // Determine whether HTTP downloads are forbidden by policy. This only
- // applies to official system builds; otherwise, HTTP is always enabled.
- bool http_allowed = true;
- if (is_official_build) {
- DevicePolicyProvider* const dp_provider = state->device_policy_provider();
- const bool* device_policy_is_loaded_p =
- ec->GetValue(dp_provider->var_device_policy_is_loaded());
- if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
- const bool* policy_http_downloads_enabled_p =
- ec->GetValue(dp_provider->var_http_downloads_enabled());
- http_allowed = (!policy_http_downloads_enabled_p ||
- *policy_http_downloads_enabled_p);
- }
- }
-
- int url_idx = update_state.last_download_url_idx;
- if (url_idx < 0)
- url_idx = -1;
- bool do_advance_url = false;
- bool is_failure_occurred = false;
- Time err_time;
-
- // Scan the relevant part of the download error log, tracking which URLs are
- // being used, and accounting the number of errors for each URL. Note that
- // this process may not traverse all errors provided, as it may decide to bail
- // out midway depending on the particular errors exhibited, the number of
- // failures allowed, etc. When this ends, |url_idx| will point to the last URL
- // used (-1 if starting fresh), |do_advance_url| will determine whether the
- // URL needs to be advanced, and |err_time| the point in time when the last
- // reported error occurred. Additionally, if the error log indicates that an
- // update attempt has failed (abnormal), then |is_failure_occurred| will be
- // set to true.
- const int num_urls = update_state.download_urls.size();
- int prev_url_idx = -1;
- int url_num_errors = update_state.last_download_url_num_errors;
- Time prev_err_time;
- bool is_first = true;
- for (const auto& err_tuple : update_state.download_errors) {
- // Do some validation checks.
- int used_url_idx = get<0>(err_tuple);
- if (is_first && url_idx >= 0 && used_url_idx != url_idx) {
- LOG(WARNING) << "First URL in error log (" << used_url_idx
- << ") not as expected (" << url_idx << ")";
- }
- is_first = false;
- url_idx = used_url_idx;
- if (url_idx < 0 || url_idx >= num_urls) {
- LOG(ERROR) << "Download error log contains an invalid URL index ("
- << url_idx << ")";
- return EvalStatus::kFailed;
- }
- err_time = get<2>(err_tuple);
- if (!(prev_err_time.is_null() || err_time >= prev_err_time)) {
- // TODO(garnold) Monotonicity cannot really be assumed when dealing with
- // wallclock-based timestamps. However, we're making a simplifying
- // assumption so as to keep the policy implementation straightforward, for
- // now. In general, we should convert all timestamp handling in the
- // UpdateManager to use monotonic time (instead of wallclock), including
- // the computation of various expiration times (backoff, scattering, etc).
- // The client will do whatever conversions necessary when
- // persisting/retrieving these values across reboots. See chromium:408794.
- LOG(ERROR) << "Download error timestamps not monotonically increasing.";
- return EvalStatus::kFailed;
- }
- prev_err_time = err_time;
-
- // Ignore errors that happened before the last known failed attempt.
- if (!update_state.failures_last_updated.is_null() &&
- err_time <= update_state.failures_last_updated)
- continue;
-
- if (prev_url_idx >= 0) {
- if (url_idx < prev_url_idx) {
- LOG(ERROR) << "The URLs in the download error log have wrapped around ("
- << prev_url_idx << "->" << url_idx
- << "). This should not have happened and means that there's "
- "a bug. To be conservative, we record a failed attempt "
- "(invalidating the rest of the error log) and resume "
- "download from the first usable URL.";
- url_idx = -1;
- is_failure_occurred = true;
- break;
- }
-
- if (url_idx > prev_url_idx) {
- url_num_errors = 0;
- do_advance_url = false;
- }
- }
-
- if (HandleErrorCode(get<1>(err_tuple), &url_num_errors) ||
- url_num_errors > update_state.download_errors_max)
- do_advance_url = true;
-
- prev_url_idx = url_idx;
- }
-
- // If required, advance to the next usable URL. If the URLs wraparound, we
- // mark an update attempt failure. Also be sure to set the download error
- // count to zero.
- if (url_idx < 0 || do_advance_url) {
- url_num_errors = 0;
- int start_url_idx = -1;
- do {
- if (++url_idx == num_urls) {
- url_idx = 0;
- // We only mark failure if an actual advancing of a URL was required.
- if (do_advance_url)
- is_failure_occurred = true;
- }
-
- if (start_url_idx < 0)
- start_url_idx = url_idx;
- else if (url_idx == start_url_idx)
- url_idx = -1; // No usable URL.
- } while (url_idx >= 0 &&
- !IsUrlUsable(update_state.download_urls[url_idx], http_allowed));
- }
-
- // If we have a download URL but a failure was observed, compute a new backoff
- // expiry (if allowed). The backoff period is generally 2 ^ (num_failures - 1)
- // days, bounded by the size of int and kAttemptBackoffMaxIntervalInDays, and
- // fuzzed by kAttemptBackoffFuzzInHours hours. Backoff expiry is computed from
- // the latest recorded time of error.
- Time backoff_expiry;
- if (url_idx >= 0 && is_failure_occurred && may_backoff) {
- CHECK(!err_time.is_null())
- << "We must have an error timestamp if a failure occurred!";
- const uint64_t* seed = ec->GetValue(state->random_provider()->var_seed());
- POLICY_CHECK_VALUE_AND_FAIL(seed, error);
- PRNG prng(*seed);
- int exp =
- min(update_state.num_failures, static_cast<int>(sizeof(int)) * 8 - 2);
- TimeDelta backoff_interval = TimeDelta::FromDays(min(
- 1 << exp,
- kNextUpdateCheckPolicyConstants.attempt_backoff_max_interval_in_days));
- TimeDelta backoff_fuzz = TimeDelta::FromHours(
- kNextUpdateCheckPolicyConstants.attempt_backoff_fuzz_in_hours);
- TimeDelta wait_period = NextUpdateCheckTimePolicyImpl::FuzzedInterval(
- &prng, backoff_interval.InSeconds(), backoff_fuzz.InSeconds());
- backoff_expiry = err_time + wait_period;
-
- // If the newly computed backoff already expired, nullify it.
- if (ec->IsWallclockTimeGreaterThan(backoff_expiry))
- backoff_expiry = Time();
- }
-
- result->do_increment_failures = is_failure_occurred;
- result->backoff_expiry = backoff_expiry;
- result->url_idx = url_idx;
- result->url_num_errors = url_num_errors;
- return EvalStatus::kSucceeded;
-}
-
-EvalStatus ChromeOSPolicy::UpdateScattering(
- EvaluationContext* ec,
- State* state,
- string* error,
- UpdateScatteringResult* result,
- const UpdateState& update_state) const {
- // Preconditions. These stem from the postconditions and usage contract.
- DCHECK(update_state.scatter_wait_period >= kZeroInterval);
- DCHECK_GE(update_state.scatter_check_threshold, 0);
-
- // Set default result values.
- result->is_scattering = false;
- result->wait_period = kZeroInterval;
- result->check_threshold = 0;
-
- DevicePolicyProvider* const dp_provider = state->device_policy_provider();
-
- // Ensure that a device policy is loaded.
- const bool* device_policy_is_loaded_p =
- ec->GetValue(dp_provider->var_device_policy_is_loaded());
- if (!(device_policy_is_loaded_p && *device_policy_is_loaded_p))
- return EvalStatus::kSucceeded;
-
- // Is scattering enabled by policy?
- const TimeDelta* scatter_factor_p =
- ec->GetValue(dp_provider->var_scatter_factor());
- if (!scatter_factor_p || *scatter_factor_p == kZeroInterval)
- return EvalStatus::kSucceeded;
-
- // Obtain a pseudo-random number generator.
- const uint64_t* seed = ec->GetValue(state->random_provider()->var_seed());
- POLICY_CHECK_VALUE_AND_FAIL(seed, error);
- PRNG prng(*seed);
-
- // Step 1: Maintain the scattering wait period.
- //
- // If no wait period was previously determined, or it no longer fits in the
- // scatter factor, then generate a new one. Otherwise, keep the one we have.
- TimeDelta wait_period = update_state.scatter_wait_period;
- if (wait_period == kZeroInterval || wait_period > *scatter_factor_p) {
- wait_period = TimeDelta::FromSeconds(
- prng.RandMinMax(1, scatter_factor_p->InSeconds()));
- }
-
- // If we surpassed the wait period or the max scatter period associated with
- // the update, then no wait is needed.
- Time wait_expires = (update_state.first_seen +
- min(wait_period, update_state.scatter_wait_period_max));
- if (ec->IsWallclockTimeGreaterThan(wait_expires))
- wait_period = kZeroInterval;
-
- // Step 2: Maintain the update check threshold count.
- //
- // If an update check threshold is not specified then generate a new
- // one.
- int check_threshold = update_state.scatter_check_threshold;
- if (check_threshold == 0) {
- check_threshold = prng.RandMinMax(update_state.scatter_check_threshold_min,
- update_state.scatter_check_threshold_max);
- }
-
- // If the update check threshold is not within allowed range then nullify it.
- // TODO(garnold) This is compliant with current logic found in
- // OmahaRequestAction::IsUpdateCheckCountBasedWaitingSatisfied(). We may want
- // to change it so that it behaves similarly to the wait period case, namely
- // if the current value exceeds the maximum, we set a new one within range.
- if (check_threshold > update_state.scatter_check_threshold_max)
- check_threshold = 0;
-
- // If the update check threshold is non-zero and satisfied, then nullify it.
- if (check_threshold > 0 && update_state.num_checks >= check_threshold)
- check_threshold = 0;
-
- bool is_scattering = (wait_period != kZeroInterval || check_threshold);
- EvalStatus ret = EvalStatus::kSucceeded;
- if (is_scattering && wait_period == update_state.scatter_wait_period &&
- check_threshold == update_state.scatter_check_threshold)
- ret = EvalStatus::kAskMeAgainLater;
- result->is_scattering = is_scattering;
- result->wait_period = wait_period;
- result->check_threshold = check_threshold;
- return ret;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/chromeos_policy.h b/update_manager/chromeos_policy.h
deleted file mode 100644
index 3c196dac..00000000
--- a/update_manager/chromeos_policy.h
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_CHROMEOS_POLICY_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_CHROMEOS_POLICY_H_
-
-#include <string>
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/next_update_check_policy_impl.h"
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Output information from UpdateBackoffAndDownloadUrl.
-struct UpdateBackoffAndDownloadUrlResult {
- // Whether the failed attempt count (maintained by the caller) needs to be
- // incremented.
- bool do_increment_failures;
- // The current backoff expiry. Null if backoff is not in effect.
- base::Time backoff_expiry;
- // The new URL index to use and number of download errors associated with it.
- // Significant iff |do_increment_failures| is false and |backoff_expiry| is
- // null. Negative value means no usable URL was found.
- int url_idx;
- int url_num_errors;
-};
-
-// Parameters for update scattering, as returned by UpdateScattering.
-struct UpdateScatteringResult {
- bool is_scattering;
- base::TimeDelta wait_period;
- int check_threshold;
-};
-
-// ChromeOSPolicy implements the policy-related logic used in ChromeOS.
-class ChromeOSPolicy : public Policy {
- public:
- ChromeOSPolicy() {}
- ~ChromeOSPolicy() override {}
-
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override;
-
- EvalStatus UpdateCanStart(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateDownloadParams* result,
- UpdateState update_state) const override;
-
- EvalStatus P2PEnabled(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result) const override;
-
- EvalStatus P2PEnabledChanged(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result,
- bool prev_result) const override;
-
- protected:
- // Policy override.
- std::string PolicyName() const override { return "ChromeOSPolicy"; }
-
- private:
- friend class UmChromeOSPolicyTest;
- FRIEND_TEST(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout);
- FRIEND_TEST(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForOOBE);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringNewWaitPeriodApplies);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringPrevWaitPeriodStillApplies);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringNewCountThresholdApplies);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringPrevCountThresholdStillApplies);
- FRIEND_TEST(UmChromeOSPolicyTest, UpdateCanStartAllowedScatteringSatisfied);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCanStartAllowedInteractivePreventsScattering);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCanStartAllowedP2PDownloadingBlockedDueToNumAttempts);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCanStartAllowedP2PDownloadingBlockedDueToAttemptsPeriod);
- FRIEND_TEST(UmChromeOSPolicyTest,
- UpdateCheckAllowedNextUpdateCheckOutsideDisallowedInterval);
-
- // Auxiliary constant (zero by default).
- const base::TimeDelta kZeroInterval;
-
- static const NextUpdateCheckPolicyConstants kNextUpdateCheckPolicyConstants;
-
- // Maximum number of times we'll allow using P2P for the same update payload.
- static const int kMaxP2PAttempts;
- // Maximum period of time allowed for download a payload via P2P, in seconds.
- static const int kMaxP2PAttemptsPeriodInSeconds;
-
- // A private policy for determining backoff and the download URL to use.
- // Within |update_state|, |backoff_expiry| and |is_backoff_disabled| are used
- // for determining whether backoff is still in effect; if not,
- // |download_errors| is scanned past |failures_last_updated|, and a new
- // download URL from |download_urls| is found and written to |result->url_idx|
- // (-1 means no usable URL exists); |download_errors_max| determines the
- // maximum number of attempts per URL, according to the Omaha response. If an
- // update failure is identified then |result->do_increment_failures| is set to
- // true; if backoff is enabled, a new backoff period is computed (from the
- // time of failure) based on |num_failures|. Otherwise, backoff expiry is
- // nullified, indicating that no backoff is in effect.
- //
- // If backing off but the previous backoff expiry is unchanged, returns
- // |EvalStatus::kAskMeAgainLater|. Otherwise:
- //
- // * If backing off with a new expiry time, then |result->backoff_expiry| is
- // set to this time.
- //
- // * Else, |result->backoff_expiry| is set to null, indicating that no backoff
- // is in effect.
- //
- // In any of these cases, returns |EvalStatus::kSucceeded|. If an error
- // occurred, returns |EvalStatus::kFailed|.
- EvalStatus UpdateBackoffAndDownloadUrl(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateBackoffAndDownloadUrlResult* result,
- const UpdateState& update_state) const;
-
- // A private policy for checking whether scattering is due. Writes in |result|
- // the decision as to whether or not to scatter; a wallclock-based scatter
- // wait period, which ranges from zero (do not wait) and no greater than the
- // current scatter factor provided by the device policy (if available) or the
- // maximum wait period determined by Omaha; and an update check-based
- // threshold between zero (no threshold) and the maximum number determined by
- // the update engine. Within |update_state|, |scatter_wait_period| should
- // contain the last scattering period returned by this function, or zero if no
- // wait period is known; |scatter_check_threshold| is the last update check
- // threshold, or zero if no such threshold is known. If not scattering, or if
- // any of the scattering values has changed, returns |EvalStatus::kSucceeded|;
- // otherwise, |EvalStatus::kAskMeAgainLater|.
- EvalStatus UpdateScattering(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateScatteringResult* result,
- const UpdateState& update_state) const;
-
- DISALLOW_COPY_AND_ASSIGN(ChromeOSPolicy);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_CHROMEOS_POLICY_H_
diff --git a/update_manager/chromeos_policy_unittest.cc b/update_manager/chromeos_policy_unittest.cc
deleted file mode 100644
index 5bd416d3..00000000
--- a/update_manager/chromeos_policy_unittest.cc
+++ /dev/null
@@ -1,1554 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/chromeos_policy.h"
-
-#include <memory>
-#include <set>
-
-#include "update_engine/update_manager/next_update_check_policy_impl.h"
-#include "update_engine/update_manager/policy_test_utils.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::ConnectionTethering;
-using chromeos_update_engine::ConnectionType;
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-using std::set;
-using std::string;
-
-namespace chromeos_update_manager {
-
-class UmChromeOSPolicyTest : public UmPolicyTestBase {
- protected:
- UmChromeOSPolicyTest() : UmPolicyTestBase() {
- policy_ = std::make_unique<ChromeOSPolicy>();
- }
-
- void SetUp() override {
- UmPolicyTestBase::SetUp();
- SetUpDefaultDevicePolicy();
- }
-
- void SetUpDefaultState() override {
- UmPolicyTestBase::SetUpDefaultState();
-
- // OOBE is enabled by default.
- fake_state_.config_provider()->var_is_oobe_enabled()->reset(new bool(true));
-
- // For the purpose of the tests, this is an official build and OOBE was
- // completed.
- fake_state_.system_provider()->var_is_official_build()->reset(
- new bool(true));
- fake_state_.system_provider()->var_is_oobe_complete()->reset(
- new bool(true));
- // NOLINTNEXTLINE(readability/casting)
- fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(2));
-
- // Connection is wifi, untethered.
- fake_state_.shill_provider()->var_conn_type()->reset(
- new ConnectionType(ConnectionType::kWifi));
- fake_state_.shill_provider()->var_conn_tethering()->reset(
- new ConnectionTethering(ConnectionTethering::kNotDetected));
- }
-
- // Sets up a default device policy that does not impose any restrictions
- // (HTTP) nor enables any features (P2P).
- void SetUpDefaultDevicePolicy() {
- fake_state_.device_policy_provider()->var_device_policy_is_loaded()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(false));
- fake_state_.device_policy_provider()
- ->var_allowed_connection_types_for_update()
- ->reset(nullptr);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta());
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(false));
- fake_state_.device_policy_provider()
- ->var_release_channel_delegated()
- ->reset(new bool(true));
- fake_state_.device_policy_provider()
- ->var_disallowed_time_intervals()
- ->reset(new WeeklyTimeIntervalVector());
- }
-
- // Configures the policy to return a desired value from UpdateCheckAllowed by
- // faking the current wall clock time as needed. Restores the default state.
- // This is used when testing policies that depend on this one.
- //
- // Note that the default implementation relies on NextUpdateCheckPolicyImpl to
- // set the FakeClock to the appropriate time.
- virtual void SetUpdateCheckAllowed(bool allow_check) {
- Time next_update_check;
- CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- ChromeOSPolicy::kNextUpdateCheckPolicyConstants);
- SetUpDefaultState();
- SetUpDefaultDevicePolicy();
- Time curr_time = next_update_check;
- if (allow_check)
- curr_time += TimeDelta::FromSeconds(1);
- else
- curr_time -= TimeDelta::FromSeconds(1);
- fake_clock_->SetWallclockTime(curr_time);
- }
-
- // Sets the policies required for a kiosk app to control Chrome OS version:
- // - AllowKioskAppControlChromeVersion = True
- // - UpdateDisabled = True
- // In the kiosk app manifest:
- // - RequiredPlatformVersion = 1234.
- void SetKioskAppControlsChromeOsVersion() {
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- new string("1234."));
- }
-
- // Sets up a test with the value of RollbackToTargetVersion policy (and
- // whether it's set), and returns the value of
- // UpdateCheckParams.rollback_allowed.
- bool TestRollbackAllowed(bool set_policy,
- RollbackToTargetVersion rollback_to_target_version) {
- // Update check is allowed, response includes attributes for use in the
- // request.
- SetUpdateCheckAllowed(true);
-
- if (set_policy) {
- // Override RollbackToTargetVersion device policy attribute.
- fake_state_.device_policy_provider()
- ->var_rollback_to_target_version()
- ->reset(new RollbackToTargetVersion(rollback_to_target_version));
- }
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- return result.rollback_allowed;
- }
-
- // Sets up a test with the given intervals and the current fake wallclock
- // time.
- void TestDisallowedTimeIntervals(const WeeklyTimeIntervalVector& intervals,
- const ErrorCode& expected_error_code,
- bool kiosk) {
- SetUpDefaultTimeProvider();
- if (kiosk)
- fake_state_.device_policy_provider()
- ->var_auto_launched_kiosk_app_id()
- ->reset(new string("myapp"));
- fake_state_.device_policy_provider()
- ->var_disallowed_time_intervals()
- ->reset(new WeeklyTimeIntervalVector(intervals));
-
- // Check that |expected_status| matches the value of UpdateCheckAllowed
- ErrorCode result;
- InstallPlan install_plan;
- ExpectPolicyStatus(EvalStatus::kSucceeded,
- &Policy::UpdateCanBeApplied,
- &result,
- &install_plan);
- EXPECT_EQ(result, expected_error_code);
- }
-};
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForTheTimeout) {
- // We get the next update_check timestamp from the policy's private method
- // and then we check the public method respects that value on the normal
- // case.
- Time next_update_check;
- Time last_checked_time =
- fake_clock_->GetWallclockTime() + TimeDelta::FromMinutes(1234);
-
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(last_checked_time));
- CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- ChromeOSPolicy::kNextUpdateCheckPolicyConstants);
-
- UpdateCheckParams result;
-
- // Check that the policy blocks until the next_update_check is reached.
- SetUpDefaultClock();
- SetUpDefaultState();
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(last_checked_time));
- fake_clock_->SetWallclockTime(next_update_check - TimeDelta::FromSeconds(1));
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
-
- SetUpDefaultClock();
- SetUpDefaultState();
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(last_checked_time));
- fake_clock_->SetWallclockTime(next_update_check + TimeDelta::FromSeconds(1));
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.updates_enabled);
- EXPECT_FALSE(result.interactive);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedWaitsForOOBE) {
- // Update checks are deferred until OOBE is completed.
-
- // Ensure that update is not allowed even if wait period is satisfied.
- Time next_update_check;
- Time last_checked_time =
- fake_clock_->GetWallclockTime() + TimeDelta::FromMinutes(1234);
-
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(last_checked_time));
- CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- ChromeOSPolicy::kNextUpdateCheckPolicyConstants);
-
- SetUpDefaultClock();
- SetUpDefaultState();
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(last_checked_time));
- fake_clock_->SetWallclockTime(next_update_check + TimeDelta::FromSeconds(1));
- fake_state_.system_provider()->var_is_oobe_complete()->reset(new bool(false));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
-
- // Now check that it is allowed if OOBE is completed.
- SetUpDefaultClock();
- SetUpDefaultState();
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(last_checked_time));
- fake_clock_->SetWallclockTime(next_update_check + TimeDelta::FromSeconds(1));
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.updates_enabled);
- EXPECT_FALSE(result.interactive);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedWithAttributes) {
- // Update check is allowed, response includes attributes for use in the
- // request.
- SetUpdateCheckAllowed(true);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_target_version_prefix()->reset(
- new string("1.2"));
- fake_state_.device_policy_provider()
- ->var_rollback_allowed_milestones()
- ->reset(new int(5));
- fake_state_.device_policy_provider()->var_release_channel_delegated()->reset(
- 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"));
- fake_state_.device_policy_provider()->var_quick_fix_build_token()->reset(
- new string("foo-token"));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.updates_enabled);
- 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_EQ("foo-token", result.quick_fix_build_token);
- EXPECT_FALSE(result.interactive);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackAndPowerwash) {
- EXPECT_TRUE(TestRollbackAllowed(
- true, RollbackToTargetVersion::kRollbackAndPowerwash));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackAndRestoreIfPossible) {
- // We're doing rollback even if we don't support data save and restore.
- EXPECT_TRUE(TestRollbackAllowed(
- true, RollbackToTargetVersion::kRollbackAndRestoreIfPossible));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackDisabled) {
- EXPECT_FALSE(TestRollbackAllowed(true, RollbackToTargetVersion::kDisabled));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackUnspecified) {
- EXPECT_FALSE(
- TestRollbackAllowed(true, RollbackToTargetVersion::kUnspecified));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedRollbackNotSet) {
- EXPECT_FALSE(
- TestRollbackAllowed(false, RollbackToTargetVersion::kUnspecified));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedKioskRollbackAllowed) {
- SetKioskAppControlsChromeOsVersion();
-
- EXPECT_TRUE(TestRollbackAllowed(
- true, RollbackToTargetVersion::kRollbackAndPowerwash));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedKioskRollbackDisabled) {
- SetKioskAppControlsChromeOsVersion();
-
- EXPECT_FALSE(TestRollbackAllowed(true, RollbackToTargetVersion::kDisabled));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedKioskRollbackUnspecified) {
- SetKioskAppControlsChromeOsVersion();
-
- EXPECT_FALSE(
- TestRollbackAllowed(true, RollbackToTargetVersion::kUnspecified));
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedKioskRollbackNotSet) {
- SetKioskAppControlsChromeOsVersion();
-
- EXPECT_FALSE(
- TestRollbackAllowed(false, RollbackToTargetVersion::kUnspecified));
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCheckAllowedUpdatesDisabledForUnofficialBuilds) {
- // UpdateCheckAllowed should return kAskMeAgainLater if this is an unofficial
- // build; we don't want periodic update checks on developer images.
-
- fake_state_.system_provider()->var_is_official_build()->reset(
- new bool(false));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- 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
- // without enough slots to do A/B updates.
-
- // NOLINTNEXTLINE(readability/casting)
- fake_state_.system_provider()->var_num_slots()->reset(new unsigned int(1));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_FALSE(result.updates_enabled);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedUpdatesDisabledByPolicy) {
- // UpdateCheckAllowed should return kAskMeAgainLater because a device policy
- // is loaded and prohibits updates.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCheckAllowedForcedUpdateRequestedInteractive) {
- // UpdateCheckAllowed should return true because a forced update request was
- // signaled for an interactive update.
-
- SetUpdateCheckAllowed(true);
- fake_state_.updater_provider()->var_forced_update_requested()->reset(
- new UpdateRequestStatus(UpdateRequestStatus::kInteractive));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.updates_enabled);
- EXPECT_TRUE(result.interactive);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedForcedUpdateRequestedPeriodic) {
- // UpdateCheckAllowed should return true because a forced update request was
- // signaled for a periodic check.
-
- SetUpdateCheckAllowed(true);
- fake_state_.updater_provider()->var_forced_update_requested()->reset(
- new UpdateRequestStatus(UpdateRequestStatus::kPeriodic));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.updates_enabled);
- EXPECT_FALSE(result.interactive);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedKioskPin) {
- // Update check is allowed.
- SetUpdateCheckAllowed(true);
-
- SetKioskAppControlsChromeOsVersion();
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.updates_enabled);
- EXPECT_EQ("1234.", result.target_version_prefix);
- EXPECT_FALSE(result.interactive);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedDisabledWhenNoKioskPin) {
- // Update check is allowed.
- SetUpdateCheckAllowed(true);
-
- // Disable AU policy is set but kiosk pin policy is set to false. Update is
- // disabled in such case.
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(false));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCheckAllowedKioskPinWithNoRequiredVersion) {
- // Update check is allowed.
- SetUpdateCheckAllowed(true);
-
- // AU disabled, allow kiosk to pin but there is no kiosk required platform
- // version (i.e. app does not provide the info). Update to latest in such
- // case.
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- new string());
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.updates_enabled);
- EXPECT_TRUE(result.target_version_prefix.empty());
- EXPECT_FALSE(result.interactive);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCheckAllowedKioskPinWithFailedGetRequiredVersionCall) {
- // AU disabled, allow kiosk to pin but D-Bus call to get required platform
- // version failed. Defer update check in this case.
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- nullptr);
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartFailsCheckAllowedError) {
- // The UpdateCanStart policy fails, not being able to query
- // UpdateCheckAllowed.
-
- // Configure the UpdateCheckAllowed policy to fail.
- fake_state_.updater_provider()->var_updater_started_time()->reset(nullptr);
-
- // Check that the UpdateCanStart fails.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kFailed, &Policy::UpdateCanStart, &result, update_state);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartNotAllowedCheckDue) {
- // The UpdateCanStart policy returns false because we are due for another
- // update check. Ensure that download related values are still returned.
-
- SetUpdateCheckAllowed(true);
-
- // Check that the UpdateCanStart returns false.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kCheckDue, result.cannot_start_reason);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_EQ(0, result.download_url_num_errors);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedNoDevicePolicy) {
- // The UpdateCanStart policy returns true; no device policy is loaded.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_device_policy_is_loaded()->reset(
- new bool(false));
-
- // Check that the UpdateCanStart returns true with no further attributes.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_FALSE(result.p2p_downloading_allowed);
- EXPECT_FALSE(result.p2p_sharing_allowed);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedBlankPolicy) {
- // The UpdateCanStart policy returns true; device policy is loaded but imposes
- // no restrictions on updating.
-
- SetUpdateCheckAllowed(false);
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_FALSE(result.p2p_downloading_allowed);
- EXPECT_FALSE(result.p2p_sharing_allowed);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedBackoffNewWaitPeriodApplies) {
- // The UpdateCanStart policy returns false; failures are reported and a new
- // backoff period is enacted.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
-
- // Check that UpdateCanStart returns false and a new backoff expiry is
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kBackoff, result.cannot_start_reason);
- EXPECT_TRUE(result.do_increment_failures);
- EXPECT_LT(curr_time, result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedBackoffPrevWaitPeriodStillApplies) {
- // The UpdateCanStart policy returns false; a previously enacted backoff
- // period still applies.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
- update_state.failures_last_updated = curr_time;
- update_state.backoff_expiry = curr_time + TimeDelta::FromMinutes(3);
-
- // Check that UpdateCanStart returns false and a new backoff expiry is
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(EvalStatus::kAskMeAgainLater,
- &Policy::UpdateCanStart,
- &result,
- update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kBackoff, result.cannot_start_reason);
- EXPECT_FALSE(result.do_increment_failures);
- EXPECT_LT(curr_time, result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedBackoffSatisfied) {
- // The UpdateCanStart policy returns true; a previously enacted backoff period
- // has elapsed, we're good to go.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
- update_state.failures_last_updated = curr_time - TimeDelta::FromSeconds(1);
- update_state.backoff_expiry = curr_time - TimeDelta::FromSeconds(1);
-
- // Check that UpdateCanStart returns false and a new backoff expiry is
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kUndefined, result.cannot_start_reason);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
- EXPECT_EQ(Time(), result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedBackoffDisabled) {
- // The UpdateCanStart policy returns false; failures are reported but backoff
- // is disabled.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
- update_state.is_backoff_disabled = true;
-
- // Check that UpdateCanStart returns false and a new backoff expiry is
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kUndefined, result.cannot_start_reason);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_TRUE(result.do_increment_failures);
- EXPECT_EQ(Time(), result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedNoBackoffInteractive) {
- // The UpdateCanStart policy returns false; failures are reported but this is
- // an interactive update check.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
- update_state.interactive = true;
-
- // Check that UpdateCanStart returns false and a new backoff expiry is
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kUndefined, result.cannot_start_reason);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_TRUE(result.do_increment_failures);
- EXPECT_EQ(Time(), result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedNoBackoffDelta) {
- // The UpdateCanStart policy returns false; failures are reported but this is
- // a delta payload.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
- update_state.is_delta_payload = true;
-
- // Check that UpdateCanStart returns false and a new backoff expiry is
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kUndefined, result.cannot_start_reason);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_TRUE(result.do_increment_failures);
- EXPECT_EQ(Time(), result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedNoBackoffUnofficialBuild) {
- // The UpdateCanStart policy returns false; failures are reported but this is
- // an unofficial build.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
-
- fake_state_.system_provider()->var_is_official_build()->reset(
- new bool(false));
-
- // Check that UpdateCanStart returns false and a new backoff expiry is
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kUndefined, result.cannot_start_reason);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_TRUE(result.do_increment_failures);
- EXPECT_EQ(Time(), result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartFailsScatteringFailed) {
- // The UpdateCanStart policy fails because the UpdateScattering policy it
- // depends on fails (unset variable).
-
- SetUpdateCheckAllowed(false);
-
- // Override the default seed variable with a null value so that the policy
- // request would fail.
- // TODO(garnold) This failure may or may not fail a number
- // sub-policies/decisions, like scattering and backoff. We'll need a more
- // deliberate setup to ensure that we're failing what we want to be failing.
- fake_state_.random_provider()->var_seed()->reset(nullptr);
-
- // Check that the UpdateCanStart fails.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kFailed, &Policy::UpdateCanStart, &result, update_state);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringNewWaitPeriodApplies) {
- // The UpdateCanStart policy returns false; device policy is loaded and
- // scattering applies due to an unsatisfied wait period, which was newly
- // generated.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromMinutes(2)));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
-
- // Check that the UpdateCanStart returns false and a new wait period
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
- EXPECT_LT(TimeDelta(), result.scatter_wait_period);
- EXPECT_EQ(0, result.scatter_check_threshold);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringPrevWaitPeriodStillApplies) {
- // The UpdateCanStart policy returns false w/ kAskMeAgainLater; device policy
- // is loaded and a previously generated scattering period still applies, none
- // of the scattering values has changed.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromMinutes(2)));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
- update_state.scatter_wait_period = TimeDelta::FromSeconds(35);
-
- // Check that the UpdateCanStart returns false and a new wait period
- // generated.
- UpdateDownloadParams result;
- ExpectPolicyStatus(EvalStatus::kAskMeAgainLater,
- &Policy::UpdateCanStart,
- &result,
- update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
- EXPECT_EQ(TimeDelta::FromSeconds(35), result.scatter_wait_period);
- EXPECT_EQ(0, result.scatter_check_threshold);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringNewCountThresholdApplies) {
- // The UpdateCanStart policy returns false; device policy is loaded and
- // scattering applies due to an unsatisfied update check count threshold.
- //
- // This ensures a non-zero check threshold, which may or may not be combined
- // with a non-zero wait period (for which we cannot reliably control).
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromSeconds(1)));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
- update_state.scatter_check_threshold_min = 2;
- update_state.scatter_check_threshold_max = 5;
-
- // Check that the UpdateCanStart returns false.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
- EXPECT_LE(2, result.scatter_check_threshold);
- EXPECT_GE(5, result.scatter_check_threshold);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartNotAllowedScatteringPrevCountThresholdStillApplies) {
- // The UpdateCanStart policy returns false; device policy is loaded and
- // scattering due to a previously generated count threshold still applies.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromSeconds(1)));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
- update_state.scatter_check_threshold = 3;
- update_state.scatter_check_threshold_min = 2;
- update_state.scatter_check_threshold_max = 5;
-
- // Check that the UpdateCanStart returns false.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kScattering, result.cannot_start_reason);
- EXPECT_EQ(3, result.scatter_check_threshold);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedScatteringSatisfied) {
- // The UpdateCanStart policy returns true; device policy is loaded and
- // scattering is enabled, but both wait period and check threshold are
- // satisfied.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromSeconds(120)));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(75));
- update_state.num_checks = 4;
- update_state.scatter_wait_period = TimeDelta::FromSeconds(60);
- update_state.scatter_check_threshold = 3;
- update_state.scatter_check_threshold_min = 2;
- update_state.scatter_check_threshold_max = 5;
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(TimeDelta(), result.scatter_wait_period);
- EXPECT_EQ(0, result.scatter_check_threshold);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartAllowedInteractivePreventsScattering) {
- // The UpdateCanStart policy returns true; device policy is loaded and
- // scattering would have applied, except that the update check is interactive
- // and so it is suppressed.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromSeconds(1)));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
- update_state.interactive = true;
- update_state.scatter_check_threshold = 0;
- update_state.scatter_check_threshold_min = 2;
- update_state.scatter_check_threshold_max = 5;
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(TimeDelta(), result.scatter_wait_period);
- EXPECT_EQ(0, result.scatter_check_threshold);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedOobePreventsScattering) {
- // The UpdateCanStart policy returns true; device policy is loaded and
- // scattering would have applied, except that OOBE was not completed and so it
- // is suppressed.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromSeconds(1)));
- fake_state_.system_provider()->var_is_oobe_complete()->reset(new bool(false));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
- update_state.interactive = true;
- update_state.scatter_check_threshold = 0;
- update_state.scatter_check_threshold_min = 2;
- update_state.scatter_check_threshold_max = 5;
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(TimeDelta(), result.scatter_wait_period);
- EXPECT_EQ(0, result.scatter_check_threshold);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithAttributes) {
- // The UpdateCanStart policy returns true; device policy permits both HTTP and
- // P2P updates, as well as a non-empty target channel string.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(true));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_TRUE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithP2PFromUpdater) {
- // The UpdateCanStart policy returns true; device policy forbids both HTTP and
- // P2P updates, but the updater is configured to allow P2P and overrules the
- // setting.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.updater_provider()->var_p2p_enabled()->reset(new bool(true));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_TRUE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartAllowedP2PDownloadingBlockedDueToOmaha) {
- // The UpdateCanStart policy returns true; device policy permits HTTP, but
- // policy blocks P2P downloading because Omaha forbids it. P2P sharing is
- // still permitted.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(true));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.p2p_downloading_disabled = true;
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_FALSE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedP2PSharingBlockedDueToOmaha) {
- // The UpdateCanStart policy returns true; device policy permits HTTP, but
- // policy blocks P2P sharing because Omaha forbids it. P2P downloading is
- // still permitted.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(true));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.p2p_sharing_disabled = true;
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_TRUE(result.p2p_downloading_allowed);
- EXPECT_FALSE(result.p2p_sharing_allowed);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartAllowedP2PDownloadingBlockedDueToNumAttempts) {
- // The UpdateCanStart policy returns true; device policy permits HTTP but
- // blocks P2P download, because the max number of P2P downloads have been
- // attempted. P2P sharing is still permitted.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(true));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.p2p_num_attempts = ChromeOSPolicy::kMaxP2PAttempts;
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_FALSE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartAllowedP2PDownloadingBlockedDueToAttemptsPeriod) {
- // The UpdateCanStart policy returns true; device policy permits HTTP but
- // blocks P2P download, because the max period for attempt to download via P2P
- // has elapsed. P2P sharing is still permitted.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(true));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.p2p_num_attempts = 1;
- update_state.p2p_first_attempted =
- fake_clock_->GetWallclockTime() -
- TimeDelta::FromSeconds(ChromeOSPolicy::kMaxP2PAttemptsPeriodInSeconds +
- 1);
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_FALSE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartAllowedWithHttpUrlForUnofficialBuild) {
- // The UpdateCanStart policy returns true; device policy forbids both HTTP and
- // P2P updates, but marking this an unofficial build overrules the HTTP
- // setting.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(false));
- fake_state_.system_provider()->var_is_official_build()->reset(
- new bool(false));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithHttpsUrl) {
- // The UpdateCanStart policy returns true; device policy forbids both HTTP and
- // P2P updates, but an HTTPS URL is provided and selected for download.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(false));
-
- // Add an HTTPS URL.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.download_urls.emplace_back("https://secure/url/");
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(1, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedMaxErrorsNotExceeded) {
- // The UpdateCanStart policy returns true; the first URL has download errors
- // but does not exceed the maximum allowed number of failures, so it is stilli
- // usable.
-
- SetUpdateCheckAllowed(false);
-
- // Add a second URL; update with this URL attempted and failed enough times to
- // disqualify the current (first) URL.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.num_checks = 5;
- update_state.download_urls.emplace_back("http://another/fake/url/");
- Time t = fake_clock_->GetWallclockTime() - TimeDelta::FromSeconds(12);
- for (int i = 0; i < 5; i++) {
- update_state.download_errors.emplace_back(
- 0, ErrorCode::kDownloadTransferError, t);
- t += TimeDelta::FromSeconds(1);
- }
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(5, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithSecondUrlMaxExceeded) {
- // The UpdateCanStart policy returns true; the first URL exceeded the maximum
- // allowed number of failures, but a second URL is available.
-
- SetUpdateCheckAllowed(false);
-
- // Add a second URL; update with this URL attempted and failed enough times to
- // disqualify the current (first) URL.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.num_checks = 10;
- update_state.download_urls.emplace_back("http://another/fake/url/");
- Time t = fake_clock_->GetWallclockTime() - TimeDelta::FromSeconds(12);
- for (int i = 0; i < 11; i++) {
- update_state.download_errors.emplace_back(
- 0, ErrorCode::kDownloadTransferError, t);
- t += TimeDelta::FromSeconds(1);
- }
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(1, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedWithSecondUrlHardError) {
- // The UpdateCanStart policy returns true; the first URL fails with a hard
- // error, but a second URL is available.
-
- SetUpdateCheckAllowed(false);
-
- // Add a second URL; update with this URL attempted and failed in a way that
- // causes it to switch directly to the next URL.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.num_checks = 10;
- update_state.download_urls.emplace_back("http://another/fake/url/");
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kPayloadHashMismatchError,
- fake_clock_->GetWallclockTime() - TimeDelta::FromSeconds(1));
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(1, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedUrlWrapsAround) {
- // The UpdateCanStart policy returns true; URL search properly wraps around
- // the last one on the list.
-
- SetUpdateCheckAllowed(false);
-
- // Add a second URL; update with this URL attempted and failed in a way that
- // causes it to switch directly to the next URL. We must disable backoff in
- // order for it not to interfere.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- update_state.num_checks = 1;
- update_state.is_backoff_disabled = true;
- update_state.download_urls.emplace_back("http://another/fake/url/");
- update_state.download_errors.emplace_back(
- 1,
- ErrorCode::kPayloadHashMismatchError,
- fake_clock_->GetWallclockTime() - TimeDelta::FromSeconds(1));
-
- // Check that the UpdateCanStart returns true.
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_TRUE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartNotAllowedNoUsableUrls) {
- // The UpdateCanStart policy returns false; there's a single HTTP URL but its
- // use is forbidden by policy.
- //
- // Note: In the case where no usable URLs are found, the policy should not
- // increment the number of failed attempts! Doing so would result in a
- // non-idempotent semantics, and does not fall within the intended purpose of
- // the backoff mechanism anyway.
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(false));
-
- // Check that the UpdateCanStart returns false.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_FALSE(result.update_can_start);
- EXPECT_EQ(UpdateCannotStartReason::kCannotDownload,
- result.cannot_start_reason);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedNoUsableUrlsButP2PEnabled) {
- // The UpdateCanStart policy returns true; there's a single HTTP URL but its
- // use is forbidden by policy, however P2P is enabled. The result indicates
- // that no URL can be used.
- //
- // Note: The number of failed attempts should not increase in this case (see
- // above test).
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(false));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_TRUE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
- EXPECT_GT(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanStartAllowedNoUsableUrlsButEnterpriseEnrolled) {
- // The UpdateCanStart policy returns true; there's a single HTTP URL but its
- // use is forbidden by policy, and P2P is unset on the policy, however the
- // device is enterprise-enrolled so P2P is allowed. The result indicates that
- // no URL can be used.
- //
- // Note: The number of failed attempts should not increase in this case (see
- // above test).
-
- SetUpdateCheckAllowed(false);
-
- // Override specific device policy attributes.
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(nullptr);
- fake_state_.device_policy_provider()->var_has_owner()->reset(new bool(false));
- fake_state_.device_policy_provider()->var_http_downloads_enabled()->reset(
- new bool(false));
-
- // Check that the UpdateCanStart returns true.
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromMinutes(10));
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_TRUE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
- EXPECT_GT(0, result.download_url_idx);
- EXPECT_TRUE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_FALSE(result.do_increment_failures);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedScatteringSupressedDueToP2P) {
- // The UpdateCanStart policy returns true; scattering should have applied, but
- // P2P download is allowed. Scattering values are nonetheless returned, and so
- // are download URL values, albeit the latter are not allowed to be used.
-
- SetUpdateCheckAllowed(false);
- fake_state_.device_policy_provider()->var_scatter_factor()->reset(
- new TimeDelta(TimeDelta::FromMinutes(2)));
- fake_state_.updater_provider()->var_p2p_enabled()->reset(new bool(true));
-
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(1));
- update_state.scatter_wait_period = TimeDelta::FromSeconds(35);
-
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_FALSE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_TRUE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
- EXPECT_FALSE(result.do_increment_failures);
- EXPECT_EQ(TimeDelta::FromSeconds(35), result.scatter_wait_period);
- EXPECT_EQ(0, result.scatter_check_threshold);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanStartAllowedBackoffSupressedDueToP2P) {
- // The UpdateCanStart policy returns true; backoff should have applied, but
- // P2P download is allowed. Backoff values are nonetheless returned, and so
- // are download URL values, albeit the latter are not allowed to be used.
-
- SetUpdateCheckAllowed(false);
-
- const Time curr_time = fake_clock_->GetWallclockTime();
- UpdateState update_state = GetDefaultUpdateState(TimeDelta::FromSeconds(10));
- update_state.download_errors_max = 1;
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(8));
- update_state.download_errors.emplace_back(
- 0,
- ErrorCode::kDownloadTransferError,
- curr_time - TimeDelta::FromSeconds(2));
- fake_state_.updater_provider()->var_p2p_enabled()->reset(new bool(true));
-
- UpdateDownloadParams result;
- ExpectPolicyStatus(
- EvalStatus::kSucceeded, &Policy::UpdateCanStart, &result, update_state);
- EXPECT_TRUE(result.update_can_start);
- EXPECT_EQ(0, result.download_url_idx);
- EXPECT_FALSE(result.download_url_allowed);
- EXPECT_EQ(0, result.download_url_num_errors);
- EXPECT_TRUE(result.p2p_downloading_allowed);
- EXPECT_TRUE(result.p2p_sharing_allowed);
- EXPECT_TRUE(result.do_increment_failures);
- EXPECT_LT(curr_time, result.backoff_expiry);
-}
-
-TEST_F(UmChromeOSPolicyTest, P2PEnabledNotAllowed) {
- bool result;
- ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::P2PEnabled, &result);
- EXPECT_FALSE(result);
-}
-
-TEST_F(UmChromeOSPolicyTest, P2PEnabledAllowedByDevicePolicy) {
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(
- new bool(true));
-
- bool result;
- ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::P2PEnabled, &result);
- EXPECT_TRUE(result);
-}
-
-TEST_F(UmChromeOSPolicyTest, P2PEnabledAllowedByUpdater) {
- fake_state_.updater_provider()->var_p2p_enabled()->reset(new bool(true));
-
- bool result;
- ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::P2PEnabled, &result);
- EXPECT_TRUE(result);
-}
-
-TEST_F(UmChromeOSPolicyTest, P2PEnabledAllowedDeviceEnterpriseEnrolled) {
- fake_state_.device_policy_provider()->var_au_p2p_enabled()->reset(nullptr);
- fake_state_.device_policy_provider()->var_has_owner()->reset(new bool(false));
-
- bool result;
- ExpectPolicyStatus(EvalStatus::kSucceeded, &Policy::P2PEnabled, &result);
- EXPECT_TRUE(result);
-}
-
-TEST_F(UmChromeOSPolicyTest, P2PEnabledChangedBlocks) {
- bool result;
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::P2PEnabledChanged, &result, false);
-}
-
-TEST_F(UmChromeOSPolicyTest,
- UpdateCanBeAppliedForcedUpdatesDisablesTimeRestrictions) {
- Time curr_time = fake_clock_->GetWallclockTime();
- fake_state_.updater_provider()->var_forced_update_requested()->reset(
- new UpdateRequestStatus(UpdateRequestStatus::kInteractive));
- // Should return kAskMeAgainLater when updated are not forced.
- TestDisallowedTimeIntervals(
- {WeeklyTimeInterval(
- WeeklyTime::FromTime(curr_time),
- WeeklyTime::FromTime(curr_time + TimeDelta::FromMinutes(1)))},
- ErrorCode::kSuccess,
- /* kiosk = */ true);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanBeAppliedFailsInDisallowedTime) {
- Time curr_time = fake_clock_->GetWallclockTime();
- TestDisallowedTimeIntervals(
- {WeeklyTimeInterval(
- WeeklyTime::FromTime(curr_time),
- WeeklyTime::FromTime(curr_time + TimeDelta::FromMinutes(1)))},
- ErrorCode::kOmahaUpdateDeferredPerPolicy,
- /* kiosk = */ true);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanBeAppliedOutsideDisallowedTime) {
- Time curr_time = fake_clock_->GetWallclockTime();
- TestDisallowedTimeIntervals(
- {WeeklyTimeInterval(
- WeeklyTime::FromTime(curr_time - TimeDelta::FromHours(3)),
- WeeklyTime::FromTime(curr_time))},
- ErrorCode::kSuccess,
- /* kiosk = */ true);
-}
-
-TEST_F(UmChromeOSPolicyTest, UpdateCanBeAppliedPassesOnNonKiosk) {
- Time curr_time = fake_clock_->GetWallclockTime();
- TestDisallowedTimeIntervals(
- {WeeklyTimeInterval(
- WeeklyTime::FromTime(curr_time),
- WeeklyTime::FromTime(curr_time + TimeDelta::FromMinutes(1)))},
- ErrorCode::kSuccess,
- /* kiosk = */ false);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/config_provider.h b/update_manager/config_provider.h
deleted file mode 100644
index 36d57a7b..00000000
--- a/update_manager/config_provider.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_CONFIG_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_CONFIG_PROVIDER_H_
-
-#include "update_engine/update_manager/provider.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// Provider for const system configurations. This provider reads the
-// configuration from a file on /etc.
-class ConfigProvider : public Provider {
- public:
- // Returns a variable stating whether the out of the box experience (OOBE) is
- // enabled on this device. A value of false means that the device doesn't have
- // an OOBE workflow.
- virtual Variable<bool>* var_is_oobe_enabled() = 0;
-
- protected:
- ConfigProvider() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ConfigProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_CONFIG_PROVIDER_H_
diff --git a/update_manager/default_policy.cc b/update_manager/default_policy.cc
deleted file mode 100644
index 0713e06a..00000000
--- a/update_manager/default_policy.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-//
-// Copyright (C) 2014 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/common/system_state.h"
-#include "update_engine/update_manager/default_policy.h"
-
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-using chromeos_update_engine::SystemState;
-
-namespace {
-
-// A fixed minimum interval between consecutive allowed update checks. This
-// needs to be long enough to prevent busywork and/or DDoS attacks on Omaha, but
-// at the same time short enough to allow the machine to update itself
-// reasonably soon.
-const int kCheckIntervalInSeconds = 15 * 60;
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-EvalStatus DefaultPolicy::UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- 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.
- result->rollback_on_channel_downgrade = false;
- result->interactive = false;
- result->quick_fix_build_token.clear();
-
- // Ensure that the minimum interval is set. If there's no clock, this defaults
- // to always allowing the update.
- if (!aux_state_->IsLastCheckAllowedTimeSet() ||
- ec->IsMonotonicTimeGreaterThan(
- aux_state_->last_check_allowed_time() +
- base::TimeDelta::FromSeconds(kCheckIntervalInSeconds))) {
- aux_state_->set_last_check_allowed_time(
- SystemState::Get()->clock()->GetMonotonicTime());
- return EvalStatus::kSucceeded;
- }
-
- return EvalStatus::kAskMeAgainLater;
-}
-
-EvalStatus DefaultPolicy::UpdateCanBeApplied(EvaluationContext* ec,
- State* state,
- std::string* error,
- ErrorCode* result,
- InstallPlan* install_plan) const {
- *result = ErrorCode::kSuccess;
- return EvalStatus::kSucceeded;
-}
-
-EvalStatus DefaultPolicy::UpdateCanStart(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateDownloadParams* result,
- const UpdateState update_state) const {
- result->update_can_start = true;
- result->cannot_start_reason = UpdateCannotStartReason::kUndefined;
- result->download_url_idx = 0;
- result->download_url_allowed = true;
- result->download_url_num_errors = 0;
- result->p2p_downloading_allowed = false;
- result->p2p_sharing_allowed = false;
- result->do_increment_failures = false;
- result->backoff_expiry = base::Time();
- result->scatter_wait_period = base::TimeDelta();
- result->scatter_check_threshold = 0;
- return EvalStatus::kSucceeded;
-}
-
-EvalStatus DefaultPolicy::P2PEnabled(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result) const {
- *result = false;
- return EvalStatus::kSucceeded;
-}
-
-EvalStatus DefaultPolicy::P2PEnabledChanged(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result,
- bool prev_result) const {
- // This policy will always prohibit P2P, so this is signaling to the caller
- // that the decision is final (because the current value is the same as the
- // previous one) and there's no need to issue another call.
- *result = false;
- return EvalStatus::kSucceeded;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/default_policy.h b/update_manager/default_policy.h
deleted file mode 100644
index c93bb46c..00000000
--- a/update_manager/default_policy.h
+++ /dev/null
@@ -1,108 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_DEFAULT_POLICY_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_DEFAULT_POLICY_H_
-
-#include <memory>
-#include <string>
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/policy.h"
-
-namespace chromeos_update_manager {
-
-// Auxiliary state class for DefaultPolicy evaluations.
-//
-// IMPORTANT: The use of a state object in policies is generally forbidden, as
-// it was a design decision to keep policy calls side-effect free. We make an
-// exception here to ensure that DefaultPolicy indeed serves as a safe (and
-// secure) fallback option. This practice should be avoided when imlpementing
-// other policies.
-class DefaultPolicyState {
- public:
- DefaultPolicyState() {}
-
- bool IsLastCheckAllowedTimeSet() const {
- return last_check_allowed_time_ != base::Time::Max();
- }
-
- // Sets/returns the point time on the monotonic time scale when the latest
- // check allowed was recorded.
- void set_last_check_allowed_time(base::Time timestamp) {
- last_check_allowed_time_ = timestamp;
- }
- base::Time last_check_allowed_time() const {
- return last_check_allowed_time_;
- }
-
- private:
- base::Time last_check_allowed_time_ = base::Time::Max();
-};
-
-// The DefaultPolicy is a safe Policy implementation that doesn't fail. The
-// values returned by this policy are safe default in case of failure of the
-// actual policy being used by the UpdateManager.
-class DefaultPolicy : public Policy {
- public:
- DefaultPolicy() : aux_state_(new DefaultPolicyState()) {}
- ~DefaultPolicy() override = default;
-
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override;
-
- EvalStatus UpdateCanStart(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateDownloadParams* result,
- UpdateState update_state) const override;
-
- EvalStatus P2PEnabled(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result) const override;
-
- EvalStatus P2PEnabledChanged(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result,
- bool prev_result) const override;
-
- protected:
- // Policy override.
- std::string PolicyName() const override { return "DefaultPolicy"; }
-
- private:
- // An auxiliary state object.
- std::unique_ptr<DefaultPolicyState> aux_state_;
-
- DISALLOW_COPY_AND_ASSIGN(DefaultPolicy);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_DEFAULT_POLICY_H_
diff --git a/update_manager/device_policy_provider.h b/update_manager/device_policy_provider.h
deleted file mode 100644
index 5112f684..00000000
--- a/update_manager/device_policy_provider.h
+++ /dev/null
@@ -1,113 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_DEVICE_POLICY_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_DEVICE_POLICY_PROVIDER_H_
-
-#include <set>
-#include <string>
-
-#include <base/time/time.h>
-#include <base/version.h>
-#include <policy/libpolicy.h>
-
-#include "update_engine/update_manager/provider.h"
-#include "update_engine/update_manager/rollback_prefs.h"
-#include "update_engine/update_manager/shill_provider.h"
-#include "update_engine/update_manager/variable.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-namespace chromeos_update_manager {
-
-// Provides access to the current DevicePolicy.
-class DevicePolicyProvider : public Provider {
- public:
- ~DevicePolicyProvider() override {}
-
- // Variable stating whether the DevicePolicy was loaded.
- virtual Variable<bool>* var_device_policy_is_loaded() = 0;
-
- // Variables mapping the information received on the DevicePolicy protobuf.
- virtual Variable<std::string>* var_release_channel() = 0;
-
- 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;
-
- // Variable returning what should happen if the target_version_prefix is
- // earlier than the current Chrome OS version.
- virtual Variable<RollbackToTargetVersion>*
- var_rollback_to_target_version() = 0;
-
- // Variable returning the number of Chrome milestones rollback should be
- // possible. Rollback protection will be postponed by this many versions.
- virtual Variable<int>* var_rollback_allowed_milestones() = 0;
-
- // Returns a non-negative scatter interval used for updates.
- virtual Variable<base::TimeDelta>* var_scatter_factor() = 0;
-
- // Variable returning the set of connection types allowed for updates. The
- // identifiers returned are consistent with the ones returned by the
- // ShillProvider.
- virtual Variable<std::set<chromeos_update_engine::ConnectionType>>*
- var_allowed_connection_types_for_update() = 0;
-
- // Variable stating whether the device has an owner. For enterprise enrolled
- // devices, this will be false as the device owner has an empty string.
- virtual Variable<bool>* var_has_owner() = 0;
-
- virtual Variable<bool>* var_http_downloads_enabled() = 0;
-
- virtual Variable<bool>* var_au_p2p_enabled() = 0;
-
- virtual Variable<bool>* var_allow_kiosk_app_control_chrome_version() = 0;
-
- // Variable that contains the app that is to be run when launched in kiosk
- // mode. If the device is not in kiosk-mode this should be empty.
- virtual Variable<std::string>* var_auto_launched_kiosk_app_id() = 0;
-
- // Variable that contains the time intervals during the week for which update
- // checks are disallowed.
- 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;
-
- // Variable that contains a token which maps to a Chrome OS Quick Fix Build to
- // which the device would be updated if not blocked by another policy.
- virtual Variable<std::string>* var_quick_fix_build_token() = 0;
-
- protected:
- DevicePolicyProvider() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DevicePolicyProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_DEVICE_POLICY_PROVIDER_H_
diff --git a/update_manager/enough_slots_ab_updates_policy_impl.cc b/update_manager/enough_slots_ab_updates_policy_impl.cc
deleted file mode 100644
index 70f15d47..00000000
--- a/update_manager/enough_slots_ab_updates_policy_impl.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// 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/update_manager/enough_slots_ab_updates_policy_impl.h"
-
-namespace chromeos_update_manager {
-
-// Do not perform any updates if booted from removable device. This decision
-// is final.
-EvalStatus EnoughSlotsAbUpdatesPolicyImpl::UpdateCheckAllowed(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const {
- const auto* num_slots_p =
- ec->GetValue(state->system_provider()->var_num_slots());
- if (num_slots_p == nullptr || *num_slots_p < 2) {
- LOG(INFO) << "Not enough slots for A/B updates, disabling update checks.";
- result->updates_enabled = false;
- return EvalStatus::kSucceeded;
- }
- return EvalStatus::kContinue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/enough_slots_ab_updates_policy_impl.h b/update_manager/enough_slots_ab_updates_policy_impl.h
deleted file mode 100644
index 1d453894..00000000
--- a/update_manager/enough_slots_ab_updates_policy_impl.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// 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_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Do not perform any updates if booted from removable device.
-class EnoughSlotsAbUpdatesPolicyImpl : public PolicyImplBase {
- public:
- EnoughSlotsAbUpdatesPolicyImpl() = default;
- ~EnoughSlotsAbUpdatesPolicyImpl() override = default;
-
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- protected:
- std::string PolicyName() const override {
- return "EnoughSlotsAbUpdatesPolicyImpl";
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(EnoughSlotsAbUpdatesPolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_ENOUGH_SLOTS_AB_UPDATES_POLICY_IMPL_H_
diff --git a/update_manager/enterprise_device_policy_impl.cc b/update_manager/enterprise_device_policy_impl.cc
deleted file mode 100644
index b9a11e11..00000000
--- a/update_manager/enterprise_device_policy_impl.cc
+++ /dev/null
@@ -1,178 +0,0 @@
-//
-// 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/update_manager/enterprise_device_policy_impl.h"
-
-#include "update_engine/common/utils.h"
-
-using std::string;
-
-namespace chromeos_update_manager {
-
-// Check to see if Enterprise-managed (has DevicePolicy) and/or Kiosk-mode. If
-// so, then defer to those settings.
-EvalStatus EnterpriseDevicePolicyImpl::UpdateCheckAllowed(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const {
- DevicePolicyProvider* const dp_provider = state->device_policy_provider();
- SystemProvider* const system_provider = state->system_provider();
-
- const bool* device_policy_is_loaded_p =
- ec->GetValue(dp_provider->var_device_policy_is_loaded());
- if (device_policy_is_loaded_p && *device_policy_is_loaded_p) {
- bool kiosk_app_control_chrome_version = false;
-
- // Check whether updates are disabled by policy.
- const bool* update_disabled_p =
- ec->GetValue(dp_provider->var_update_disabled());
- if (update_disabled_p && *update_disabled_p) {
- // Check whether allow kiosk app to control chrome version policy. This
- // policy is only effective when AU is disabled by admin.
- const bool* allow_kiosk_app_control_chrome_version_p = ec->GetValue(
- dp_provider->var_allow_kiosk_app_control_chrome_version());
- kiosk_app_control_chrome_version =
- allow_kiosk_app_control_chrome_version_p &&
- *allow_kiosk_app_control_chrome_version_p;
- if (!kiosk_app_control_chrome_version) {
- // No kiosk pin chrome version policy. AU is really disabled.
- LOG(INFO) << "Updates disabled by policy, blocking update checks.";
- return EvalStatus::kAskMeAgainLater;
- }
- }
-
- // By default, result->rollback_allowed is false.
- if (kiosk_app_control_chrome_version) {
- // Get the required platform version from Chrome.
- const string* kiosk_required_platform_version_p =
- ec->GetValue(system_provider->var_kiosk_required_platform_version());
- if (!kiosk_required_platform_version_p) {
- LOG(INFO) << "Kiosk app required platform version is not fetched, "
- "blocking update checks.";
- return EvalStatus::kAskMeAgainLater;
- } else if (kiosk_required_platform_version_p->empty()) {
- // The platform version could not be fetched several times. Update
- // based on |DeviceMinimumVersion| instead (crbug.com/1048931).
- const base::Version* device_minimum_version_p =
- ec->GetValue(dp_provider->var_device_minimum_version());
- const base::Version* current_version_p(
- ec->GetValue(system_provider->var_chromeos_version()));
- if (device_minimum_version_p && device_minimum_version_p->IsValid() &&
- current_version_p && current_version_p->IsValid() &&
- *current_version_p > *device_minimum_version_p) {
- // Do not update if the current version is newer than the minimum
- // version.
- LOG(INFO) << "Reading kiosk app required platform version failed "
- "repeatedly but current version is newer than "
- "DeviceMinimumVersion. Blocking update checks. "
- "Current version: "
- << *current_version_p
- << " DeviceMinimumVersion: " << *device_minimum_version_p;
- return EvalStatus::kAskMeAgainLater;
- }
- LOG(WARNING) << "Reading kiosk app required platform version failed "
- "repeatedly. Attempting an update without it now.";
- // An empty string for |target_version_prefix| allows arbitrary updates.
- result->target_version_prefix = "";
- } else {
- result->target_version_prefix = *kiosk_required_platform_version_p;
- LOG(INFO) << "Allow kiosk app to control Chrome version policy is set, "
- << "target version is " << result->target_version_prefix;
- }
- // TODO(hunyadym): Add support for allowing rollback using the manifest
- // (if policy doesn't specify otherwise).
- } else {
- // Determine whether a target version prefix is dictated by policy.
- const string* target_version_prefix_p =
- ec->GetValue(dp_provider->var_target_version_prefix());
- if (target_version_prefix_p)
- result->target_version_prefix = *target_version_prefix_p;
- }
-
- // Policy always overwrites whether rollback is allowed by the kiosk app
- // manifest.
- const RollbackToTargetVersion* rollback_to_target_version_p =
- ec->GetValue(dp_provider->var_rollback_to_target_version());
- if (rollback_to_target_version_p) {
- switch (*rollback_to_target_version_p) {
- case RollbackToTargetVersion::kUnspecified:
- // We leave the default or the one specified by the kiosk app.
- break;
- case RollbackToTargetVersion::kDisabled:
- LOG(INFO) << "Policy disables rollbacks.";
- result->rollback_allowed = false;
- result->rollback_data_save_requested = false;
- break;
- case RollbackToTargetVersion::kRollbackAndPowerwash:
- LOG(INFO) << "Policy allows rollbacks with powerwash.";
- result->rollback_allowed = true;
- result->rollback_data_save_requested = false;
- break;
- case RollbackToTargetVersion::kRollbackAndRestoreIfPossible:
- LOG(INFO)
- << "Policy allows rollbacks, also tries to restore if possible.";
- result->rollback_allowed = true;
- result->rollback_data_save_requested = true;
- break;
- case RollbackToTargetVersion::kMaxValue:
- NOTREACHED();
- // Don't add a default case to let the compiler warn about newly
- // added enum values which should be added here.
- }
- }
-
- // Determine allowed milestones for rollback
- const int* rollback_allowed_milestones_p =
- ec->GetValue(dp_provider->var_rollback_allowed_milestones());
- if (rollback_allowed_milestones_p)
- result->rollback_allowed_milestones = *rollback_allowed_milestones_p;
-
- // Determine whether a target channel is dictated by policy and whether we
- // should rollback in case that channel is more stable.
- const bool* release_channel_delegated_p =
- ec->GetValue(dp_provider->var_release_channel_delegated());
- if (release_channel_delegated_p && !(*release_channel_delegated_p)) {
- const string* release_channel_p =
- ec->GetValue(dp_provider->var_release_channel());
- if (release_channel_p) {
- result->target_channel = *release_channel_p;
- const ChannelDowngradeBehavior* channel_downgrade_behavior_p =
- ec->GetValue(dp_provider->var_channel_downgrade_behavior());
- if (channel_downgrade_behavior_p &&
- *channel_downgrade_behavior_p ==
- ChannelDowngradeBehavior::kRollback) {
- result->rollback_on_channel_downgrade = true;
- }
- }
- }
-
- 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;
- }
-
- const string* quick_fix_build_token_p =
- ec->GetValue(dp_provider->var_quick_fix_build_token());
- if (quick_fix_build_token_p) {
- result->quick_fix_build_token = *quick_fix_build_token_p;
- }
- }
- return EvalStatus::kContinue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/enterprise_device_policy_impl.h b/update_manager/enterprise_device_policy_impl.h
deleted file mode 100644
index 4b97fda6..00000000
--- a/update_manager/enterprise_device_policy_impl.h
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// 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_UPDATE_MANAGER_ENTERPRISE_DEVICE_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_ENTERPRISE_DEVICE_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Check to see if Enterprise-managed (has DevicePolicy) and/or Kiosk-mode. If
-// so, then defer to those settings.
-class EnterpriseDevicePolicyImpl : public PolicyImplBase {
- public:
- EnterpriseDevicePolicyImpl() = default;
- ~EnterpriseDevicePolicyImpl() override = default;
-
- std::string PolicyName() const override {
- return "EnterpriseDevicePolicyImpl";
- }
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(EnterpriseDevicePolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_ENTERPRISE_DEVICE_POLICY_IMPL_H_
diff --git a/update_manager/enterprise_device_policy_impl_unittest.cc b/update_manager/enterprise_device_policy_impl_unittest.cc
deleted file mode 100644
index 30f54b1c..00000000
--- a/update_manager/enterprise_device_policy_impl_unittest.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-//
-// 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/update_manager/enterprise_device_policy_impl.h"
-
-#include <memory>
-
-#include "update_engine/update_manager/policy_test_utils.h"
-
-namespace chromeos_update_manager {
-
-class UmEnterpriseDevicePolicyImplTest : public UmPolicyTestBase {
- protected:
- UmEnterpriseDevicePolicyImplTest() : UmPolicyTestBase() {
- policy_ = std::make_unique<EnterpriseDevicePolicyImpl>();
- }
-
- void SetUpDefaultState() override {
- UmPolicyTestBase::SetUpDefaultState();
-
- fake_state_.device_policy_provider()->var_device_policy_is_loaded()->reset(
- new bool(true));
- }
-};
-
-TEST_F(UmEnterpriseDevicePolicyImplTest, KioskAppVersionSet) {
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
-
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- new std::string("1234.5.6"));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kContinue, &Policy::UpdateCheckAllowed, &result);
- EXPECT_EQ(result.target_version_prefix, "1234.5.6");
-}
-
-TEST_F(UmEnterpriseDevicePolicyImplTest, KioskAppVersionUnreadableNoUpdate) {
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
-
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- nullptr);
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
-}
-
-TEST_F(UmEnterpriseDevicePolicyImplTest, KioskAppVersionUnreadableUpdate) {
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
-
- // The real variable returns an empty string after several unsuccessful
- // reading attempts. Fake this by setting it directly to empty string.
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- new std::string(""));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kContinue, &Policy::UpdateCheckAllowed, &result);
- EXPECT_EQ(result.target_version_prefix, "");
-}
-
-TEST_F(UmEnterpriseDevicePolicyImplTest,
- KioskAppVersionUnreadableUpdateWithMinVersion) {
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
-
- // The real variable returns an empty string after several unsuccessful
- // reading attempts. Fake this by setting it directly to empty string.
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- new std::string(""));
- // Update if the minimum version is above the current OS version.
- fake_state_.device_policy_provider()->var_device_minimum_version()->reset(
- new base::Version("2.0.0"));
- fake_state_.system_provider()->var_chromeos_version()->reset(
- new base::Version("1.0.0"));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kContinue, &Policy::UpdateCheckAllowed, &result);
- EXPECT_EQ(result.target_version_prefix, "");
-}
-
-TEST_F(UmEnterpriseDevicePolicyImplTest,
- KioskAppVersionUnreadableNoUpdateWithMinVersion) {
- fake_state_.device_policy_provider()->var_update_disabled()->reset(
- new bool(true));
- fake_state_.device_policy_provider()
- ->var_allow_kiosk_app_control_chrome_version()
- ->reset(new bool(true));
-
- // The real variable returns an empty string after several unsuccessful
- // reading attempts. Fake this by setting it directly to empty string.
- fake_state_.system_provider()->var_kiosk_required_platform_version()->reset(
- new std::string(""));
- // Block update if the minimum version is below the current OS version.
- fake_state_.device_policy_provider()->var_device_minimum_version()->reset(
- new base::Version("1.0.0"));
- fake_state_.system_provider()->var_chromeos_version()->reset(
- new base::Version("2.0.0"));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kAskMeAgainLater, &Policy::UpdateCheckAllowed, &result);
-}
-
-TEST_F(UmEnterpriseDevicePolicyImplTest, ChannelDowngradeBehaviorNoRollback) {
- fake_state_.device_policy_provider()->var_release_channel_delegated()->reset(
- new bool(false));
- fake_state_.device_policy_provider()->var_release_channel()->reset(
- new std::string("stable-channel"));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kContinue, &Policy::UpdateCheckAllowed, &result);
- EXPECT_FALSE(result.rollback_on_channel_downgrade);
-}
-
-TEST_F(UmEnterpriseDevicePolicyImplTest, ChannelDowngradeBehaviorRollback) {
- fake_state_.device_policy_provider()->var_release_channel_delegated()->reset(
- new bool(false));
- fake_state_.device_policy_provider()->var_release_channel()->reset(
- new std::string("stable-channel"));
- fake_state_.device_policy_provider()->var_channel_downgrade_behavior()->reset(
- new ChannelDowngradeBehavior(ChannelDowngradeBehavior::kRollback));
-
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kContinue, &Policy::UpdateCheckAllowed, &result);
- EXPECT_TRUE(result.rollback_on_channel_downgrade);
-}
-
-TEST_F(UmEnterpriseDevicePolicyImplTest, QuickFixBuildToken) {
- fake_state_.device_policy_provider()->var_quick_fix_build_token()->reset(
- new std::string("token"));
- UpdateCheckParams result;
- ExpectPolicyStatus(
- EvalStatus::kContinue, &Policy::UpdateCheckAllowed, &result);
- EXPECT_EQ(result.quick_fix_build_token, "token");
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/enterprise_rollback_policy_impl.cc b/update_manager/enterprise_rollback_policy_impl.cc
deleted file mode 100644
index ab4e38cd..00000000
--- a/update_manager/enterprise_rollback_policy_impl.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// 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/update_manager/enterprise_rollback_policy_impl.h"
-
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-using std::string;
-
-namespace chromeos_update_manager {
-
-EvalStatus EnterpriseRollbackPolicyImpl::UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- string* error,
- ErrorCode* result,
- InstallPlan* install_plan) const {
- if (install_plan && install_plan->is_rollback) {
- LOG(INFO)
- << "Update is enterprise rollback, allowing update to be applied.";
- *result = ErrorCode::kSuccess;
- return EvalStatus::kSucceeded;
- }
- return EvalStatus::kContinue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/enterprise_rollback_policy_impl.h b/update_manager/enterprise_rollback_policy_impl.h
deleted file mode 100644
index bcaf95ec..00000000
--- a/update_manager/enterprise_rollback_policy_impl.h
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// 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_UPDATE_MANAGER_ENTERPRISE_ROLLBACK_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_ENTERPRISE_ROLLBACK_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/common/error_code.h"
-#include "update_engine/payload_consumer/install_plan.h"
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// If the update is an enterprise rollback, this should not block the update
-// to be applied.
-class EnterpriseRollbackPolicyImpl : public PolicyImplBase {
- public:
- EnterpriseRollbackPolicyImpl() = default;
- ~EnterpriseRollbackPolicyImpl() override = default;
-
- // Policy overrides.
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override;
-
- protected:
- std::string PolicyName() const override {
- return "EnterpriseRollbackPolicyImpl";
- }
-
- private:
- EnterpriseRollbackPolicyImpl(const EnterpriseRollbackPolicyImpl&) = delete;
- EnterpriseRollbackPolicyImpl& operator=(const EnterpriseRollbackPolicyImpl&) =
- delete;
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_ENTERPRISE_ROLLBACK_POLICY_IMPL_H_
diff --git a/update_manager/enterprise_rollback_policy_impl_unittest.cc b/update_manager/enterprise_rollback_policy_impl_unittest.cc
deleted file mode 100644
index 5cc5c75e..00000000
--- a/update_manager/enterprise_rollback_policy_impl_unittest.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// 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 <memory>
-
-#include "update_engine/update_manager/enterprise_rollback_policy_impl.h"
-#include "update_engine/update_manager/policy_test_utils.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-
-namespace chromeos_update_manager {
-
-class UmEnterpriseRollbackPolicyImplTest : public UmPolicyTestBase {
- protected:
- UmEnterpriseRollbackPolicyImplTest() {
- policy_ = std::make_unique<EnterpriseRollbackPolicyImpl>();
- }
-};
-
-TEST_F(UmEnterpriseRollbackPolicyImplTest,
- ContinueWhenUpdateIsNotEnterpriseRollback) {
- InstallPlan install_plan{.is_rollback = false};
- ErrorCode result;
- ExpectPolicyStatus(EvalStatus::kContinue,
- &Policy::UpdateCanBeApplied,
- &result,
- &install_plan);
-}
-
-TEST_F(UmEnterpriseRollbackPolicyImplTest,
- SuccessWhenUpdateIsEnterpriseRollback) {
- InstallPlan install_plan{.is_rollback = true};
- ErrorCode result;
- ExpectPolicyStatus(EvalStatus::kSucceeded,
- &Policy::UpdateCanBeApplied,
- &result,
- &install_plan);
- EXPECT_EQ(result, ErrorCode::kSuccess);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/evaluation_context-inl.h b/update_manager/evaluation_context-inl.h
deleted file mode 100644
index 82861fa2..00000000
--- a/update_manager/evaluation_context-inl.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_EVALUATION_CONTEXT_INL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_INL_H_
-
-#include <string>
-
-#include <base/logging.h>
-
-namespace chromeos_update_manager {
-
-template <typename T>
-const T* EvaluationContext::GetValue(Variable<T>* var) {
- if (var == nullptr) {
- LOG(ERROR) << "GetValue received an uninitialized variable.";
- return nullptr;
- }
-
- // Search for the value on the cache first.
- ValueCacheMap::iterator it = value_cache_.find(var);
- if (it != value_cache_.end())
- return reinterpret_cast<const T*>(it->second.value());
-
- // Get the value from the variable if not found on the cache.
- std::string errmsg;
- const T* result =
- var->GetValue(RemainingTime(evaluation_monotonic_deadline_), &errmsg);
- if (result == nullptr && !var->IsMissingOk()) {
- LOG(WARNING) << "Error reading Variable " << var->GetName() << ": \""
- << errmsg << "\"";
- }
- // Cache the value for the next time. The map of CachedValues keeps the
- // ownership of the pointer until the map is destroyed.
- value_cache_.emplace(static_cast<BaseVariable*>(var), BoxedValue(result));
- return result;
-}
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_INL_H_
diff --git a/update_manager/evaluation_context.cc b/update_manager/evaluation_context.cc
deleted file mode 100644
index b86f41cf..00000000
--- a/update_manager/evaluation_context.cc
+++ /dev/null
@@ -1,254 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/evaluation_context.h"
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <utility>
-
-#include <base/bind.h>
-#include <base/json/json_writer.h>
-#include <base/location.h>
-#include <base/strings/string_util.h>
-#include <base/values.h>
-
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-
-using base::Callback;
-using base::Closure;
-using base::Time;
-using base::TimeDelta;
-using brillo::MessageLoop;
-using chromeos_update_engine::SystemState;
-using std::string;
-using std::unique_ptr;
-
-namespace {
-
-// Returns whether |curr_time| surpassed |ref_time|; if not, also checks whether
-// |ref_time| is sooner than the current value of |*reeval_time|, in which case
-// the latter is updated to the former.
-bool IsTimeGreaterThanHelper(Time ref_time, Time curr_time, Time* reeval_time) {
- if (curr_time > ref_time)
- return true;
- // Remember the nearest reference we've checked against in this evaluation.
- if (*reeval_time > ref_time)
- *reeval_time = ref_time;
- return false;
-}
-
-// If |expires| never happens (maximal value), returns the maximal interval;
-// otherwise, returns the difference between |expires| and |curr|.
-TimeDelta GetTimeout(Time curr, Time expires) {
- if (expires.is_max())
- return TimeDelta::Max();
- return expires - curr;
-}
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-EvaluationContext::EvaluationContext(
- TimeDelta evaluation_timeout,
- TimeDelta expiration_timeout,
- unique_ptr<Callback<void(EvaluationContext*)>> unregister_cb)
- : evaluation_timeout_(evaluation_timeout),
- expiration_timeout_(expiration_timeout),
- unregister_cb_(std::move(unregister_cb)),
- weak_ptr_factory_(this) {
- ResetEvaluation();
- ResetExpiration();
-}
-
-EvaluationContext::~EvaluationContext() {
- RemoveObserversAndTimeout();
- if (unregister_cb_.get())
- unregister_cb_->Run(this);
-}
-
-unique_ptr<Closure> EvaluationContext::RemoveObserversAndTimeout() {
- for (auto& it : value_cache_) {
- if (it.first->GetMode() == kVariableModeAsync)
- it.first->RemoveObserver(this);
- }
- MessageLoop::current()->CancelTask(timeout_event_);
- timeout_event_ = MessageLoop::kTaskIdNull;
-
- return std::move(callback_);
-}
-
-TimeDelta EvaluationContext::RemainingTime(Time monotonic_deadline) const {
- if (monotonic_deadline.is_max())
- return TimeDelta::Max();
- TimeDelta remaining =
- monotonic_deadline - SystemState::Get()->clock()->GetMonotonicTime();
- return std::max(remaining, TimeDelta());
-}
-
-Time EvaluationContext::MonotonicDeadline(TimeDelta timeout) {
- return (timeout.is_max()
- ? Time::Max()
- : SystemState::Get()->clock()->GetMonotonicTime() + timeout);
-}
-
-void EvaluationContext::ValueChanged(BaseVariable* var) {
- DLOG(INFO) << "ValueChanged() called for variable " << var->GetName();
- OnValueChangedOrTimeout();
-}
-
-void EvaluationContext::OnTimeout() {
- DLOG(INFO) << "OnTimeout() called due to "
- << (timeout_marks_expiration_ ? "expiration" : "poll interval");
- timeout_event_ = MessageLoop::kTaskIdNull;
- is_expired_ = timeout_marks_expiration_;
- OnValueChangedOrTimeout();
-}
-
-void EvaluationContext::OnValueChangedOrTimeout() {
- // Copy the callback handle locally, allowing it to be reassigned.
- unique_ptr<Closure> callback = RemoveObserversAndTimeout();
-
- if (callback.get())
- callback->Run();
-}
-
-bool EvaluationContext::IsWallclockTimeGreaterThan(Time timestamp) {
- return IsTimeGreaterThanHelper(
- timestamp, evaluation_start_wallclock_, &reevaluation_time_wallclock_);
-}
-
-bool EvaluationContext::IsMonotonicTimeGreaterThan(Time timestamp) {
- return IsTimeGreaterThanHelper(
- timestamp, evaluation_start_monotonic_, &reevaluation_time_monotonic_);
-}
-
-void EvaluationContext::ResetEvaluation() {
- const auto* clock = SystemState::Get()->clock();
- evaluation_start_wallclock_ = clock->GetWallclockTime();
- evaluation_start_monotonic_ = clock->GetMonotonicTime();
- reevaluation_time_wallclock_ = Time::Max();
- reevaluation_time_monotonic_ = Time::Max();
- evaluation_monotonic_deadline_ = MonotonicDeadline(evaluation_timeout_);
-
- // Remove the cached values of non-const variables
- for (auto it = value_cache_.begin(); it != value_cache_.end();) {
- if (it->first->GetMode() == kVariableModeConst) {
- ++it;
- } else {
- it = value_cache_.erase(it);
- }
- }
-}
-
-void EvaluationContext::ResetExpiration() {
- expiration_monotonic_deadline_ = MonotonicDeadline(expiration_timeout_);
- is_expired_ = false;
-}
-
-bool EvaluationContext::RunOnValueChangeOrTimeout(Closure callback) {
- // Check that the method was not called more than once.
- if (callback_.get()) {
- LOG(ERROR) << "RunOnValueChangeOrTimeout called more than once.";
- return false;
- }
-
- // Check that the context did not yet expire.
- if (is_expired()) {
- LOG(ERROR) << "RunOnValueChangeOrTimeout called on an expired context.";
- return false;
- }
-
- // Handle reevaluation due to a Is{Wallclock,Monotonic}TimeGreaterThan(). We
- // choose the smaller of the differences between evaluation start time and
- // reevaluation time among the wallclock and monotonic scales.
- TimeDelta timeout = std::min(
- GetTimeout(evaluation_start_wallclock_, reevaluation_time_wallclock_),
- GetTimeout(evaluation_start_monotonic_, reevaluation_time_monotonic_));
-
- // Handle reevaluation due to async or poll variables.
- bool waiting_for_value_change = false;
- for (auto& it : value_cache_) {
- switch (it.first->GetMode()) {
- case kVariableModeAsync:
- DLOG(INFO) << "Waiting for value on " << it.first->GetName();
- it.first->AddObserver(this);
- waiting_for_value_change = true;
- break;
- case kVariableModePoll:
- timeout = std::min(timeout, it.first->GetPollInterval());
- break;
- case kVariableModeConst:
- // Ignored.
- break;
- }
- }
-
- // Check if the re-evaluation is actually being scheduled. If there are no
- // events waited for, this function should return false.
- if (!waiting_for_value_change && timeout.is_max())
- return false;
-
- // Ensure that we take into account the expiration timeout.
- TimeDelta expiration = RemainingTime(expiration_monotonic_deadline_);
- timeout_marks_expiration_ = expiration < timeout;
- if (timeout_marks_expiration_)
- timeout = expiration;
-
- // Store the reevaluation callback.
- callback_.reset(new Closure(callback));
-
- // Schedule a timeout event, if one is set.
- if (!timeout.is_max()) {
- DLOG(INFO) << "Waiting for timeout in "
- << chromeos_update_engine::utils::FormatTimeDelta(timeout);
- timeout_event_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&EvaluationContext::OnTimeout,
- weak_ptr_factory_.GetWeakPtr()),
- timeout);
- }
-
- return true;
-}
-
-string EvaluationContext::DumpContext() const {
- auto variables = std::make_unique<base::DictionaryValue>();
- for (auto& it : value_cache_) {
- variables->SetString(it.first->GetName(), it.second.ToString());
- }
-
- base::DictionaryValue value;
- value.Set("variables", std::move(variables));
- value.SetString(
- "evaluation_start_wallclock",
- chromeos_update_engine::utils::ToString(evaluation_start_wallclock_));
- value.SetString(
- "evaluation_start_monotonic",
- chromeos_update_engine::utils::ToString(evaluation_start_monotonic_));
-
- string json_str;
- base::JSONWriter::WriteWithOptions(
- value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &json_str);
- base::TrimWhitespaceASCII(json_str, base::TRIM_TRAILING, &json_str);
-
- return json_str;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/evaluation_context.h b/update_manager/evaluation_context.h
deleted file mode 100644
index 3460f2af..00000000
--- a/update_manager/evaluation_context.h
+++ /dev/null
@@ -1,213 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_EVALUATION_CONTEXT_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_
-
-#include <map>
-#include <memory>
-#include <string>
-
-#include <base/bind.h>
-#include <base/callback.h>
-#include <base/memory/weak_ptr.h>
-#include <base/time/time.h>
-#include <brillo/message_loops/message_loop.h>
-
-#include "update_engine/update_manager/boxed_value.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// The EvaluationContext class is the interface between a policy implementation
-// and the state. The EvaluationContext tracks the variables used by a policy
-// request and caches the returned values, owning those cached values.
-// The same EvaluationContext should be re-used for all the evaluations of the
-// same policy request (an AsyncPolicyRequest might involve several
-// re-evaluations). Each evaluation of the EvaluationContext is run at a given
-// point in time, which is used as a reference for the evaluation timeout and
-// the time based queries of the policy, such as
-// Is{Wallclock,Monotonic}TimeGreaterThan().
-//
-// Example:
-//
-// auto ec = std::make_shared<EvaluationContext>(...);
-//
-// ...
-// // The following call to ResetEvaluation() is optional. Use it to reset the
-// // evaluation time if the EvaluationContext isn't used right after its
-// // construction.
-// ec->ResetEvaluation();
-// EvalStatus status = policy->SomeMethod(ec, state, &result, args...);
-//
-// ...
-// // Run a closure when any of the used async variables changes its value or
-// // the timeout for re-query the values happens again.
-// ec->RunOnValueChangeOrTimeout(closure);
-// // If the provided |closure| wants to re-evaluate the policy, it should
-// // call ec->ResetEvaluation() to start a new evaluation.
-//
-class EvaluationContext : private BaseVariable::ObserverInterface {
- public:
- EvaluationContext(
- base::TimeDelta evaluation_timeout,
- base::TimeDelta expiration_timeout,
- std::unique_ptr<base::Callback<void(EvaluationContext*)>> unregister_cb);
- explicit EvaluationContext(base::TimeDelta evaluation_timeout)
- : EvaluationContext(
- evaluation_timeout,
- base::TimeDelta::Max(),
- std::unique_ptr<base::Callback<void(EvaluationContext*)>>()) {}
- ~EvaluationContext();
-
- // Returns a pointer to the value returned by the passed variable |var|. The
- // EvaluationContext instance keeps the ownership of the returned object. The
- // returned object is valid during the life of the evaluation, even if the
- // passed Variable changes it.
- //
- // In case of error, a null value is returned.
- template <typename T>
- const T* GetValue(Variable<T>* var);
-
- // Returns whether the evaluation time has surpassed |timestamp|, on either
- // the ClockInterface::GetWallclockTime() or
- // ClockInterface::GetMonotonicTime() scales, respectively.
- bool IsWallclockTimeGreaterThan(base::Time timestamp);
- bool IsMonotonicTimeGreaterThan(base::Time timestamp);
-
- // Returns whether the evaluation context has expired.
- bool is_expired() const { return is_expired_; }
-
- // TODO(deymo): Move the following methods to an interface only visible by the
- // UpdateManager class and not the policy implementations.
-
- // Resets the EvaluationContext to its initial state removing all the
- // non-const cached variables and re-setting the evaluation time. This should
- // be called right before any new evaluation starts.
- void ResetEvaluation();
-
- // Clears the expiration status of the EvaluationContext and resets its
- // expiration timeout based on |expiration_timeout_|. This should be called if
- // expiration occurred, prior to re-evaluating the policy.
- void ResetExpiration();
-
- // Schedules the passed |callback| closure to be called when a cached
- // variable changes its value, a polling interval passes, or the context
- // expiration occurs. If none of these events can happen, for example if
- // there's no cached variable, this method returns false.
- //
- // Right before the passed closure is called the EvaluationContext is
- // reset, removing all the non-const cached values.
- bool RunOnValueChangeOrTimeout(base::Closure callback);
-
- // Returns a textual representation of the evaluation context,
- // including the variables and their values. This is intended only
- // to help with debugging and the format may change in the future.
- std::string DumpContext() const;
-
- // Removes all the Observers callbacks and timeout events scheduled by
- // RunOnValueChangeOrTimeout(). Also releases and returns the closure
- // associated with these events. This method is idempotent.
- std::unique_ptr<base::Closure> RemoveObserversAndTimeout();
-
- private:
- friend class UmEvaluationContextTest;
-
- // BaseVariable::ObserverInterface override.
- void ValueChanged(BaseVariable* var) override;
-
- // Called from the main loop when a scheduled timeout has passed.
- void OnTimeout();
-
- // Removes the observers from the used Variables and cancels the timeout,
- // then executes the scheduled callback.
- void OnValueChangedOrTimeout();
-
- // If |monotonic_deadline| is not Time::Max(), returns the remaining time
- // until it is reached, or zero if it has passed. Otherwise, returns
- // TimeDelta::Max().
- base::TimeDelta RemainingTime(base::Time monotonic_deadline) const;
-
- // Returns a monotonic clock timestamp at which |timeout| will have elapsed
- // since the current time.
- base::Time MonotonicDeadline(base::TimeDelta timeout);
-
- // A map to hold the cached values for every variable.
- typedef std::map<BaseVariable*, BoxedValue> ValueCacheMap;
-
- // The cached values of the called Variables.
- ValueCacheMap value_cache_;
-
- // A callback used for triggering re-evaluation upon a value change or poll
- // timeout, or notifying about the evaluation context expiration. It is up to
- // the caller to determine whether or not expiration occurred via
- // is_expired().
- std::unique_ptr<base::Closure> callback_;
-
- // The TaskId returned by the message loop identifying the timeout callback.
- // Used for canceling the timeout callback.
- brillo::MessageLoop::TaskId timeout_event_ = brillo::MessageLoop::kTaskIdNull;
-
- // Whether a timeout event firing marks the expiration of the evaluation
- // context.
- bool timeout_marks_expiration_;
-
- // Whether the evaluation context has indeed expired.
- bool is_expired_ = false;
-
- // The timestamps when the evaluation of this EvaluationContext started,
- // corresponding to ClockInterface::GetWallclockTime() and
- // ClockInterface::GetMonotonicTime(), respectively. These values are reset
- // every time ResetEvaluation() is called.
- base::Time evaluation_start_wallclock_;
- base::Time evaluation_start_monotonic_;
-
- // The timestamps when a reevaluation should be triggered due to various
- // expected value changes, corresponding to ClockInterface::GetWallclockTime()
- // and ClockInterface::GetMonotonicTIme(), respectively. These timestamps are
- // greater or equal to corresponding |evaluation_start_{wallclock,monotonic}_|
- // counterparts since they are in the future; however, they may be smaller
- // than the current corresponding times during the course of evaluation.
- base::Time reevaluation_time_wallclock_;
- base::Time reevaluation_time_monotonic_;
-
- // The timeout of an evaluation.
- const base::TimeDelta evaluation_timeout_;
-
- // The timestamp in the ClockInterface::GetMonotonicTime() scale at which the
- // current evaluation should finish.
- base::Time evaluation_monotonic_deadline_;
-
- // The expiration timeout of the evaluation context.
- const base::TimeDelta expiration_timeout_;
-
- // The monotonic clock deadline at which expiration occurs.
- base::Time expiration_monotonic_deadline_;
-
- // A callback for unregistering the context upon destruction.
- std::unique_ptr<base::Callback<void(EvaluationContext*)>> unregister_cb_;
-
- base::WeakPtrFactory<EvaluationContext> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(EvaluationContext);
-};
-
-} // namespace chromeos_update_manager
-
-// Include the implementation of the template methods.
-#include "update_engine/update_manager/evaluation_context-inl.h"
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_EVALUATION_CONTEXT_H_
diff --git a/update_manager/evaluation_context_unittest.cc b/update_manager/evaluation_context_unittest.cc
deleted file mode 100644
index fdb408b8..00000000
--- a/update_manager/evaluation_context_unittest.cc
+++ /dev/null
@@ -1,496 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/evaluation_context.h"
-
-#include <memory>
-#include <string>
-
-#include <base/bind.h>
-#include <base/bind_helpers.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/fake_clock.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/fake_variable.h"
-#include "update_engine/update_manager/generic_variables.h"
-#include "update_engine/update_manager/mock_variable.h"
-#include "update_engine/update_manager/umtest_utils.h"
-
-using base::Bind;
-using base::Closure;
-using base::Time;
-using base::TimeDelta;
-using brillo::MessageLoop;
-using brillo::MessageLoopRunMaxIterations;
-using brillo::MessageLoopRunUntil;
-using chromeos_update_engine::FakeClock;
-using chromeos_update_engine::FakeSystemState;
-using std::shared_ptr;
-using std::string;
-using std::unique_ptr;
-using testing::_;
-using testing::Return;
-using testing::StrictMock;
-
-namespace chromeos_update_manager {
-
-namespace {
-
-// Sets the value of the passed pointer to true.
-void SetTrue(bool* value) {
- *value = true;
-}
-
-bool GetBoolean(bool* value) {
- return *value;
-}
-
-template <typename T>
-void ReadVar(shared_ptr<EvaluationContext> ec, Variable<T>* var) {
- ec->GetValue(var);
-}
-
-// Runs |evaluation|; if the value pointed by |count_p| is greater than zero,
-// decrement it and schedule a reevaluation; otherwise, writes true to |done_p|.
-void EvaluateRepeatedly(Closure evaluation,
- shared_ptr<EvaluationContext> ec,
- int* count_p,
- bool* done_p) {
- evaluation.Run();
-
- // Schedule reevaluation if needed.
- if (*count_p > 0) {
- Closure closure = Bind(EvaluateRepeatedly, evaluation, ec, count_p, done_p);
- ASSERT_TRUE(ec->RunOnValueChangeOrTimeout(closure))
- << "Failed to schedule reevaluation, count_p=" << *count_p;
- (*count_p)--;
- } else {
- *done_p = true;
- }
-}
-
-} // namespace
-
-class UmEvaluationContextTest : public ::testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
- fake_clock_ = FakeSystemState::Get()->fake_clock();
- loop_.SetAsCurrent();
- // Apr 22, 2009 19:25:00 UTC (this is a random reference point).
- fake_clock_->SetMonotonicTime(Time::FromTimeT(1240428300));
- // Mar 2, 2006 1:23:45 UTC.
- fake_clock_->SetWallclockTime(Time::FromTimeT(1141262625));
- eval_ctx_.reset(new EvaluationContext(
- default_timeout_,
- default_timeout_,
- unique_ptr<base::Callback<void(EvaluationContext*)>>(nullptr)));
- }
-
- void TearDown() override {
- // Ensure that the evaluation context did not leak and is actually being
- // destroyed.
- if (eval_ctx_) {
- base::WeakPtr<EvaluationContext> eval_ctx_weak_alias =
- eval_ctx_->weak_ptr_factory_.GetWeakPtr();
- ASSERT_NE(nullptr, eval_ctx_weak_alias.get());
- eval_ctx_ = nullptr;
- EXPECT_EQ(nullptr, eval_ctx_weak_alias.get())
- << "The evaluation context was not destroyed! This is likely a bug "
- "in how the test was written, look for leaking handles to the EC, "
- "possibly through closure objects.";
- }
-
- // Check that the evaluation context removed all the observers.
- EXPECT_TRUE(fake_int_var_.observer_list_.empty());
- EXPECT_TRUE(fake_async_var_.observer_list_.empty());
- EXPECT_TRUE(fake_const_var_.observer_list_.empty());
- EXPECT_TRUE(fake_poll_var_.observer_list_.empty());
-
- EXPECT_FALSE(loop_.PendingTasks());
- }
-
- TimeDelta default_timeout_ = TimeDelta::FromSeconds(5);
-
- brillo::FakeMessageLoop loop_{nullptr};
- FakeClock* fake_clock_;
- shared_ptr<EvaluationContext> eval_ctx_;
-
- // FakeVariables used for testing the EvaluationContext. These are required
- // here to prevent them from going away *before* the EvaluationContext under
- // test does, which keeps a reference to them.
- FakeVariable<bool> fail_var_ = {"fail_var", kVariableModePoll};
- FakeVariable<int> fake_int_var_ = {"fake_int", kVariableModePoll};
- FakeVariable<string> fake_async_var_ = {"fake_async", kVariableModeAsync};
- FakeVariable<string> fake_const_var_ = {"fake_const", kVariableModeConst};
- FakeVariable<string> fake_poll_var_ = {"fake_poll",
- TimeDelta::FromSeconds(1)};
- StrictMock<MockVariable<string>> mock_var_async_{"mock_var_async",
- kVariableModeAsync};
- StrictMock<MockVariable<string>> mock_var_poll_{"mock_var_poll",
- kVariableModePoll};
-};
-
-TEST_F(UmEvaluationContextTest, GetValueFails) {
- // FakeVariable is initialized as returning null.
- EXPECT_EQ(nullptr, eval_ctx_->GetValue(&fake_int_var_));
-}
-
-TEST_F(UmEvaluationContextTest, GetValueFailsWithInvalidVar) {
- EXPECT_EQ(nullptr, eval_ctx_->GetValue(static_cast<Variable<int>*>(nullptr)));
-}
-
-TEST_F(UmEvaluationContextTest, GetValueReturns) {
- const int* p_fake_int;
-
- fake_int_var_.reset(new int(42));
- p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
- ASSERT_NE(nullptr, p_fake_int);
- EXPECT_EQ(42, *p_fake_int);
-}
-
-TEST_F(UmEvaluationContextTest, GetValueCached) {
- const int* p_fake_int;
-
- fake_int_var_.reset(new int(42));
- p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
-
- // Check that if the variable changes, the EvaluationContext keeps returning
- // the cached value.
- fake_int_var_.reset(new int(5));
-
- p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
- ASSERT_NE(nullptr, p_fake_int);
- EXPECT_EQ(42, *p_fake_int);
-}
-
-TEST_F(UmEvaluationContextTest, GetValueCachesNull) {
- const int* p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
- EXPECT_EQ(nullptr, p_fake_int);
-
- fake_int_var_.reset(new int(42));
- // A second attempt to read the variable should not work because this
- // EvaluationContext already got a null value.
- p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
- EXPECT_EQ(nullptr, p_fake_int);
-}
-
-TEST_F(UmEvaluationContextTest, GetValueMixedTypes) {
- const int* p_fake_int;
- const string* p_fake_string;
-
- fake_int_var_.reset(new int(42));
- fake_poll_var_.reset(new string("Hello world!"));
- // Check that the EvaluationContext can handle multiple Variable types. This
- // is mostly a compile-time check due to the template nature of this method.
- p_fake_int = eval_ctx_->GetValue(&fake_int_var_);
- p_fake_string = eval_ctx_->GetValue(&fake_poll_var_);
-
- ASSERT_NE(nullptr, p_fake_int);
- EXPECT_EQ(42, *p_fake_int);
-
- ASSERT_NE(nullptr, p_fake_string);
- EXPECT_EQ("Hello world!", *p_fake_string);
-}
-
-// Test that we don't schedule an event if there's no variable to wait for.
-TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithoutVariables) {
- fake_const_var_.reset(new string("Hello world!"));
- EXPECT_EQ(*eval_ctx_->GetValue(&fake_const_var_), "Hello world!");
-
- EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
-}
-
-// Test that reevaluation occurs when an async variable it depends on changes.
-TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutWithVariables) {
- fake_async_var_.reset(new string("Async value"));
- eval_ctx_->GetValue(&fake_async_var_);
-
- bool value = false;
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
- // Check that the scheduled callback isn't run until we signal a ValueChaged.
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_FALSE(value);
-
- fake_async_var_.NotifyValueChanged();
- EXPECT_FALSE(value);
- // Ensure that the scheduled callback isn't run until we are back on the main
- // loop.
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_TRUE(value);
-}
-
-// Test that we don't re-schedule the events if we are attending one.
-TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutCalledTwice) {
- fake_async_var_.reset(new string("Async value"));
- eval_ctx_->GetValue(&fake_async_var_);
-
- bool value = false;
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
- EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
-
- // The scheduled event should still work.
- fake_async_var_.NotifyValueChanged();
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_TRUE(value);
-}
-
-// Test that reevaluation occurs when a polling timeout fires.
-TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutRunsFromTimeout) {
- fake_poll_var_.reset(new string("Polled value"));
- eval_ctx_->GetValue(&fake_poll_var_);
-
- bool value = false;
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
- // Check that the scheduled callback isn't run until the timeout occurs.
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- EXPECT_FALSE(value);
- MessageLoopRunUntil(MessageLoop::current(),
- TimeDelta::FromSeconds(10),
- Bind(&GetBoolean, &value));
- EXPECT_TRUE(value);
-}
-
-// Test that callback is called when evaluation context expires, and that it
-// cannot be used again unless the expiration deadline is reset.
-TEST_F(UmEvaluationContextTest, RunOnValueChangeOrTimeoutExpires) {
- fake_async_var_.reset(new string("Async value"));
- eval_ctx_->GetValue(&fake_async_var_);
-
- bool value = false;
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
- // Check that the scheduled callback isn't run until the timeout occurs.
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- EXPECT_FALSE(value);
- MessageLoopRunUntil(MessageLoop::current(),
- TimeDelta::FromSeconds(10),
- Bind(&GetBoolean, &value));
- EXPECT_TRUE(value);
-
- // Ensure that we cannot reschedule an evaluation.
- EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
-
- // Ensure that we can reschedule an evaluation after resetting expiration.
- eval_ctx_->ResetExpiration();
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
-}
-
-// Test that we clear the events when destroying the EvaluationContext.
-TEST_F(UmEvaluationContextTest, RemoveObserversAndTimeoutTest) {
- fake_async_var_.reset(new string("Async value"));
- eval_ctx_->GetValue(&fake_async_var_);
-
- bool value = false;
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
- eval_ctx_ = nullptr;
-
- // This should not trigger the callback since the EvaluationContext waiting
- // for it is gone, and it should have remove all its observers.
- fake_async_var_.NotifyValueChanged();
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_FALSE(value);
-}
-
-// Scheduling two reevaluations from the callback should succeed.
-TEST_F(UmEvaluationContextTest,
- RunOnValueChangeOrTimeoutReevaluatesRepeatedly) {
- fake_poll_var_.reset(new string("Polled value"));
- Closure evaluation = Bind(ReadVar<string>, eval_ctx_, &fake_poll_var_);
- int num_reevaluations = 2;
- bool done = false;
-
- // Run the evaluation once.
- evaluation.Run();
-
- // Schedule repeated reevaluations.
- Closure closure = Bind(
- EvaluateRepeatedly, evaluation, eval_ctx_, &num_reevaluations, &done);
- ASSERT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(closure));
- MessageLoopRunUntil(MessageLoop::current(),
- TimeDelta::FromSeconds(10),
- Bind(&GetBoolean, &done));
- EXPECT_EQ(0, num_reevaluations);
-}
-
-// Test that we can delete the EvaluationContext while having pending events.
-TEST_F(UmEvaluationContextTest, ObjectDeletedWithPendingEventsTest) {
- fake_async_var_.reset(new string("Async value"));
- fake_poll_var_.reset(new string("Polled value"));
- eval_ctx_->GetValue(&fake_async_var_);
- eval_ctx_->GetValue(&fake_poll_var_);
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
- // TearDown() checks for leaked observers on this async_variable, which means
- // that our object is still alive after removing its reference.
-}
-
-// Test that timed events fired after removal of the EvaluationContext don't
-// crash.
-TEST_F(UmEvaluationContextTest, TimeoutEventAfterDeleteTest) {
- FakeVariable<string> fake_short_poll_var = {"fake_short_poll",
- TimeDelta::FromSeconds(1)};
- fake_short_poll_var.reset(new string("Polled value"));
- eval_ctx_->GetValue(&fake_short_poll_var);
- bool value = false;
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(Bind(&SetTrue, &value)));
- // Remove the last reference to the EvaluationContext and run the loop for
- // 10 seconds to give time to the main loop to trigger the timeout Event (of 1
- // second). Our callback should not be called because the EvaluationContext
- // was removed before the timeout event is attended.
- eval_ctx_ = nullptr;
- MessageLoopRunUntil(MessageLoop::current(),
- TimeDelta::FromSeconds(10),
- Bind(&GetBoolean, &value));
- EXPECT_FALSE(value);
-}
-
-TEST_F(UmEvaluationContextTest, DefaultTimeout) {
- // Test that the evaluation timeout calculation uses the default timeout on
- // setup.
- EXPECT_CALL(mock_var_async_, GetValue(default_timeout_, _))
- .WillOnce(Return(nullptr));
- EXPECT_EQ(nullptr, eval_ctx_->GetValue(&mock_var_async_));
-}
-
-TEST_F(UmEvaluationContextTest, TimeoutUpdatesWithMonotonicTime) {
- fake_clock_->SetMonotonicTime(fake_clock_->GetMonotonicTime() +
- TimeDelta::FromSeconds(1));
-
- TimeDelta timeout = default_timeout_ - TimeDelta::FromSeconds(1);
-
- EXPECT_CALL(mock_var_async_, GetValue(timeout, _)).WillOnce(Return(nullptr));
- EXPECT_EQ(nullptr, eval_ctx_->GetValue(&mock_var_async_));
-}
-
-TEST_F(UmEvaluationContextTest, ResetEvaluationResetsTimesWallclock) {
- Time cur_time = fake_clock_->GetWallclockTime();
- // Advance the time on the clock but don't call ResetEvaluation yet.
- fake_clock_->SetWallclockTime(cur_time + TimeDelta::FromSeconds(4));
-
- EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time -
- TimeDelta::FromSeconds(1)));
- EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time));
- EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan(
- cur_time + TimeDelta::FromSeconds(1)));
- // Call ResetEvaluation now, which should use the new evaluation time.
- eval_ctx_->ResetEvaluation();
-
- cur_time = fake_clock_->GetWallclockTime();
- EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time -
- TimeDelta::FromSeconds(1)));
- EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan(cur_time));
- EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan(
- cur_time + TimeDelta::FromSeconds(1)));
-}
-
-TEST_F(UmEvaluationContextTest, ResetEvaluationResetsTimesMonotonic) {
- Time cur_time = fake_clock_->GetMonotonicTime();
- // Advance the time on the clock but don't call ResetEvaluation yet.
- fake_clock_->SetMonotonicTime(cur_time + TimeDelta::FromSeconds(4));
-
- EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time -
- TimeDelta::FromSeconds(1)));
- EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time));
- EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan(
- cur_time + TimeDelta::FromSeconds(1)));
- // Call ResetEvaluation now, which should use the new evaluation time.
- eval_ctx_->ResetEvaluation();
-
- cur_time = fake_clock_->GetMonotonicTime();
- EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time -
- TimeDelta::FromSeconds(1)));
- EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan(cur_time));
- EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan(
- cur_time + TimeDelta::FromSeconds(1)));
-}
-
-TEST_F(UmEvaluationContextTest,
- IsWallclockTimeGreaterThanSignalsTriggerReevaluation) {
- EXPECT_FALSE(eval_ctx_->IsWallclockTimeGreaterThan(
- fake_clock_->GetWallclockTime() + TimeDelta::FromSeconds(1)));
-
- // The "false" from IsWallclockTimeGreaterThan means that's not that timestamp
- // yet, so this should schedule a callback for when that happens.
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
-}
-
-TEST_F(UmEvaluationContextTest,
- IsMonotonicTimeGreaterThanSignalsTriggerReevaluation) {
- EXPECT_FALSE(eval_ctx_->IsMonotonicTimeGreaterThan(
- fake_clock_->GetMonotonicTime() + TimeDelta::FromSeconds(1)));
-
- // The "false" from IsMonotonicTimeGreaterThan means that's not that timestamp
- // yet, so this should schedule a callback for when that happens.
- EXPECT_TRUE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
-}
-
-TEST_F(UmEvaluationContextTest,
- IsWallclockTimeGreaterThanDoesntRecordPastTimestamps) {
- // IsWallclockTimeGreaterThan() should ignore timestamps on the past for
- // reevaluation.
- EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan(
- fake_clock_->GetWallclockTime() - TimeDelta::FromSeconds(20)));
- EXPECT_TRUE(eval_ctx_->IsWallclockTimeGreaterThan(
- fake_clock_->GetWallclockTime() - TimeDelta::FromSeconds(1)));
-
- // Callback should not be scheduled.
- EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
-}
-
-TEST_F(UmEvaluationContextTest,
- IsMonotonicTimeGreaterThanDoesntRecordPastTimestamps) {
- // IsMonotonicTimeGreaterThan() should ignore timestamps on the past for
- // reevaluation.
- EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan(
- fake_clock_->GetMonotonicTime() - TimeDelta::FromSeconds(20)));
- EXPECT_TRUE(eval_ctx_->IsMonotonicTimeGreaterThan(
- fake_clock_->GetMonotonicTime() - TimeDelta::FromSeconds(1)));
-
- // Callback should not be scheduled.
- EXPECT_FALSE(eval_ctx_->RunOnValueChangeOrTimeout(base::DoNothing()));
-}
-
-TEST_F(UmEvaluationContextTest, DumpContext) {
- // |fail_var_| yield "(no value)" since it is unset.
- eval_ctx_->GetValue(&fail_var_);
-
- // Check that this is included.
- fake_int_var_.reset(new int(42));
- eval_ctx_->GetValue(&fake_int_var_);
-
- // Check that double-quotes are escaped properly.
- fake_poll_var_.reset(new string("Hello \"world\"!"));
- eval_ctx_->GetValue(&fake_poll_var_);
-
- // Note that the variables are printed in alphabetical order. Also
- // see UmEvaluationContextText::SetUp() where the values used for
- // |evaluation_start_{monotonic,wallclock| are set.
- EXPECT_EQ(
- "{\n"
- " \"evaluation_start_monotonic\": \"4/22/2009 19:25:00 GMT\",\n"
- " \"evaluation_start_wallclock\": \"3/2/2006 1:23:45 GMT\",\n"
- " \"variables\": {\n"
- " \"fail_var\": \"(no value)\",\n"
- " \"fake_int\": \"42\",\n"
- " \"fake_poll\": \"Hello \\\"world\\\"!\"\n"
- " }\n"
- "}",
- eval_ctx_->DumpContext());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/fake_config_provider.h b/update_manager/fake_config_provider.h
deleted file mode 100644
index 7e6c35b3..00000000
--- a/update_manager/fake_config_provider.h
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_CONFIG_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_CONFIG_PROVIDER_H_
-
-#include "update_engine/update_manager/config_provider.h"
-#include "update_engine/update_manager/fake_variable.h"
-
-namespace chromeos_update_manager {
-
-// Fake implementation of the ConfigProvider base class.
-class FakeConfigProvider : public ConfigProvider {
- public:
- FakeConfigProvider() {}
-
- FakeVariable<bool>* var_is_oobe_enabled() override {
- return &var_is_oobe_enabled_;
- }
-
- private:
- FakeVariable<bool> var_is_oobe_enabled_{"is_oobe_enabled",
- kVariableModeConst};
-
- DISALLOW_COPY_AND_ASSIGN(FakeConfigProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_CONFIG_PROVIDER_H_
diff --git a/update_manager/fake_device_policy_provider.h b/update_manager/fake_device_policy_provider.h
deleted file mode 100644
index 762bfc51..00000000
--- a/update_manager/fake_device_policy_provider.h
+++ /dev/null
@@ -1,154 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
-
-#include <set>
-#include <string>
-
-#include "update_engine/update_manager/device_policy_provider.h"
-#include "update_engine/update_manager/fake_variable.h"
-
-namespace chromeos_update_manager {
-
-// Fake implementation of the DevicePolicyProvider base class.
-class FakeDevicePolicyProvider : public DevicePolicyProvider {
- public:
- FakeDevicePolicyProvider() {}
-
- FakeVariable<bool>* var_device_policy_is_loaded() override {
- return &var_device_policy_is_loaded_;
- }
-
- FakeVariable<std::string>* var_release_channel() override {
- return &var_release_channel_;
- }
-
- FakeVariable<bool>* var_release_channel_delegated() override {
- 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_;
- }
-
- FakeVariable<std::string>* var_target_version_prefix() override {
- return &var_target_version_prefix_;
- }
-
- FakeVariable<RollbackToTargetVersion>* var_rollback_to_target_version()
- override {
- return &var_rollback_to_target_version_;
- }
-
- FakeVariable<int>* var_rollback_allowed_milestones() override {
- return &var_rollback_allowed_milestones_;
- }
-
- FakeVariable<base::TimeDelta>* var_scatter_factor() override {
- return &var_scatter_factor_;
- }
-
- FakeVariable<std::set<chromeos_update_engine::ConnectionType>>*
- var_allowed_connection_types_for_update() override {
- return &var_allowed_connection_types_for_update_;
- }
-
- FakeVariable<bool>* var_has_owner() override { return &var_has_owner_; }
-
- FakeVariable<bool>* var_http_downloads_enabled() override {
- return &var_http_downloads_enabled_;
- }
-
- FakeVariable<bool>* var_au_p2p_enabled() override {
- return &var_au_p2p_enabled_;
- }
-
- FakeVariable<bool>* var_allow_kiosk_app_control_chrome_version() override {
- return &var_allow_kiosk_app_control_chrome_version_;
- }
-
- FakeVariable<std::string>* var_auto_launched_kiosk_app_id() override {
- return &var_auto_launched_kiosk_app_id_;
- }
-
- FakeVariable<WeeklyTimeIntervalVector>* var_disallowed_time_intervals()
- override {
- 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_;
- }
-
- FakeVariable<std::string>* var_quick_fix_build_token() override {
- return &var_quick_fix_build_token_;
- }
-
- private:
- FakeVariable<bool> var_device_policy_is_loaded_{"policy_is_loaded",
- kVariableModePoll};
- FakeVariable<std::string> var_release_channel_{"release_channel",
- 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};
- FakeVariable<RollbackToTargetVersion> var_rollback_to_target_version_{
- "rollback_to_target_version", kVariableModePoll};
- FakeVariable<int> var_rollback_allowed_milestones_{
- "rollback_allowed_milestones", kVariableModePoll};
- FakeVariable<base::TimeDelta> var_scatter_factor_{"scatter_factor",
- kVariableModePoll};
- FakeVariable<std::set<chromeos_update_engine::ConnectionType>>
- var_allowed_connection_types_for_update_{
- "allowed_connection_types_for_update", kVariableModePoll};
- FakeVariable<bool> var_has_owner_{"owner", kVariableModePoll};
- FakeVariable<bool> var_http_downloads_enabled_{"http_downloads_enabled",
- kVariableModePoll};
- FakeVariable<bool> var_au_p2p_enabled_{"au_p2p_enabled", kVariableModePoll};
- FakeVariable<bool> var_allow_kiosk_app_control_chrome_version_{
- "allow_kiosk_app_control_chrome_version", kVariableModePoll};
- FakeVariable<std::string> var_auto_launched_kiosk_app_id_{
- "auto_launched_kiosk_app_id", kVariableModePoll};
- FakeVariable<WeeklyTimeIntervalVector> var_disallowed_time_intervals_{
- "disallowed_time_intervals", kVariableModeAsync};
- FakeVariable<ChannelDowngradeBehavior> var_channel_downgrade_behavior_{
- "channel_downgrade_behavior", kVariableModePoll};
- FakeVariable<base::Version> var_device_minimum_version_{
- "device_minimum_version", kVariableModePoll};
- FakeVariable<std::string> var_quick_fix_build_token_{"quick_fix_build_token",
- kVariableModePoll};
-
- DISALLOW_COPY_AND_ASSIGN(FakeDevicePolicyProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_DEVICE_POLICY_PROVIDER_H_
diff --git a/update_manager/fake_random_provider.h b/update_manager/fake_random_provider.h
deleted file mode 100644
index 643a194a..00000000
--- a/update_manager/fake_random_provider.h
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_RANDOM_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_RANDOM_PROVIDER_H_
-
-#include "update_engine/update_manager/fake_variable.h"
-#include "update_engine/update_manager/random_provider.h"
-
-namespace chromeos_update_manager {
-
-// Fake implementation of the RandomProvider base class.
-class FakeRandomProvider : public RandomProvider {
- public:
- FakeRandomProvider() {}
-
- FakeVariable<uint64_t>* var_seed() override { return &var_seed_; }
-
- private:
- FakeVariable<uint64_t> var_seed_{"seed", kVariableModePoll};
-
- DISALLOW_COPY_AND_ASSIGN(FakeRandomProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_RANDOM_PROVIDER_H_
diff --git a/update_manager/fake_shill_provider.h b/update_manager/fake_shill_provider.h
deleted file mode 100644
index 7a23507f..00000000
--- a/update_manager/fake_shill_provider.h
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_SHILL_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SHILL_PROVIDER_H_
-
-#include "update_engine/update_manager/fake_variable.h"
-#include "update_engine/update_manager/shill_provider.h"
-
-namespace chromeos_update_manager {
-
-// Fake implementation of the ShillProvider base class.
-class FakeShillProvider : public ShillProvider {
- public:
- FakeShillProvider() {}
-
- FakeVariable<bool>* var_is_connected() override { return &var_is_connected_; }
-
- FakeVariable<chromeos_update_engine::ConnectionType>* var_conn_type()
- override {
- return &var_conn_type_;
- }
-
- FakeVariable<chromeos_update_engine::ConnectionTethering>*
- var_conn_tethering() override {
- return &var_conn_tethering_;
- }
-
- FakeVariable<base::Time>* var_conn_last_changed() override {
- return &var_conn_last_changed_;
- }
-
- private:
- FakeVariable<bool> var_is_connected_{"is_connected", kVariableModePoll};
- FakeVariable<chromeos_update_engine::ConnectionType> var_conn_type_{
- "conn_type", kVariableModePoll};
- FakeVariable<chromeos_update_engine::ConnectionTethering> var_conn_tethering_{
- "conn_tethering", kVariableModePoll};
- FakeVariable<base::Time> var_conn_last_changed_{"conn_last_changed",
- kVariableModePoll};
-
- DISALLOW_COPY_AND_ASSIGN(FakeShillProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SHILL_PROVIDER_H_
diff --git a/update_manager/fake_state.h b/update_manager/fake_state.h
deleted file mode 100644
index 0fd584fe..00000000
--- a/update_manager/fake_state.h
+++ /dev/null
@@ -1,81 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_STATE_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_STATE_H_
-
-#include "update_engine/update_manager/fake_config_provider.h"
-#include "update_engine/update_manager/fake_device_policy_provider.h"
-#include "update_engine/update_manager/fake_random_provider.h"
-#include "update_engine/update_manager/fake_shill_provider.h"
-#include "update_engine/update_manager/fake_system_provider.h"
-#include "update_engine/update_manager/fake_time_provider.h"
-#include "update_engine/update_manager/fake_updater_provider.h"
-#include "update_engine/update_manager/state.h"
-
-namespace chromeos_update_manager {
-
-// A fake State class that creates fake providers for all the providers.
-// This fake can be used in unit testing of Policy subclasses. To fake out the
-// value a variable is exposing, just call FakeVariable<T>::SetValue() on the
-// variable you fake out. For example:
-//
-// FakeState fake_state_;
-// fake_state_.random_provider_->var_seed()->SetValue(new uint64_t(12345));
-//
-// You can call SetValue more than once and the FakeVariable will take care of
-// the memory, but only the last value will remain.
-class FakeState : public State {
- public:
- // Creates and initializes the FakeState using fake providers.
- FakeState() {}
-
- ~FakeState() override {}
-
- // Downcasted getters to access the fake instances during testing.
- FakeConfigProvider* config_provider() override { return &config_provider_; }
-
- FakeDevicePolicyProvider* device_policy_provider() override {
- return &device_policy_provider_;
- }
-
- FakeRandomProvider* random_provider() override { return &random_provider_; }
-
- FakeShillProvider* shill_provider() override { return &shill_provider_; }
-
- FakeSystemProvider* system_provider() override { return &system_provider_; }
-
- FakeTimeProvider* time_provider() override { return &time_provider_; }
-
- FakeUpdaterProvider* updater_provider() override {
- return &updater_provider_;
- }
-
- private:
- FakeConfigProvider config_provider_;
- FakeDevicePolicyProvider device_policy_provider_;
- FakeRandomProvider random_provider_;
- FakeShillProvider shill_provider_;
- FakeSystemProvider system_provider_;
- FakeTimeProvider time_provider_;
- FakeUpdaterProvider updater_provider_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeState);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_STATE_H_
diff --git a/update_manager/fake_system_provider.h b/update_manager/fake_system_provider.h
deleted file mode 100644
index b320c01a..00000000
--- a/update_manager/fake_system_provider.h
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_SYSTEM_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SYSTEM_PROVIDER_H_
-
-#include "update_engine/update_manager/system_provider.h"
-
-#include <string>
-
-#include "update_engine/update_manager/fake_variable.h"
-
-namespace chromeos_update_manager {
-
-// Fake implementation of the SystemProvider base class.
-class FakeSystemProvider : public SystemProvider {
- public:
- FakeSystemProvider() {}
-
- FakeVariable<bool>* var_is_normal_boot_mode() override {
- return &var_is_normal_boot_mode_;
- }
-
- FakeVariable<bool>* var_is_official_build() override {
- return &var_is_official_build_;
- }
-
- FakeVariable<bool>* var_is_oobe_complete() override {
- return &var_is_oobe_complete_;
- }
-
- FakeVariable<unsigned int>* var_num_slots() override {
- return &var_num_slots_;
- }
-
- FakeVariable<std::string>* var_kiosk_required_platform_version() override {
- return &var_kiosk_required_platform_version_;
- }
-
- FakeVariable<base::Version>* var_chromeos_version() override {
- return &var_version_;
- }
-
- private:
- FakeVariable<bool> var_is_normal_boot_mode_{"is_normal_boot_mode",
- kVariableModeConst};
- FakeVariable<bool> var_is_official_build_{"is_official_build",
- kVariableModeConst};
- FakeVariable<bool> var_is_oobe_complete_{"is_oobe_complete",
- kVariableModePoll};
- FakeVariable<unsigned int> var_num_slots_{"num_slots", kVariableModePoll};
- FakeVariable<std::string> var_kiosk_required_platform_version_{
- "kiosk_required_platform_version", kVariableModePoll};
- FakeVariable<base::Version> var_version_{"chromeos_version",
- kVariableModePoll};
-
- DISALLOW_COPY_AND_ASSIGN(FakeSystemProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_SYSTEM_PROVIDER_H_
diff --git a/update_manager/fake_time_provider.h b/update_manager/fake_time_provider.h
deleted file mode 100644
index bd370d26..00000000
--- a/update_manager/fake_time_provider.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_TIME_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_TIME_PROVIDER_H_
-
-#include "update_engine/update_manager/fake_variable.h"
-#include "update_engine/update_manager/time_provider.h"
-
-namespace chromeos_update_manager {
-
-// Fake implementation of the TimeProvider base class.
-class FakeTimeProvider : public TimeProvider {
- public:
- FakeTimeProvider() {}
-
- FakeVariable<base::Time>* var_curr_date() override { return &var_curr_date_; }
- FakeVariable<int>* var_curr_hour() override { return &var_curr_hour_; }
- FakeVariable<int>* var_curr_minute() override { return &var_curr_minute_; }
-
- private:
- FakeVariable<base::Time> var_curr_date_{"curr_date", kVariableModePoll};
- FakeVariable<int> var_curr_hour_{"curr_hour", kVariableModePoll};
- FakeVariable<int> var_curr_minute_{"curr_minute", kVariableModePoll};
-
- DISALLOW_COPY_AND_ASSIGN(FakeTimeProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_TIME_PROVIDER_H_
diff --git a/update_manager/fake_update_manager.h b/update_manager/fake_update_manager.h
deleted file mode 100644
index b8805828..00000000
--- a/update_manager/fake_update_manager.h
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_UPDATE_MANAGER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATE_MANAGER_H_
-
-#include "update_engine/update_manager/update_manager.h"
-
-#include "update_engine/update_manager/default_policy.h"
-#include "update_engine/update_manager/fake_state.h"
-
-namespace chromeos_update_manager {
-
-class FakeUpdateManager : public UpdateManager {
- public:
- FakeUpdateManager()
- : UpdateManager(base::TimeDelta::FromSeconds(5),
- base::TimeDelta::FromHours(1),
- new FakeState()) {
- // The FakeUpdateManager uses a DefaultPolicy.
- set_policy(new DefaultPolicy());
- }
-
- // UpdateManager overrides.
- using UpdateManager::set_policy;
-
- FakeState* state() {
- return reinterpret_cast<FakeState*>(UpdateManager::state());
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FakeUpdateManager);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATE_MANAGER_H_
diff --git a/update_manager/fake_updater_provider.h b/update_manager/fake_updater_provider.h
deleted file mode 100644
index d967f420..00000000
--- a/update_manager/fake_updater_provider.h
+++ /dev/null
@@ -1,123 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_UPDATER_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATER_PROVIDER_H_
-
-#include <string>
-
-#include "update_engine/update_manager/fake_variable.h"
-#include "update_engine/update_manager/updater_provider.h"
-
-namespace chromeos_update_manager {
-
-// Fake implementation of the UpdaterProvider base class.
-class FakeUpdaterProvider : public UpdaterProvider {
- public:
- FakeUpdaterProvider() {}
-
- FakeVariable<base::Time>* var_updater_started_time() override {
- return &var_updater_started_time_;
- }
-
- FakeVariable<base::Time>* var_last_checked_time() override {
- return &var_last_checked_time_;
- }
-
- FakeVariable<base::Time>* var_update_completed_time() override {
- return &var_update_completed_time_;
- }
-
- FakeVariable<double>* var_progress() override { return &var_progress_; }
-
- FakeVariable<Stage>* var_stage() override { return &var_stage_; }
-
- FakeVariable<std::string>* var_new_version() override {
- return &var_new_version_;
- }
-
- FakeVariable<uint64_t>* var_payload_size() override {
- return &var_payload_size_;
- }
-
- FakeVariable<std::string>* var_curr_channel() override {
- return &var_curr_channel_;
- }
-
- FakeVariable<std::string>* var_new_channel() override {
- return &var_new_channel_;
- }
-
- FakeVariable<bool>* var_p2p_enabled() override { return &var_p2p_enabled_; }
-
- FakeVariable<bool>* var_cellular_enabled() override {
- return &var_cellular_enabled_;
- }
-
- FakeVariable<unsigned int>* var_consecutive_failed_update_checks() override {
- return &var_consecutive_failed_update_checks_;
- }
-
- FakeVariable<unsigned int>* var_server_dictated_poll_interval() override {
- return &var_server_dictated_poll_interval_;
- }
-
- FakeVariable<UpdateRequestStatus>* var_forced_update_requested() override {
- return &var_forced_update_requested_;
- }
-
- FakeVariable<UpdateRestrictions>* var_update_restrictions() override {
- 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};
- FakeVariable<base::Time> var_last_checked_time_{"last_checked_time",
- kVariableModePoll};
- FakeVariable<base::Time> var_update_completed_time_{"update_completed_time",
- kVariableModePoll};
- FakeVariable<double> var_progress_{"progress", kVariableModePoll};
- FakeVariable<Stage> var_stage_{"stage", kVariableModePoll};
- FakeVariable<std::string> var_new_version_{"new_version", kVariableModePoll};
- FakeVariable<uint64_t> var_payload_size_{"payload_size", kVariableModePoll};
- FakeVariable<std::string> var_curr_channel_{"curr_channel",
- kVariableModePoll};
- FakeVariable<std::string> var_new_channel_{"new_channel", kVariableModePoll};
- FakeVariable<bool> var_p2p_enabled_{"p2p_enabled", kVariableModeAsync};
- FakeVariable<bool> var_cellular_enabled_{"cellular_enabled",
- kVariableModeAsync};
- FakeVariable<unsigned int> var_consecutive_failed_update_checks_{
- "consecutive_failed_update_checks", kVariableModePoll};
- FakeVariable<unsigned int> var_server_dictated_poll_interval_{
- "server_dictated_poll_interval", kVariableModePoll};
- FakeVariable<UpdateRequestStatus> var_forced_update_requested_{
- "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);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_UPDATER_PROVIDER_H_
diff --git a/update_manager/fake_variable.h b/update_manager/fake_variable.h
deleted file mode 100644
index ef5b4f32..00000000
--- a/update_manager/fake_variable.h
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_FAKE_VARIABLE_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_FAKE_VARIABLE_H_
-
-#include <memory>
-#include <string>
-
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// A fake typed variable to use while testing policy implementations. The
-// variable can be instructed to return any object of its type.
-template <typename T>
-class FakeVariable : public Variable<T> {
- public:
- FakeVariable(const std::string& name, VariableMode mode)
- : Variable<T>(name, mode) {}
- FakeVariable(const std::string& name, base::TimeDelta poll_interval)
- : Variable<T>(name, poll_interval) {}
- ~FakeVariable() override {}
-
- // Sets the next value of this variable to the passed |p_value| pointer. Once
- // returned by GetValue(), the pointer is released and has to be set again.
- // A value of null means that the GetValue() call will fail and return
- // null.
- void reset(const T* p_value) { ptr_.reset(p_value); }
-
- // Make the NotifyValueChanged() public for FakeVariables.
- void NotifyValueChanged() { Variable<T>::NotifyValueChanged(); }
-
- protected:
- // Variable<T> overrides.
- // Returns the pointer set with reset(). The ownership of the object is passed
- // to the caller and the pointer is release from the FakeVariable. A second
- // call to GetValue() without reset() will return null and set the error
- // message.
- const T* GetValue(base::TimeDelta /* timeout */,
- std::string* errmsg) override {
- if (ptr_ == nullptr && errmsg != nullptr)
- *errmsg = this->GetName() + " is an empty FakeVariable";
- // Passes the pointer ownership to the caller.
- return ptr_.release();
- }
-
- private:
- // The pointer returned by GetValue().
- std::unique_ptr<const T> ptr_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeVariable);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_FAKE_VARIABLE_H_
diff --git a/update_manager/generic_variables.h b/update_manager/generic_variables.h
deleted file mode 100644
index afbdcbee..00000000
--- a/update_manager/generic_variables.h
+++ /dev/null
@@ -1,229 +0,0 @@
-//
-// Copyright (C) 2014 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.
-//
-
-// Generic and provider-independent Variable subclasses. These variables can be
-// used by any state provider to implement simple variables to avoid repeat the
-// same common code on different state providers.
-
-#ifndef UPDATE_ENGINE_UPDATE_MANAGER_GENERIC_VARIABLES_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_GENERIC_VARIABLES_H_
-
-#include <string>
-
-#include <base/callback.h>
-
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// Variable class returning a copy of a given object using the copy constructor.
-// This template class can be used to define variables that expose as a variable
-// any fixed object, such as the a provider's private member. The variable will
-// create copies of the provided object using the copy constructor of that
-// class.
-//
-// For example, a state provider exposing a private member as a variable can
-// implement this as follows:
-//
-// class SomethingProvider {
-// public:
-// SomethingProvider(...) {
-// var_something_foo = new PollCopyVariable<MyType>(foo_);
-// }
-// ...
-// private:
-// MyType foo_;
-// };
-template <typename T>
-class PollCopyVariable : public Variable<T> {
- public:
- // Creates the variable returning copies of the passed |ref|. The reference to
- // this object is kept and it should be available whenever the GetValue()
- // method is called. If |is_set_p| is not null, then this flag will be
- // consulted prior to returning the value, and an |errmsg| will be returned if
- // it is not set.
- PollCopyVariable(const std::string& name,
- const T& ref,
- const bool* is_set_p,
- const std::string& errmsg)
- : Variable<T>(name, kVariableModePoll),
- ref_(ref),
- is_set_p_(is_set_p),
- errmsg_(errmsg) {}
- PollCopyVariable(const std::string& name, const T& ref, const bool* is_set_p)
- : PollCopyVariable(name, ref, is_set_p, std::string()) {}
- PollCopyVariable(const std::string& name, const T& ref)
- : PollCopyVariable(name, ref, nullptr) {}
-
- PollCopyVariable(const std::string& name,
- const base::TimeDelta poll_interval,
- const T& ref,
- const bool* is_set_p,
- const std::string& errmsg)
- : Variable<T>(name, poll_interval),
- ref_(ref),
- is_set_p_(is_set_p),
- errmsg_(errmsg) {}
- PollCopyVariable(const std::string& name,
- const base::TimeDelta poll_interval,
- const T& ref,
- const bool* is_set_p)
- : PollCopyVariable(name, poll_interval, ref, is_set_p, std::string()) {}
- PollCopyVariable(const std::string& name,
- const base::TimeDelta poll_interval,
- const T& ref)
- : PollCopyVariable(name, poll_interval, ref, nullptr) {}
-
- protected:
- FRIEND_TEST(UmPollCopyVariableTest, SimpleTest);
- FRIEND_TEST(UmPollCopyVariableTest, UseCopyConstructorTest);
-
- // Variable override.
- inline const T* GetValue(base::TimeDelta /* timeout */,
- std::string* errmsg) override {
- if (is_set_p_ && !(*is_set_p_)) {
- if (errmsg) {
- if (errmsg_.empty())
- *errmsg = "No value set for " + this->GetName();
- else
- *errmsg = errmsg_;
- }
- return nullptr;
- }
- return new T(ref_);
- }
-
- private:
- // Reference to the object to be copied by GetValue().
- const T& ref_;
-
- // A pointer to a flag indicating whether the value is set. If null, then the
- // value is assumed to be set.
- const bool* const is_set_p_;
-
- // An error message to be returned when attempting to get an unset value.
- const std::string errmsg_;
-};
-
-// Variable class returning a constant value that is cached on the variable when
-// it is created.
-template <typename T>
-class ConstCopyVariable : public Variable<T> {
- public:
- // Creates the variable returning copies of the passed |obj|. The value passed
- // is copied in this variable, and new copies of it will be returned by
- // GetValue().
- ConstCopyVariable(const std::string& name, const T& obj)
- : Variable<T>(name, kVariableModeConst), obj_(obj) {}
-
- protected:
- // Variable override.
- const T* GetValue(base::TimeDelta /* timeout */,
- std::string* /* errmsg */) override {
- return new T(obj_);
- }
-
- private:
- // Value to be copied by GetValue().
- const T obj_;
-};
-
-// Variable class returning a copy of a value returned by a given function. The
-// function is called every time the variable is being polled.
-template <typename T>
-class CallCopyVariable : public Variable<T> {
- public:
- CallCopyVariable(const std::string& name, base::Callback<T(void)> func)
- : Variable<T>(name, kVariableModePoll), func_(func) {}
- CallCopyVariable(const std::string& name,
- const base::TimeDelta poll_interval,
- base::Callback<T(void)> func)
- : Variable<T>(name, poll_interval), func_(func) {}
-
- protected:
- // Variable override.
- const T* GetValue(base::TimeDelta /* timeout */,
- std::string* /* errmsg */) override {
- if (func_.is_null())
- return nullptr;
- return new T(func_.Run());
- }
-
- private:
- FRIEND_TEST(UmCallCopyVariableTest, SimpleTest);
-
- // The function to be called, stored as a base::Callback.
- base::Callback<T(void)> func_;
-
- DISALLOW_COPY_AND_ASSIGN(CallCopyVariable);
-};
-
-// A Variable class to implement simple Async variables. It provides two methods
-// SetValue and UnsetValue to modify the current value of the variable and
-// notify the registered observers whenever the value changed.
-//
-// The type T needs to be copy-constructible, default-constructible and have an
-// operator== (to determine if the value changed), which makes this class
-// suitable for basic types.
-template <typename T>
-class AsyncCopyVariable : public Variable<T> {
- public:
- explicit AsyncCopyVariable(const std::string& name)
- : Variable<T>(name, kVariableModeAsync), has_value_(false) {}
-
- AsyncCopyVariable(const std::string& name, const T value)
- : Variable<T>(name, kVariableModeAsync),
- has_value_(true),
- value_(value) {}
-
- void SetValue(const T& new_value) {
- bool should_notify = !(has_value_ && new_value == value_);
- value_ = new_value;
- has_value_ = true;
- if (should_notify)
- this->NotifyValueChanged();
- }
-
- void UnsetValue() {
- if (has_value_) {
- has_value_ = false;
- this->NotifyValueChanged();
- }
- }
-
- protected:
- // Variable override.
- const T* GetValue(base::TimeDelta /* timeout */,
- std::string* errmsg) override {
- if (!has_value_) {
- if (errmsg)
- *errmsg = "No value set for " + this->GetName();
- return nullptr;
- }
- return new T(value_);
- }
-
- private:
- // Whether the variable has a value set.
- bool has_value_;
-
- // Copy of the object to be returned by GetValue().
- T value_;
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_GENERIC_VARIABLES_H_
diff --git a/update_manager/generic_variables_unittest.cc b/update_manager/generic_variables_unittest.cc
deleted file mode 100644
index 0ff97e39..00000000
--- a/update_manager/generic_variables_unittest.cc
+++ /dev/null
@@ -1,214 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/generic_variables.h"
-
-#include <memory>
-
-#include <base/callback.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/update_manager/umtest_utils.h"
-
-using brillo::MessageLoop;
-using brillo::MessageLoopRunMaxIterations;
-using std::unique_ptr;
-
-namespace chromeos_update_manager {
-
-class UmPollCopyVariableTest : public ::testing::Test {};
-
-TEST_F(UmPollCopyVariableTest, SimpleTest) {
- // Tests that copies are generated as intended.
- int source = 5;
- PollCopyVariable<int> var("var", source);
-
- // Generate and validate a copy.
- unique_ptr<const int> copy_1(
- var.GetValue(UmTestUtils::DefaultTimeout(), nullptr));
- ASSERT_NE(nullptr, copy_1.get());
- EXPECT_EQ(5, *copy_1);
-
- // Assign a different value to the source variable.
- source = 42;
-
- // Check that the content of the copy was not affected (distinct instance).
- EXPECT_EQ(5, *copy_1);
-
- // Generate and validate a second copy.
- UmTestUtils::ExpectVariableHasValue(42, &var);
-}
-
-TEST_F(UmPollCopyVariableTest, SetFlagTest) {
- // Tests that the set flag is being referred to as expected.
- int source = 5;
- bool is_set = false;
- PollCopyVariable<int> var("var", source, &is_set);
-
- // Flag marked unset, nothing should be returned.
- UmTestUtils::ExpectVariableNotSet(&var);
-
- // Flag marked set, we should be getting a value.
- is_set = true;
- UmTestUtils::ExpectVariableHasValue(5, &var);
-}
-
-class CopyConstructorTestClass {
- public:
- CopyConstructorTestClass(void) : copied_(false) {}
- CopyConstructorTestClass(const CopyConstructorTestClass& other)
- : copied_(true), val_(other.val_ * 2) {}
-
- // Tells if the instance was constructed using the copy-constructor.
- const bool copied_;
-
- // An auxiliary internal value.
- int val_ = 0;
-};
-
-TEST_F(UmPollCopyVariableTest, UseCopyConstructorTest) {
- // Ensures that CopyVariables indeed uses the copy constructor.
- const CopyConstructorTestClass source;
- ASSERT_FALSE(source.copied_);
-
- PollCopyVariable<CopyConstructorTestClass> var("var", source);
- unique_ptr<const CopyConstructorTestClass> copy(
- var.GetValue(UmTestUtils::DefaultTimeout(), nullptr));
- ASSERT_NE(nullptr, copy.get());
- EXPECT_TRUE(copy->copied_);
-}
-
-class UmConstCopyVariableTest : public ::testing::Test {};
-
-TEST_F(UmConstCopyVariableTest, SimpleTest) {
- int source = 5;
- ConstCopyVariable<int> var("var", source);
- UmTestUtils::ExpectVariableHasValue(5, &var);
-
- // Ensure the value is cached.
- source = 42;
- UmTestUtils::ExpectVariableHasValue(5, &var);
-}
-
-class UmCallCopyVariableTest : public ::testing::Test {};
-
-CopyConstructorTestClass test_func(CopyConstructorTestClass* obj) {
- obj->val_++; // So we can check that the function was called.
- return *obj;
-}
-
-TEST_F(UmCallCopyVariableTest, SimpleTest) {
- // Tests that the returned value is generated by copying the value returned by
- // the function call.
-
- CopyConstructorTestClass test_obj;
- ASSERT_FALSE(test_obj.copied_);
- test_obj.val_ = 5;
-
- base::Callback<CopyConstructorTestClass(void)> cb =
- base::Bind(test_func, &test_obj);
- CallCopyVariable<CopyConstructorTestClass> var("var", cb);
-
- unique_ptr<const CopyConstructorTestClass> copy(
- var.GetValue(UmTestUtils::DefaultTimeout(), nullptr));
- EXPECT_EQ(6, test_obj.val_); // Check that the function was called.
- ASSERT_NE(nullptr, copy.get());
- EXPECT_TRUE(copy->copied_);
- EXPECT_EQ(12, copy->val_); // Check that copying occurred once.
-}
-
-TEST_F(UmCallCopyVariableTest, NullTest) {
- // Ensures that the variable returns null when the callback is null.
-
- base::Callback<bool(void)> cb;
- CallCopyVariable<bool> var("var", cb);
- UmTestUtils::ExpectVariableNotSet(&var);
-}
-
-class UmAsyncCopyVariableTest : public ::testing::Test {
- protected:
- void SetUp() override { loop_.SetAsCurrent(); }
-
- void TearDown() override {
- // No remaining event on the main loop.
- EXPECT_FALSE(loop_.PendingTasks());
- }
-
- brillo::FakeMessageLoop loop_{nullptr};
-};
-
-TEST_F(UmAsyncCopyVariableTest, ConstructorTest) {
- AsyncCopyVariable<int> var("var");
- UmTestUtils::ExpectVariableNotSet(&var);
- EXPECT_EQ(kVariableModeAsync, var.GetMode());
-}
-
-TEST_F(UmAsyncCopyVariableTest, SetValueTest) {
- AsyncCopyVariable<int> var("var");
- var.SetValue(5);
- UmTestUtils::ExpectVariableHasValue(5, &var);
- // Execute all the pending observers.
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
-}
-
-TEST_F(UmAsyncCopyVariableTest, UnsetValueTest) {
- AsyncCopyVariable<int> var("var", 42);
- var.UnsetValue();
- UmTestUtils::ExpectVariableNotSet(&var);
- // Execute all the pending observers.
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
-}
-
-class CallCounterObserver : public BaseVariable::ObserverInterface {
- public:
- void ValueChanged(BaseVariable* variable) { calls_count_++; }
-
- int calls_count_ = 0;
-};
-
-TEST_F(UmAsyncCopyVariableTest, ObserverCalledTest) {
- AsyncCopyVariable<int> var("var", 42);
- CallCounterObserver observer;
- var.AddObserver(&observer);
- EXPECT_EQ(0, observer.calls_count_);
-
- // Check that a different value fires the notification.
- var.SetValue(5);
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_EQ(1, observer.calls_count_);
-
- // Check the same value doesn't.
- var.SetValue(5);
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_EQ(1, observer.calls_count_);
-
- // Check that unsetting a previously set value fires the notification.
- var.UnsetValue();
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_EQ(2, observer.calls_count_);
-
- // Check that unsetting again doesn't.
- var.UnsetValue();
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_EQ(2, observer.calls_count_);
-
- var.RemoveObserver(&observer);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/interactive_update_policy_impl.cc b/update_manager/interactive_update_policy_impl.cc
deleted file mode 100644
index 872dc5d7..00000000
--- a/update_manager/interactive_update_policy_impl.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-//
-// 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/update_manager/interactive_update_policy_impl.h"
-
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-
-namespace chromeos_update_manager {
-
-// Check to see if an interactive update was requested.
-EvalStatus InteractiveUpdatePolicyImpl::UpdateCheckAllowed(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const {
- bool interactive;
- if (CheckInteractiveUpdateRequested(
- ec, state->updater_provider(), &interactive)) {
- result->interactive = interactive;
- LOG(INFO) << "Forced update signaled ("
- << (interactive ? "interactive" : "periodic")
- << "), allowing update check.";
- return EvalStatus::kSucceeded;
- }
- return EvalStatus::kContinue;
-}
-
-EvalStatus InteractiveUpdatePolicyImpl::UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- ErrorCode* result,
- InstallPlan* install_plan) const {
- bool interactive;
- if (CheckInteractiveUpdateRequested(
- ec, state->updater_provider(), &interactive)) {
- LOG(INFO) << "Forced update signaled ("
- << (interactive ? "interactive" : "periodic")
- << "), allowing update to be applied.";
- *result = ErrorCode::kSuccess;
- return EvalStatus::kSucceeded;
- }
- return EvalStatus::kContinue;
-}
-
-bool InteractiveUpdatePolicyImpl::CheckInteractiveUpdateRequested(
- EvaluationContext* ec,
- UpdaterProvider* const updater_provider,
- bool* interactive_out) const {
- // First, check to see if an interactive update was requested.
- const UpdateRequestStatus* forced_update_requested_p =
- ec->GetValue(updater_provider->var_forced_update_requested());
- if (forced_update_requested_p != nullptr &&
- *forced_update_requested_p != UpdateRequestStatus::kNone) {
- if (interactive_out)
- *interactive_out =
- (*forced_update_requested_p == UpdateRequestStatus::kInteractive);
- return true;
- }
- return false;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/interactive_update_policy_impl.h b/update_manager/interactive_update_policy_impl.h
deleted file mode 100644
index 3690cfb0..00000000
--- a/update_manager/interactive_update_policy_impl.h
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// 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_UPDATE_MANAGER_INTERACTIVE_UPDATE_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_INTERACTIVE_UPDATE_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/common/error_code.h"
-#include "update_engine/payload_consumer/install_plan.h"
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Check to see if an interactive update was requested.
-class InteractiveUpdatePolicyImpl : public PolicyImplBase {
- public:
- InteractiveUpdatePolicyImpl() = default;
- ~InteractiveUpdatePolicyImpl() override = default;
-
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override;
-
- protected:
- std::string PolicyName() const override {
- return "InteractiveUpdatePolicyImpl";
- }
-
- private:
- // Checks whether a forced update was requested. If there is a forced update,
- // return true and set |interactive_out| to true if the forced update is
- // interactive, and false otherwise. If there are no forced updates, return
- // true and don't modify |interactive_out|.
- bool CheckInteractiveUpdateRequested(EvaluationContext* ec,
- UpdaterProvider* const updater_provider,
- bool* interactive_out) const;
-
- DISALLOW_COPY_AND_ASSIGN(InteractiveUpdatePolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_INTERACTIVE_UPDATE_POLICY_IMPL_H_
diff --git a/update_manager/minimum_version_policy_impl.cc b/update_manager/minimum_version_policy_impl.cc
deleted file mode 100644
index fb94ee49..00000000
--- a/update_manager/minimum_version_policy_impl.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// 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/update_manager/minimum_version_policy_impl.h"
-
-#include <base/version.h>
-
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-
-namespace chromeos_update_manager {
-
-EvalStatus MinimumVersionPolicyImpl::UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- ErrorCode* result,
- InstallPlan* install_plan) const {
- const base::Version* current_version(
- ec->GetValue(state->system_provider()->var_chromeos_version()));
- if (current_version == nullptr || !current_version->IsValid()) {
- LOG(WARNING) << "Unable to access current version";
- return EvalStatus::kContinue;
- }
-
- const base::Version* minimum_version = ec->GetValue(
- state->device_policy_provider()->var_device_minimum_version());
- if (minimum_version == nullptr || !minimum_version->IsValid()) {
- LOG(WARNING) << "Unable to access minimum version";
- return EvalStatus::kContinue;
- }
-
- if (*current_version < *minimum_version) {
- LOG(INFO) << "Updating from version less than minimum required"
- ", allowing update to be applied.";
- *result = ErrorCode::kSuccess;
- return EvalStatus::kSucceeded;
- }
-
- return EvalStatus::kContinue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/minimum_version_policy_impl.h b/update_manager/minimum_version_policy_impl.h
deleted file mode 100644
index 600d6244..00000000
--- a/update_manager/minimum_version_policy_impl.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// 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_UPDATE_MANAGER_MINIMUM_VERSION_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_MINIMUM_VERSION_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/common/error_code.h"
-#include "update_engine/payload_consumer/install_plan.h"
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Check to see if an update happens from a version less than the minimum
-// required one.
-class MinimumVersionPolicyImpl : public PolicyImplBase {
- public:
- MinimumVersionPolicyImpl() = default;
- ~MinimumVersionPolicyImpl() override = default;
-
- // If current version is less than the minimum required one, then this should
- // not block the update to be applied.
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override;
-
- protected:
- std::string PolicyName() const override { return "MinimumVersionPolicyImpl"; }
-
- private:
- MinimumVersionPolicyImpl(const MinimumVersionPolicyImpl&) = delete;
- MinimumVersionPolicyImpl& operator=(const MinimumVersionPolicyImpl&) = delete;
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_MINIMUM_VERSION_POLICY_IMPL_H_
diff --git a/update_manager/minimum_version_policy_impl_unittest.cc b/update_manager/minimum_version_policy_impl_unittest.cc
deleted file mode 100644
index 8e4dba55..00000000
--- a/update_manager/minimum_version_policy_impl_unittest.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-//
-// 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 <memory>
-
-#include "update_engine/update_manager/minimum_version_policy_impl.h"
-#include "update_engine/update_manager/policy_test_utils.h"
-
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-
-namespace {
-
-const char* kInvalidVersion = "13315.woops.12";
-const char* kOldVersion = "13315.60.12";
-const char* kNewVersion = "13315.60.15";
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-class UmMinimumVersionPolicyImplTest : public UmPolicyTestBase {
- protected:
- UmMinimumVersionPolicyImplTest() {
- policy_ = std::make_unique<MinimumVersionPolicyImpl>();
- }
-
- void SetCurrentVersion(const std::string& version) {
- fake_state_.system_provider()->var_chromeos_version()->reset(
- new base::Version(version));
- }
-
- void SetMinimumVersion(const std::string& version) {
- fake_state_.device_policy_provider()->var_device_minimum_version()->reset(
- new base::Version(version));
- }
-
- void TestPolicy(const EvalStatus& expected_status) {
- InstallPlan install_plan;
- ErrorCode result;
- ExpectPolicyStatus(
- expected_status, &Policy::UpdateCanBeApplied, &result, &install_plan);
- if (expected_status == EvalStatus::kSucceeded)
- EXPECT_EQ(result, ErrorCode::kSuccess);
- }
-};
-
-TEST_F(UmMinimumVersionPolicyImplTest, ContinueWhenCurrentVersionIsNotSet) {
- SetMinimumVersion(kNewVersion);
-
- TestPolicy(EvalStatus::kContinue);
-}
-
-TEST_F(UmMinimumVersionPolicyImplTest, ContinueWhenCurrentVersionIsInvalid) {
- SetCurrentVersion(kInvalidVersion);
- SetMinimumVersion(kNewVersion);
-
- TestPolicy(EvalStatus::kContinue);
-}
-
-TEST_F(UmMinimumVersionPolicyImplTest, ContinueWhenMinumumVersionIsNotSet) {
- SetCurrentVersion(kOldVersion);
-
- TestPolicy(EvalStatus::kContinue);
-}
-
-TEST_F(UmMinimumVersionPolicyImplTest, ContinueWhenMinumumVersionIsInvalid) {
- SetCurrentVersion(kOldVersion);
- SetMinimumVersion(kInvalidVersion);
-
- TestPolicy(EvalStatus::kContinue);
-}
-
-TEST_F(UmMinimumVersionPolicyImplTest,
- ContinueWhenCurrentVersionIsGreaterThanMinimumVersion) {
- SetCurrentVersion(kNewVersion);
- SetMinimumVersion(kOldVersion);
-
- TestPolicy(EvalStatus::kContinue);
-}
-
-TEST_F(UmMinimumVersionPolicyImplTest,
- ContinueWhenCurrentVersionIsEqualToMinimumVersion) {
- SetCurrentVersion(kNewVersion);
- SetMinimumVersion(kNewVersion);
-
- TestPolicy(EvalStatus::kContinue);
-}
-
-TEST_F(UmMinimumVersionPolicyImplTest,
- SuccessWhenCurrentVersionIsLessThanMinimumVersion) {
- SetCurrentVersion(kOldVersion);
- SetMinimumVersion(kNewVersion);
-
- TestPolicy(EvalStatus::kSucceeded);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/mock_policy.h b/update_manager/mock_policy.h
deleted file mode 100644
index 3c6313fd..00000000
--- a/update_manager/mock_policy.h
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_MOCK_POLICY_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_MOCK_POLICY_H_
-
-#include <string>
-
-#include <gmock/gmock.h>
-
-#include "update_engine/update_manager/default_policy.h"
-#include "update_engine/update_manager/policy.h"
-
-namespace chromeos_update_manager {
-
-// A mocked implementation of Policy.
-class MockPolicy : public Policy {
- public:
- MockPolicy() {
- // We defer to the corresponding DefaultPolicy methods, by default.
- ON_CALL(*this,
- UpdateCheckAllowed(testing::_, testing::_, testing::_, testing::_))
- .WillByDefault(testing::Invoke(&default_policy_,
- &DefaultPolicy::UpdateCheckAllowed));
- ON_CALL(*this,
- UpdateCanBeApplied(
- testing::_, testing::_, testing::_, testing::_, testing::_))
- .WillByDefault(testing::Invoke(&default_policy_,
- &DefaultPolicy::UpdateCanBeApplied));
- ON_CALL(*this,
- UpdateCanStart(
- testing::_, testing::_, testing::_, testing::_, testing::_))
- .WillByDefault(
- testing::Invoke(&default_policy_, &DefaultPolicy::UpdateCanStart));
- ON_CALL(*this, P2PEnabled(testing::_, testing::_, testing::_, testing::_))
- .WillByDefault(
- testing::Invoke(&default_policy_, &DefaultPolicy::P2PEnabled));
- ON_CALL(*this,
- P2PEnabledChanged(
- testing::_, testing::_, testing::_, testing::_, testing::_))
- .WillByDefault(testing::Invoke(&default_policy_,
- &DefaultPolicy::P2PEnabledChanged));
- }
- ~MockPolicy() override {}
-
- // Policy overrides.
- MOCK_CONST_METHOD4(
- UpdateCheckAllowed,
- EvalStatus(EvaluationContext*, State*, std::string*, UpdateCheckParams*));
-
- MOCK_CONST_METHOD5(UpdateCanBeApplied,
- EvalStatus(EvaluationContext*,
- State*,
- std::string*,
- chromeos_update_engine::ErrorCode*,
- chromeos_update_engine::InstallPlan*));
-
- MOCK_CONST_METHOD5(UpdateCanStart,
- EvalStatus(EvaluationContext*,
- State*,
- std::string*,
- UpdateDownloadParams*,
- UpdateState));
-
- MOCK_CONST_METHOD4(
- UpdateDownloadAllowed,
- EvalStatus(EvaluationContext*, State*, std::string*, bool*));
-
- MOCK_CONST_METHOD4(
- P2PEnabled, EvalStatus(EvaluationContext*, State*, std::string*, bool*));
-
- MOCK_CONST_METHOD5(
- P2PEnabledChanged,
- EvalStatus(EvaluationContext*, State*, std::string*, bool*, bool));
-
- protected:
- // Policy override.
- std::string PolicyName() const override { return "MockPolicy"; }
-
- private:
- DefaultPolicy default_policy_;
-
- DISALLOW_COPY_AND_ASSIGN(MockPolicy);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_MOCK_POLICY_H_
diff --git a/update_manager/mock_update_manager.h b/update_manager/mock_update_manager.h
deleted file mode 100644
index 06e17d81..00000000
--- a/update_manager/mock_update_manager.h
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// Copyright (C) 2019 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_MOCK_UPDATE_MANAGER_H
-#define UPDATE_ENGINE_MOCK_UPDATE_MANAGER_H
-
-#include <string>
-
-#include "update_engine/update_manager/update_manager.h"
-
-#include <gmock/gmock.h>
-
-namespace chromeos_update_manager {
-
-class MockUpdateManager : public UpdateManager {
- public:
- MockUpdateManager()
- : UpdateManager(base::TimeDelta(), base::TimeDelta(), nullptr) {}
-
- MOCK_METHOD2(
- AsyncPolicyRequestUpdateCheckAllowed,
- void(base::Callback<void(EvalStatus, const UpdateCheckParams& result)>
- callback,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, UpdateCheckParams*)
- const));
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_MOCK_UPDATE_MANAGER_H
diff --git a/update_manager/mock_variable.h b/update_manager/mock_variable.h
deleted file mode 100644
index 8b6c2769..00000000
--- a/update_manager/mock_variable.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_MOCK_VARIABLE_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_MOCK_VARIABLE_H_
-
-#include <string>
-
-#include <gmock/gmock.h>
-
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// This is a generic mock of the Variable class.
-template <typename T>
-class MockVariable : public Variable<T> {
- public:
- using Variable<T>::Variable;
-
- MOCK_METHOD2_T(GetValue, const T*(base::TimeDelta, std::string*));
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockVariable);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_MOCK_VARIABLE_H_
diff --git a/update_manager/next_update_check_policy_impl.cc b/update_manager/next_update_check_policy_impl.cc
deleted file mode 100644
index 0a787186..00000000
--- a/update_manager/next_update_check_policy_impl.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-//
-// 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/update_manager/next_update_check_policy_impl.h"
-
-#include <algorithm>
-
-#include "update_engine/common/utils.h"
-
-using base::Time;
-using base::TimeDelta;
-using std::max;
-using std::string;
-
-namespace chromeos_update_manager {
-
-NextUpdateCheckTimePolicyImpl::NextUpdateCheckTimePolicyImpl(
- const NextUpdateCheckPolicyConstants& constants)
- : policy_constants_(constants) {}
-
-EvalStatus NextUpdateCheckTimePolicyImpl::UpdateCheckAllowed(
- EvaluationContext* ec,
- State* state,
- string* error,
- UpdateCheckParams* result) const {
- // Ensure that periodic update checks are timed properly.
- Time next_update_check;
-
- if (NextUpdateCheckTime(
- ec, state, error, &next_update_check, policy_constants_) !=
- EvalStatus::kSucceeded) {
- return EvalStatus::kFailed;
- }
- if (!ec->IsWallclockTimeGreaterThan(next_update_check)) {
- LOG(INFO) << "Periodic check interval not satisfied, blocking until "
- << chromeos_update_engine::utils::ToString(next_update_check);
- return EvalStatus::kAskMeAgainLater;
- }
-
- return EvalStatus::kContinue;
-}
-
-EvalStatus NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime(
- EvaluationContext* ec,
- State* state,
- string* error,
- Time* next_update_check,
- const NextUpdateCheckPolicyConstants& constants) {
- UpdaterProvider* const updater_provider = state->updater_provider();
-
- // Don't check for updates too often. We limit the update checks to once every
- // some interval. The interval is kTimeoutInitialInterval the first time and
- // kTimeoutPeriodicInterval for the subsequent update checks. If the update
- // check fails, we increase the interval between the update checks
- // exponentially until kTimeoutMaxBackoffInterval. Finally, to avoid having
- // many chromebooks running update checks at the exact same time, we add some
- // fuzz to the interval.
- const Time* updater_started_time =
- 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());
-
- const auto* seed = ec->GetValue(state->random_provider()->var_seed());
- POLICY_CHECK_VALUE_AND_FAIL(seed, error);
-
- PRNG prng(*seed);
-
- // If this is the first attempt, compute and return an initial value.
- if (last_checked_time == nullptr ||
- *last_checked_time < *updater_started_time) {
- 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 =
- ec->GetValue(updater_provider->var_server_dictated_poll_interval());
- POLICY_CHECK_VALUE_AND_FAIL(server_dictated_poll_interval, error);
-
- int interval = *server_dictated_poll_interval;
- int fuzz = 0;
-
- // If no poll interval was dictated by server compute a back-off period,
- // starting from a predetermined base periodic interval and increasing
- // exponentially by the number of consecutive failed attempts.
- if (interval == 0) {
- const unsigned int* consecutive_failed_update_checks =
- ec->GetValue(updater_provider->var_consecutive_failed_update_checks());
- POLICY_CHECK_VALUE_AND_FAIL(consecutive_failed_update_checks, error);
-
- interval = constants.timeout_periodic_interval;
- unsigned int num_failures = *consecutive_failed_update_checks;
- while (interval < constants.timeout_max_backoff_interval && num_failures) {
- interval *= 2;
- num_failures--;
- }
- }
-
- // We cannot back off longer than the predetermined maximum interval.
- if (interval > constants.timeout_max_backoff_interval)
- interval = constants.timeout_max_backoff_interval;
-
- // We cannot back off shorter than the predetermined periodic interval. Also,
- // in this case set the fuzz to a predetermined regular value.
- if (interval <= constants.timeout_periodic_interval) {
- interval = constants.timeout_periodic_interval;
- fuzz = constants.timeout_regular_fuzz;
- }
-
- // If not otherwise determined, defer to a fuzz of +/-(interval / 2).
- if (fuzz == 0)
- fuzz = interval;
-
- *next_update_check =
- *last_checked_time + FuzzedInterval(&prng, interval, fuzz);
- return EvalStatus::kSucceeded;
-}
-
-TimeDelta NextUpdateCheckTimePolicyImpl::FuzzedInterval(PRNG* prng,
- int interval,
- int fuzz) {
- DCHECK_GE(interval, 0);
- DCHECK_GE(fuzz, 0);
- int half_fuzz = fuzz / 2;
- // This guarantees the output interval is non negative.
- int interval_min = max(interval - half_fuzz, 0);
- int interval_max = interval + half_fuzz;
- return TimeDelta::FromSeconds(prng->RandMinMax(interval_min, interval_max));
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/next_update_check_policy_impl.h b/update_manager/next_update_check_policy_impl.h
deleted file mode 100644
index 291ea0f0..00000000
--- a/update_manager/next_update_check_policy_impl.h
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// 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_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
-
-#include <string>
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/policy_utils.h"
-#include "update_engine/update_manager/prng.h"
-
-namespace chromeos_update_manager {
-
-// Constants that are provided to the policy implementation.
-struct NextUpdateCheckPolicyConstants {
- // Default update check timeout interval/fuzz values used to compute the
- // NextUpdateCheckTime(), in seconds. Actual fuzz is within +/- half of the
- // indicated value.
- int timeout_initial_interval;
- int timeout_periodic_interval;
- int timeout_max_backoff_interval;
- int timeout_regular_fuzz;
-
- // Maximum update attempt backoff interval and fuzz.
- int attempt_backoff_max_interval_in_days;
- int attempt_backoff_fuzz_in_hours;
-};
-
-// Ensure that periodic update checks are timed properly.
-class NextUpdateCheckTimePolicyImpl : public PolicyImplBase {
- public:
- explicit NextUpdateCheckTimePolicyImpl(
- const NextUpdateCheckPolicyConstants& constants);
-
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- // A private policy implementation returning the wallclock timestamp when
- // the next update check should happen.
- // TODO(garnold) We should probably change that to infer a monotonic
- // timestamp, which will make the update check intervals more resilient to
- // clock skews. Might require switching some of the variables exported by the
- // UpdaterProvider to report monotonic time, as well.
- //
- // NOTE:
- // Exposed as a public static so that it's logic can be used to test
- // Policy implementations that utilize this fragment for their
- // timing, without needing to list them all with FRIEND_TEST (so that
- // those Policy implementations can exist without modifying this
- // class's definition.
- //
- // The output value from this method (|next_update_check|), isn't
- // available via the UpdateCheckParams |result| of the Policy
- // method, and so this timing logic needs to be otherwise exposed.
- static EvalStatus NextUpdateCheckTime(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- base::Time* next_update_check,
- const NextUpdateCheckPolicyConstants& constants);
-
- // Returns a TimeDelta based on the provided |interval| seconds +/- half
- // |fuzz| seconds. The return value is guaranteed to be a non-negative
- // TimeDelta.
- static base::TimeDelta FuzzedInterval(PRNG* prng, int interval, int fuzz);
-
- protected:
- std::string PolicyName() const override {
- return "NextUpdateCheckTimePolicyImpl";
- }
-
- private:
- const NextUpdateCheckPolicyConstants policy_constants_;
-
- DISALLOW_COPY_AND_ASSIGN(NextUpdateCheckTimePolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_NEXT_UPDATE_CHECK_POLICY_IMPL_H_
diff --git a/update_manager/next_update_check_policy_impl_unittest.cc b/update_manager/next_update_check_policy_impl_unittest.cc
deleted file mode 100644
index d80063de..00000000
--- a/update_manager/next_update_check_policy_impl_unittest.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-//
-// 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/update_manager/next_update_check_policy_impl.h"
-
-#include <memory>
-
-#include "update_engine/update_manager/policy_test_utils.h"
-
-using base::Time;
-using base::TimeDelta;
-using std::string;
-
-namespace chromeos_update_manager {
-
-const NextUpdateCheckPolicyConstants policy_test_constants = {
- // these are specifically NOT the values used by real Policy
- // implementations.
- .timeout_initial_interval = 3 * 60,
- .timeout_periodic_interval = 2 * 60 * 60,
- .timeout_max_backoff_interval = 8 * 60 * 60,
- .timeout_regular_fuzz = 5 * 60,
- .attempt_backoff_max_interval_in_days = 12,
- .attempt_backoff_fuzz_in_hours = 10,
-};
-
-class UmNextUpdateCheckTimePolicyImplTest : public UmPolicyTestBase {
- protected:
- UmNextUpdateCheckTimePolicyImplTest() {
- policy_ =
- std::make_unique<NextUpdateCheckTimePolicyImpl>(policy_test_constants);
- }
-};
-
-TEST_F(UmNextUpdateCheckTimePolicyImplTest,
- FirstCheckIsAtMostInitialIntervalAfterStart) {
- Time next_update_check;
-
- // Set the last update time so it'll appear as if this is a first update check
- // in the lifetime of the current updater.
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(fake_clock_->GetWallclockTime() - TimeDelta::FromMinutes(10)));
-
- CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- policy_test_constants);
-
- EXPECT_LE(fake_clock_->GetWallclockTime(), next_update_check);
- EXPECT_GE(fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(
- policy_test_constants.timeout_initial_interval +
- policy_test_constants.timeout_regular_fuzz / 2),
- next_update_check);
-}
-
-TEST_F(UmNextUpdateCheckTimePolicyImplTest, RecurringCheckBaseIntervalAndFuzz) {
- // Ensure that we're using the correct interval (kPeriodicInterval) and fuzz
- // (ktimeout_regular_fuzz) as base values for period updates.
- Time next_update_check;
-
- CallMethodWithContext(&NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- policy_test_constants);
-
- EXPECT_LE(fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(
- policy_test_constants.timeout_periodic_interval -
- policy_test_constants.timeout_regular_fuzz / 2),
- next_update_check);
- EXPECT_GE(fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(
- policy_test_constants.timeout_periodic_interval +
- policy_test_constants.timeout_regular_fuzz / 2),
- next_update_check);
-}
-
-TEST_F(UmNextUpdateCheckTimePolicyImplTest,
- RecurringCheckBackoffIntervalAndFuzz) {
- // Ensure that we're properly backing off and fuzzing in the presence of
- // failed updates attempts.
- Time next_update_check;
-
- fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
- new unsigned int{2});
-
- ExpectStatus(EvalStatus::kSucceeded,
- NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- policy_test_constants);
-
- int expected_interval = policy_test_constants.timeout_periodic_interval * 4;
- EXPECT_LE(
- fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(expected_interval - expected_interval / 2),
- next_update_check);
- EXPECT_GE(
- fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(expected_interval + expected_interval / 2),
- next_update_check);
-}
-
-TEST_F(UmNextUpdateCheckTimePolicyImplTest,
- RecurringCheckServerDictatedPollInterval) {
- // Policy honors the server provided check poll interval.
- Time next_update_check;
-
- const auto kInterval = policy_test_constants.timeout_periodic_interval * 4;
- fake_state_.updater_provider()->var_server_dictated_poll_interval()->reset(
- new unsigned int(kInterval)); // NOLINT(readability/casting)
- // We should not be backing off in this case.
- fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
- new unsigned int(2)); // NOLINT(readability/casting)
-
- ExpectStatus(EvalStatus::kSucceeded,
- &NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- policy_test_constants);
-
- EXPECT_LE(fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(kInterval - kInterval / 2),
- next_update_check);
- EXPECT_GE(fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(kInterval + kInterval / 2),
- next_update_check);
-}
-
-TEST_F(UmNextUpdateCheckTimePolicyImplTest, ExponentialBackoffIsCapped) {
- Time next_update_check;
-
- fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
- new unsigned int(100)); // NOLINT(readability/casting)
-
- ExpectStatus(EvalStatus::kSucceeded,
- &NextUpdateCheckTimePolicyImpl::NextUpdateCheckTime,
- &next_update_check,
- policy_test_constants);
-
- EXPECT_LE(fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(
- policy_test_constants.timeout_max_backoff_interval -
- policy_test_constants.timeout_max_backoff_interval / 2),
- next_update_check);
- EXPECT_GE(fake_clock_->GetWallclockTime() +
- TimeDelta::FromSeconds(
- policy_test_constants.timeout_max_backoff_interval +
- policy_test_constants.timeout_max_backoff_interval / 2),
- next_update_check);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/official_build_check_policy_impl.cc b/update_manager/official_build_check_policy_impl.cc
deleted file mode 100644
index e80c09f8..00000000
--- a/update_manager/official_build_check_policy_impl.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// 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/update_manager/official_build_check_policy_impl.h"
-
-namespace chromeos_update_manager {
-
-// Unofficial builds should not perform periodic update checks.
-EvalStatus OnlyUpdateOfficialBuildsPolicyImpl::UpdateCheckAllowed(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const {
- 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)) {
- 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;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/official_build_check_policy_impl.h b/update_manager/official_build_check_policy_impl.h
deleted file mode 100644
index 62572092..00000000
--- a/update_manager/official_build_check_policy_impl.h
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// 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_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Unofficial builds should not perform periodic update checks.
-class OnlyUpdateOfficialBuildsPolicyImpl : public PolicyImplBase {
- public:
- OnlyUpdateOfficialBuildsPolicyImpl() = default;
- ~OnlyUpdateOfficialBuildsPolicyImpl() override = default;
-
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- protected:
- std::string PolicyName() const override {
- return "OnlyUpdateOfficialBuildsPolicyImpl";
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(OnlyUpdateOfficialBuildsPolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_OFFICIAL_BUILD_CHECK_POLICY_IMPL_H_
diff --git a/update_manager/out_of_box_experience_policy_impl.cc b/update_manager/out_of_box_experience_policy_impl.cc
deleted file mode 100644
index 8dcb5606..00000000
--- a/update_manager/out_of_box_experience_policy_impl.cc
+++ /dev/null
@@ -1,43 +0,0 @@
-//
-// 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/update_manager/out_of_box_experience_policy_impl.h"
-
-#include "update_engine/common/utils.h"
-
-namespace chromeos_update_manager {
-
-EvalStatus OobePolicyImpl::UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const {
- SystemProvider* const system_provider = state->system_provider();
-
- // If OOBE is enabled, wait until it is completed.
- const bool* is_oobe_enabled_p =
- ec->GetValue(state->config_provider()->var_is_oobe_enabled());
- if (is_oobe_enabled_p && *is_oobe_enabled_p) {
- const bool* is_oobe_complete_p =
- ec->GetValue(system_provider->var_is_oobe_complete());
- if (is_oobe_complete_p && !(*is_oobe_complete_p)) {
- LOG(INFO) << "OOBE not completed, blocking update checks.";
- return EvalStatus::kAskMeAgainLater;
- }
- }
- return EvalStatus::kContinue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/out_of_box_experience_policy_impl.h b/update_manager/out_of_box_experience_policy_impl.h
deleted file mode 100644
index ec1997b1..00000000
--- a/update_manager/out_of_box_experience_policy_impl.h
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// 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_UPDATE_MANAGER_OUT_OF_BOX_EXPERIENCE_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_OUT_OF_BOX_EXPERIENCE_POLICY_IMPL_H_
-
-#include <string>
-
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// If OOBE is enabled, wait until it is completed.
-class OobePolicyImpl : public PolicyImplBase {
- public:
- OobePolicyImpl() = default;
- ~OobePolicyImpl() override = default;
-
- std::string PolicyName() const override { return "OobePolicyImpl"; }
-
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(OobePolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_OUT_OF_BOX_EXPERIENCE_POLICY_IMPL_H_
diff --git a/update_manager/policy.cc b/update_manager/policy.cc
deleted file mode 100644
index 5f79a688..00000000
--- a/update_manager/policy.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/policy.h"
-
-#include <string>
-
-using std::string;
-
-namespace chromeos_update_manager {
-
-string ToString(EvalStatus status) {
- switch (status) {
- case EvalStatus::kFailed:
- return "kFailed";
- case EvalStatus::kSucceeded:
- return "kSucceeded";
- case EvalStatus::kAskMeAgainLater:
- return "kAskMeAgainLater";
- case EvalStatus::kContinue:
- return "kContinue";
- }
- return "Invalid";
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/policy.h b/update_manager/policy.h
deleted file mode 100644
index fb4a1295..00000000
--- a/update_manager/policy.h
+++ /dev/null
@@ -1,314 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_POLICY_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_POLICY_H_
-
-#include <memory>
-#include <string>
-#include <tuple>
-#include <vector>
-
-#include "update_engine/common/error_code.h"
-#include "update_engine/payload_consumer/install_plan.h"
-#include "update_engine/update_manager/evaluation_context.h"
-#include "update_engine/update_manager/rollback_prefs.h"
-#include "update_engine/update_manager/state.h"
-
-namespace chromeos_update_manager {
-
-// The three different results of a policy request.
-enum class EvalStatus {
- kFailed,
- kSucceeded,
- kAskMeAgainLater,
- kContinue,
-};
-
-std::string ToString(EvalStatus status);
-
-// Parameters of an update check. These parameters are determined by the
-// UpdateCheckAllowed policy.
-struct UpdateCheckParams {
- // Whether the auto-updates are enabled on this build.
- bool updates_enabled{true};
-
- // Attributes pertaining to the case where update checks are allowed.
- //
- // A target version prefix, if imposed by policy; otherwise, an empty string.
- std::string target_version_prefix;
- // Specifies whether rollback images are allowed by device policy.
- bool rollback_allowed{false};
- // Specifies if rollbacks should attempt to preserve some system state.
- bool rollback_data_save_requested{false};
- // Specifies the number of Chrome milestones rollback should be allowed,
- // starting from the stable version at any time. Value is -1 if unspecified
- // (e.g. no device policy is available yet), in this case no version
- // roll-forward should happen.
- int rollback_allowed_milestones{0};
- // Whether a rollback with data save should be initiated on channel
- // downgrade (e.g. beta to stable).
- bool rollback_on_channel_downgrade{false};
- // 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;
- // Specifies a token which maps to a Chrome OS Quick Fix Build, if imposed by
- // policy; otherwise, an empty string.
- std::string quick_fix_build_token;
-
- // Whether the allowed update is interactive (user-initiated) or periodic.
- bool interactive{false};
-};
-
-// Input arguments to UpdateCanStart.
-//
-// A snapshot of the state of the current update process. This includes
-// everything that a policy might need and that occurred since the first time
-// the current payload was first seen and attempted (consecutively).
-struct UpdateState {
- // Information pertaining to the current update payload and/or check.
- //
- // Whether the current update check is an interactive one. The caller should
- // feed the value returned by the preceding call to UpdateCheckAllowed().
- bool interactive;
- // Whether it is a delta payload.
- bool is_delta_payload;
- // Wallclock time when payload was first (consecutively) offered by Omaha.
- base::Time first_seen;
- // Number of consecutive update checks returning the current update.
- int num_checks;
- // Number of update payload failures and the wallclock time when it was last
- // updated by the updater. These should both be nullified whenever a new
- // update is seen; they are updated at the policy's descretion (via
- // UpdateDownloadParams.do_increment_failures) once all of the usable download
- // URLs for the payload have been used without success. They should be
- // persisted across reboots.
- int num_failures;
- base::Time failures_last_updated;
-
- // Information pertaining to downloading and applying of the current update.
- //
- // An array of download URLs provided by Omaha.
- std::vector<std::string> download_urls;
- // Max number of errors allowed per download URL.
- int download_errors_max;
- // The index of the URL to download from, as determined in the previous call
- // to the policy. For a newly seen payload, this should be -1.
- int last_download_url_idx;
- // The number of successive download errors pertaining to this last URL, as
- // determined in the previous call to the policy. For a newly seen payload,
- // this should be zero.
- int last_download_url_num_errors;
- // An array of errors that occurred while trying to download this update since
- // the previous call to this policy has returned, or since this payload was
- // first seen, or since the updater process has started (whichever is later).
- // Includes the URL index attempted, the error code, and the wallclock-based
- // timestamp when it occurred.
- std::vector<std::tuple<int, chromeos_update_engine::ErrorCode, base::Time>>
- download_errors;
- // Whether Omaha forbids use of P2P for downloading and/or sharing.
- bool p2p_downloading_disabled;
- bool p2p_sharing_disabled;
- // The number of P2P download attempts and wallclock-based time when P2P
- // download was first attempted.
- int p2p_num_attempts;
- base::Time p2p_first_attempted;
-
- // Information pertaining to update backoff mechanism.
- //
- // The currently known (persisted) wallclock-based backoff expiration time;
- // zero if none.
- base::Time backoff_expiry;
- // Whether backoff is disabled by Omaha.
- bool is_backoff_disabled;
-
- // Information pertaining to update scattering.
- //
- // The currently known (persisted) scattering wallclock-based wait period and
- // update check threshold; zero if none.
- base::TimeDelta scatter_wait_period;
- int scatter_check_threshold;
- // Maximum wait period allowed for this update, as determined by Omaha.
- base::TimeDelta scatter_wait_period_max;
- // Minimum/maximum check threshold values.
- // TODO(garnold) These appear to not be related to the current update and so
- // should probably be obtained as variables via UpdaterProvider.
- int scatter_check_threshold_min;
- int scatter_check_threshold_max;
-};
-
-// Results regarding the downloading and applying of an update, as determined by
-// UpdateCanStart.
-//
-// An enumerator for the reasons of not allowing an update to start.
-enum class UpdateCannotStartReason {
- kUndefined,
- kCheckDue,
- kScattering,
- kBackoff,
- kCannotDownload,
-};
-
-struct UpdateDownloadParams {
- // Whether the update attempt is allowed to proceed.
- bool update_can_start;
- // If update cannot proceed, a reason code for why it cannot do so.
- UpdateCannotStartReason cannot_start_reason;
-
- // Download related attributes. The update engine uses them to choose the
- // means for downloading and applying an update.
- //
- // The index of the download URL to use (-1 means no suitable URL was found)
- // and whether it can be used. Even if there's no URL or its use is not
- // allowed (backoff, scattering) there may still be other means for download
- // (like P2P). The URL index needs to be persisted and handed back to the
- // policy on the next time it is called.
- int download_url_idx;
- bool download_url_allowed;
- // The number of download errors associated with this download URL. This value
- // needs to be persisted and handed back to the policy on the next time it is
- // called.
- int download_url_num_errors;
- // Whether P2P download and sharing are allowed.
- bool p2p_downloading_allowed;
- bool p2p_sharing_allowed;
-
- // Other values that need to be persisted and handed to the policy as need on
- // the next call.
- //
- // Whether an update failure has been identified by the policy. The client
- // should increment and persist its update failure count, and record the time
- // when this was done; it needs to hand these values back to the policy
- // (UpdateState.{num_failures,failures_last_updated}) on the next time it is
- // called.
- bool do_increment_failures;
- // The current backof expiry.
- base::Time backoff_expiry;
- // The scattering wait period and check threshold.
- base::TimeDelta scatter_wait_period;
- int scatter_check_threshold;
-};
-
-// The Policy class is an interface to the ensemble of policy requests that the
-// client can make. A derived class includes the policy implementations of
-// these.
-//
-// When compile-time selection of the policy is required due to missing or extra
-// parts in a given platform, a different Policy subclass can be used.
-class Policy {
- public:
- virtual ~Policy() {}
-
- // Returns the name of a public policy request.
- // IMPORTANT: Be sure to add a conditional for each new public policy that is
- // being added to this class in the future.
- template <typename R, typename... Args>
- std::string PolicyRequestName(EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, Args...) const) const {
- std::string class_name = PolicyName() + "::";
-
- if (reinterpret_cast<typeof(&Policy::UpdateCheckAllowed)>(policy_method) ==
- &Policy::UpdateCheckAllowed)
- return class_name + "UpdateCheckAllowed";
- if (reinterpret_cast<typeof(&Policy::UpdateCanBeApplied)>(policy_method) ==
- &Policy::UpdateCanBeApplied)
- return class_name + "UpdateCanBeApplied";
- if (reinterpret_cast<typeof(&Policy::UpdateCanStart)>(policy_method) ==
- &Policy::UpdateCanStart)
- return class_name + "UpdateCanStart";
- if (reinterpret_cast<typeof(&Policy::P2PEnabled)>(policy_method) ==
- &Policy::P2PEnabled)
- return class_name + "P2PEnabled";
- if (reinterpret_cast<typeof(&Policy::P2PEnabledChanged)>(policy_method) ==
- &Policy::P2PEnabledChanged)
- return class_name + "P2PEnabledChanged";
-
- NOTREACHED();
- return class_name + "(unknown)";
- }
-
- // List of policy requests. A policy request takes an EvaluationContext as the
- // first argument, a State instance, a returned error message, a returned
- // value and optionally followed by one or more arbitrary constant arguments.
- //
- // When the implementation fails, the method returns EvalStatus::kFailed and
- // sets the |error| string.
-
- // UpdateCheckAllowed returns whether it is allowed to request an update check
- // to Omaha.
- virtual EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const = 0;
-
- // UpdateCanBeApplied returns whether the given |install_plan| can be acted
- // on at this time. The reason for not applying is returned in |result|.
- // The Policy may modify the passed-in |install_plan|, based on the
- // implementation in the Policy and values provided by the EvaluationContext.
- virtual EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const = 0;
-
- // Returns EvalStatus::kSucceeded if either an update can start being
- // processed, or the attempt needs to be aborted. In cases where the update
- // needs to wait for some condition to be satisfied, but none of the values
- // that need to be persisted has changed, returns
- // EvalStatus::kAskMeAgainLater. Arguments include an |update_state| that
- // encapsulates data pertaining to the current ongoing update process.
- virtual EvalStatus UpdateCanStart(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateDownloadParams* result,
- UpdateState update_state) const = 0;
-
- // Checks whether P2P is enabled. This may consult device policy and other
- // global settings.
- virtual EvalStatus P2PEnabled(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result) const = 0;
-
- // Checks whether P2P is enabled, but blocks (returns
- // |EvalStatus::kAskMeAgainLater|) until it is different from |prev_result|.
- // If the P2P enabled status is not expected to change, will return
- // immediately with |EvalStatus::kSucceeded|. This internally uses the
- // P2PEnabled() policy above.
- virtual EvalStatus P2PEnabledChanged(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result,
- bool prev_result) const = 0;
-
- protected:
- Policy() {}
-
- // Returns the name of the actual policy class.
- virtual std::string PolicyName() const = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Policy);
-};
-
-// Get system dependent policy implementation.
-std::unique_ptr<Policy> GetSystemPolicy();
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_POLICY_H_
diff --git a/update_manager/policy_test_utils.cc b/update_manager/policy_test_utils.cc
deleted file mode 100644
index e8961b1b..00000000
--- a/update_manager/policy_test_utils.cc
+++ /dev/null
@@ -1,126 +0,0 @@
-//
-// 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/update_manager/policy_test_utils.h"
-
-#include <memory>
-#include <tuple>
-#include <vector>
-
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/next_update_check_policy_impl.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::FakeSystemState;
-using std::string;
-using std::tuple;
-using std::vector;
-
-namespace chromeos_update_manager {
-
-void UmPolicyTestBase::SetUp() {
- loop_.SetAsCurrent();
- FakeSystemState::CreateInstance();
- fake_clock_ = FakeSystemState::Get()->fake_clock();
- SetUpDefaultClock();
- eval_ctx_.reset(new EvaluationContext(TimeDelta::FromSeconds(5)));
- SetUpDefaultState();
-}
-
-void UmPolicyTestBase::TearDown() {
- EXPECT_FALSE(loop_.PendingTasks());
-}
-
-// Sets the clock to fixed values.
-void UmPolicyTestBase::SetUpDefaultClock() {
- fake_clock_->SetMonotonicTime(Time::FromInternalValue(12345678L));
- fake_clock_->SetWallclockTime(Time::FromInternalValue(12345678901234L));
-}
-
-void UmPolicyTestBase::SetUpDefaultTimeProvider() {
- Time current_time = FakeSystemState::Get()->clock()->GetWallclockTime();
- base::Time::Exploded exploded;
- current_time.LocalExplode(&exploded);
- fake_state_.time_provider()->var_curr_hour()->reset(new int(exploded.hour));
- fake_state_.time_provider()->var_curr_minute()->reset(
- new int(exploded.minute));
- fake_state_.time_provider()->var_curr_date()->reset(
- new Time(current_time.LocalMidnight()));
-}
-
-void UmPolicyTestBase::SetUpDefaultState() {
- fake_state_.updater_provider()->var_updater_started_time()->reset(
- new Time(fake_clock_->GetWallclockTime()));
- fake_state_.updater_provider()->var_last_checked_time()->reset(
- new Time(fake_clock_->GetWallclockTime()));
- fake_state_.updater_provider()->var_consecutive_failed_update_checks()->reset(
- new unsigned int(0)); // NOLINT(readability/casting)
- fake_state_.updater_provider()->var_server_dictated_poll_interval()->reset(
- new unsigned int(0)); // NOLINT(readability/casting)
- fake_state_.updater_provider()->var_forced_update_requested()->reset(
- new UpdateRequestStatus{UpdateRequestStatus::kNone});
-
- // Chosen by fair dice roll. Guaranteed to be random.
- fake_state_.random_provider()->var_seed()->reset(new uint64_t(4));
-}
-
-// Returns a default UpdateState structure:
-UpdateState UmPolicyTestBase::GetDefaultUpdateState(
- TimeDelta first_seen_period) {
- Time first_seen_time =
- FakeSystemState::Get()->clock()->GetWallclockTime() - first_seen_period;
- UpdateState update_state = UpdateState();
-
- // This is a non-interactive check returning a delta payload, seen for the
- // first time (|first_seen_period| ago). Clearly, there were no failed
- // attempts so far.
- update_state.interactive = false;
- update_state.is_delta_payload = false;
- update_state.first_seen = first_seen_time;
- update_state.num_checks = 1;
- update_state.num_failures = 0;
- update_state.failures_last_updated = Time(); // Needs to be zero.
- // There's a single HTTP download URL with a maximum of 10 retries.
- update_state.download_urls = vector<string>{"http://fake/url/"};
- update_state.download_errors_max = 10;
- // Download was never attempted.
- update_state.last_download_url_idx = -1;
- update_state.last_download_url_num_errors = 0;
- // There were no download errors.
- update_state.download_errors = vector<tuple<int, ErrorCode, Time>>();
- // P2P is not disabled by Omaha.
- update_state.p2p_downloading_disabled = false;
- update_state.p2p_sharing_disabled = false;
- // P2P was not attempted.
- update_state.p2p_num_attempts = 0;
- update_state.p2p_first_attempted = Time();
- // No active backoff period, backoff is not disabled by Omaha.
- update_state.backoff_expiry = Time();
- update_state.is_backoff_disabled = false;
- // There is no active scattering wait period (max 7 days allowed) nor check
- // threshold (none allowed).
- update_state.scatter_wait_period = TimeDelta();
- update_state.scatter_check_threshold = 0;
- update_state.scatter_wait_period_max = TimeDelta::FromDays(7);
- update_state.scatter_check_threshold_min = 0;
- update_state.scatter_check_threshold_max = 0;
-
- return update_state;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/policy_test_utils.h b/update_manager/policy_test_utils.h
deleted file mode 100644
index 72bd3bc6..00000000
--- a/update_manager/policy_test_utils.h
+++ /dev/null
@@ -1,102 +0,0 @@
-//
-// 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_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
-
-#include <memory>
-#include <string>
-
-#include <base/time/time.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/fake_clock.h"
-#include "update_engine/update_manager/evaluation_context.h"
-#include "update_engine/update_manager/fake_state.h"
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-class UmPolicyTestBase : public ::testing::Test {
- protected:
- UmPolicyTestBase() = default;
-
- void SetUp() override;
-
- void TearDown() override;
-
- // Sets the clock to fixed values.
- virtual void SetUpDefaultClock();
-
- // Sets the fake time provider to the time given by the fake clock.
- virtual void SetUpDefaultTimeProvider();
-
- // Sets up the default state in fake_state_. override to add Policy-specific
- // items, but only after calling this class's implementation.
- virtual void SetUpDefaultState();
-
- // Returns a default UpdateState structure:
- virtual UpdateState GetDefaultUpdateState(base::TimeDelta first_seen_period);
-
- // Runs the passed |method| after resetting the EvaluationContext and expects
- // it to return the |expected| return value.
- template <typename T, typename R, typename... Args>
- void ExpectStatus(EvalStatus expected, T method, R* result, Args... args) {
- std::string error = "<None>";
- eval_ctx_->ResetEvaluation();
- EXPECT_EQ(expected,
- (*method)(eval_ctx_.get(), &fake_state_, &error, result, args...))
- << "Returned error: " << error
- << "\nEvaluation context: " << eval_ctx_->DumpContext();
- }
-
- // Runs the passed |method| after resetting the EvaluationContext, in order
- // to use the method to get a value for other testing (doesn't validate the
- // return value, just returns it).
- template <typename T, typename R, typename... Args>
- EvalStatus CallMethodWithContext(T method, R* result, Args... args) {
- std::string error = "<None>";
- eval_ctx_->ResetEvaluation();
- return (*method)(eval_ctx_.get(), &fake_state_, &error, result, args...);
- }
-
- // Runs the passed |policy_method| on the framework policy and expects it to
- // return the |expected| return value.
- template <typename T, typename R, typename... Args>
- void ExpectPolicyStatus(EvalStatus expected,
- T policy_method,
- R* result,
- Args... args) {
- std::string error = "<None>";
- eval_ctx_->ResetEvaluation();
- EXPECT_EQ(expected,
- (policy_.get()->*policy_method)(
- eval_ctx_.get(), &fake_state_, &error, result, args...))
- << "Returned error: " << error
- << "\nEvaluation context: " << eval_ctx_->DumpContext();
- }
-
- brillo::FakeMessageLoop loop_{nullptr};
- chromeos_update_engine::FakeClock* fake_clock_;
- FakeState fake_state_;
- std::shared_ptr<EvaluationContext> eval_ctx_;
- std::unique_ptr<Policy> policy_;
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_POLICY_TEST_UTILS_H_
diff --git a/update_manager/policy_utils.h b/update_manager/policy_utils.h
deleted file mode 100644
index aedb90cb..00000000
--- a/update_manager/policy_utils.h
+++ /dev/null
@@ -1,113 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_POLICY_UTILS_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_POLICY_UTILS_H_
-
-#include <string>
-#include <vector>
-
-#include "update_engine/update_manager/policy.h"
-
-// Checks that the passed pointer value is not null, returning kFailed on the
-// current context and setting the *error description when it is null. The
-// intended use is to validate variable failures while using
-// EvaluationContext::GetValue, for example:
-//
-// const int* my_value = ec->GetValue(state->my_provider()->var_my_value());
-// POLICY_CHECK_VALUE_AND_FAIL(my_value, error);
-//
-#define POLICY_CHECK_VALUE_AND_FAIL(ptr, error) \
- do { \
- if ((ptr) == nullptr) { \
- *(error) = #ptr " is required but is null."; \
- return EvalStatus::kFailed; \
- } \
- } while (false)
-
-namespace chromeos_update_manager {
-
-// Call the passed-in Policy method on a series of Policy implementations, until
-// one of them renders a decision by returning a value other than
-// |EvalStatus::kContinue|.
-template <typename T, typename R, typename... Args>
-EvalStatus ConsultPolicies(const std::vector<Policy const*> policies,
- T policy_method,
- EvaluationContext* ec,
- State* state,
- std::string* error,
- R* result,
- Args... args) {
- for (auto policy : policies) {
- EvalStatus status =
- (policy->*policy_method)(ec, state, error, result, args...);
- if (status != EvalStatus::kContinue) {
- return status;
- }
- }
- return EvalStatus::kContinue;
-}
-
-// Base class implementation that returns |EvalStatus::kContinue| for all
-// decisions, to be used as a base-class for various Policy facets that only
-// pertain to certain situations. This might be better folded into Policy
-// instead of using pure-virtual methods on that class.
-class PolicyImplBase : public Policy {
- public:
- // Policy overrides.
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateCheckParams* result) const override {
- return EvalStatus::kContinue;
- };
-
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override {
- return EvalStatus::kContinue;
- };
-
- EvalStatus UpdateCanStart(EvaluationContext* ec,
- State* state,
- std::string* error,
- UpdateDownloadParams* result,
- UpdateState update_state) const override {
- return EvalStatus::kContinue;
- };
-
- EvalStatus P2PEnabled(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result) const override {
- return EvalStatus::kContinue;
- };
-
- EvalStatus P2PEnabledChanged(EvaluationContext* ec,
- State* state,
- std::string* error,
- bool* result,
- bool prev_result) const override {
- return EvalStatus::kContinue;
- };
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_POLICY_UTILS_H_
diff --git a/update_manager/prng.h b/update_manager/prng.h
deleted file mode 100644
index 64f886c7..00000000
--- a/update_manager/prng.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_PRNG_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_PRNG_H_
-
-#include <random>
-
-#include <base/logging.h>
-
-namespace chromeos_update_manager {
-
-// A thread-safe, unsecure, 32-bit pseudo-random number generator based on
-// std::mt19937.
-class PRNG {
- public:
- // Initializes the generator with the passed |seed| value.
- explicit PRNG(uint32_t seed) : gen_(seed) {}
-
- // Returns a random unsigned 32-bit integer.
- uint32_t Rand() { return gen_(); }
-
- // Returns a random integer uniformly distributed in the range [min, max].
- int RandMinMax(int min, int max) {
- DCHECK_LE(min, max);
- return std::uniform_int_distribution<>(min, max)(gen_);
- }
-
- private:
- // A pseudo-random number generator.
- std::mt19937 gen_;
-
- DISALLOW_COPY_AND_ASSIGN(PRNG);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_PRNG_H_
diff --git a/update_manager/prng_unittest.cc b/update_manager/prng_unittest.cc
deleted file mode 100644
index cb35f0aa..00000000
--- a/update_manager/prng_unittest.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/prng.h"
-
-#include <vector>
-
-#include <gtest/gtest.h>
-
-using std::vector;
-
-namespace chromeos_update_manager {
-
-TEST(UmPRNGTest, ShouldBeDeterministic) {
- PRNG a(42);
- PRNG b(42);
-
- for (int i = 0; i < 1000; ++i) {
- EXPECT_EQ(a.Rand(), b.Rand()) << "Iteration i=" << i;
- }
-}
-
-TEST(UmPRNGTest, SeedChangesGeneratedSequence) {
- PRNG a(42);
- PRNG b(5);
-
- vector<uint32_t> values_a;
- vector<uint32_t> values_b;
-
- for (int i = 0; i < 100; ++i) {
- values_a.push_back(a.Rand());
- values_b.push_back(b.Rand());
- }
- EXPECT_NE(values_a, values_b);
-}
-
-TEST(UmPRNGTest, IsNotConstant) {
- PRNG prng(5);
-
- uint32_t initial_value = prng.Rand();
- bool prng_is_constant = true;
- for (int i = 0; i < 100; ++i) {
- if (prng.Rand() != initial_value) {
- prng_is_constant = false;
- break;
- }
- }
- EXPECT_FALSE(prng_is_constant) << "After 100 iterations.";
-}
-
-TEST(UmPRNGTest, RandCoversRange) {
- PRNG a(42);
- int hits[11] = {0};
-
- for (int i = 0; i < 1000; i++) {
- int r = a.RandMinMax(0, 10);
- ASSERT_LE(0, r);
- ASSERT_GE(10, r);
- hits[r]++;
- }
-
- for (auto& hit : hits)
- EXPECT_LT(0, hit);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/provider.h b/update_manager/provider.h
deleted file mode 100644
index 84335a24..00000000
--- a/update_manager/provider.h
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_PROVIDER_H_
-
-#include <base/macros.h>
-
-namespace chromeos_update_manager {
-
-// Abstract base class for a policy provider.
-class Provider {
- public:
- virtual ~Provider() {}
-
- protected:
- Provider() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Provider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_PROVIDER_H_
diff --git a/update_manager/random_provider.h b/update_manager/random_provider.h
deleted file mode 100644
index 60df62da..00000000
--- a/update_manager/random_provider.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_RANDOM_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_RANDOM_PROVIDER_H_
-
-#include "update_engine/update_manager/provider.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// Provider of random values.
-class RandomProvider : public Provider {
- public:
- ~RandomProvider() override {}
-
- // Return a random number every time it is requested. Note that values
- // returned by the variables are cached by the EvaluationContext, so the
- // returned value will be the same during the same policy request. If more
- // random values are needed use a PRNG seeded with this value.
- virtual Variable<uint64_t>* var_seed() = 0;
-
- protected:
- RandomProvider() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(RandomProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_RANDOM_PROVIDER_H_
diff --git a/update_manager/real_config_provider.cc b/update_manager/real_config_provider.cc
deleted file mode 100644
index 97e624e0..00000000
--- a/update_manager/real_config_provider.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_config_provider.h"
-
-#include "update_engine/update_manager/generic_variables.h"
-
-namespace chromeos_update_manager {
-
-bool RealConfigProvider::Init() {
- var_is_oobe_enabled_.reset(new ConstCopyVariable<bool>(
- "is_oobe_enabled", hardware_->IsOOBEEnabled()));
-
- return true;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_config_provider.h b/update_manager/real_config_provider.h
deleted file mode 100644
index e79ae606..00000000
--- a/update_manager/real_config_provider.h
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_CONFIG_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_CONFIG_PROVIDER_H_
-
-#include <memory>
-
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/update_manager/config_provider.h"
-#include "update_engine/update_manager/generic_variables.h"
-
-namespace chromeos_update_manager {
-
-// ConfigProvider concrete implementation.
-class RealConfigProvider : public ConfigProvider {
- public:
- explicit RealConfigProvider(
- chromeos_update_engine::HardwareInterface* hardware)
- : hardware_(hardware) {}
-
- // Initializes the provider and returns whether it succeeded.
- bool Init();
-
- Variable<bool>* var_is_oobe_enabled() override {
- return var_is_oobe_enabled_.get();
- }
-
- private:
- std::unique_ptr<ConstCopyVariable<bool>> var_is_oobe_enabled_;
-
- chromeos_update_engine::HardwareInterface* hardware_;
-
- DISALLOW_COPY_AND_ASSIGN(RealConfigProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_CONFIG_PROVIDER_H_
diff --git a/update_manager/real_device_policy_provider.cc b/update_manager/real_device_policy_provider.cc
deleted file mode 100644
index e7b964b0..00000000
--- a/update_manager/real_device_policy_provider.cc
+++ /dev/null
@@ -1,273 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_device_policy_provider.h"
-
-#include <stdint.h>
-
-#include <vector>
-
-#include <base/location.h>
-#include <base/logging.h>
-#include <base/time/time.h>
-#include <policy/device_policy.h>
-
-#include "update_engine/common/connection_utils.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/update_manager/generic_variables.h"
-
-using base::TimeDelta;
-using brillo::MessageLoop;
-using chromeos_update_engine::ConnectionType;
-using policy::DevicePolicy;
-using std::set;
-using std::string;
-using std::vector;
-
-namespace {
-
-const int kDevicePolicyRefreshRateInMinutes = 60;
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-RealDevicePolicyProvider::~RealDevicePolicyProvider() {
- MessageLoop::current()->CancelTask(scheduled_refresh_);
-}
-
-bool RealDevicePolicyProvider::Init() {
- CHECK(policy_provider_ != nullptr);
-
- // On Init() we try to get the device policy and keep updating it.
- RefreshDevicePolicyAndReschedule();
-
-#if USE_DBUS
- // We also listen for signals from the session manager to force a device
- // policy refresh.
- session_manager_proxy_->RegisterPropertyChangeCompleteSignalHandler(
- base::Bind(&RealDevicePolicyProvider::OnPropertyChangedCompletedSignal,
- base::Unretained(this)),
- base::Bind(&RealDevicePolicyProvider::OnSignalConnected,
- base::Unretained(this)));
-#endif // USE_DBUS
- return true;
-}
-
-void RealDevicePolicyProvider::OnPropertyChangedCompletedSignal(
- const string& success) {
- if (success != "success") {
- LOG(WARNING) << "Received device policy updated signal with a failure.";
- }
- // We refresh the policy file even if the payload string is kSignalFailure.
- LOG(INFO) << "Reloading and re-scheduling device policy due to signal "
- "received.";
- MessageLoop::current()->CancelTask(scheduled_refresh_);
- scheduled_refresh_ = MessageLoop::kTaskIdNull;
- RefreshDevicePolicyAndReschedule();
-}
-
-void RealDevicePolicyProvider::OnSignalConnected(const string& interface_name,
- const string& signal_name,
- bool successful) {
- if (!successful) {
- LOG(WARNING) << "We couldn't connect to SessionManager signal for updates "
- "on the device policy blob. We will reload the policy file "
- "periodically.";
- }
- // We do a one-time refresh of the DevicePolicy just in case we missed a
- // signal between the first refresh and the time the signal handler was
- // actually connected.
- RefreshDevicePolicy();
-}
-
-void RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule() {
- RefreshDevicePolicy();
- scheduled_refresh_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&RealDevicePolicyProvider::RefreshDevicePolicyAndReschedule,
- base::Unretained(this)),
- TimeDelta::FromMinutes(kDevicePolicyRefreshRateInMinutes));
-}
-
-template <typename T>
-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)) {
- var->SetValue(new_value);
- } else {
- var->UnsetValue();
- }
-}
-
-template <typename T>
-void RealDevicePolicyProvider::UpdateVariable(
- AsyncCopyVariable<T>* var,
- bool (RealDevicePolicyProvider::*getter)(T*) const) {
- T new_value;
- if (policy_provider_->device_policy_is_loaded() &&
- (this->*getter)(&new_value)) {
- var->SetValue(new_value);
- } else {
- var->UnsetValue();
- }
-}
-
-bool RealDevicePolicyProvider::ConvertRollbackToTargetVersion(
- RollbackToTargetVersion* rollback_to_target_version) const {
- int rollback_to_target_version_int;
- if (!policy_provider_->GetDevicePolicy().GetRollbackToTargetVersion(
- &rollback_to_target_version_int)) {
- return false;
- }
- if (rollback_to_target_version_int < 0 ||
- rollback_to_target_version_int >=
- static_cast<int>(RollbackToTargetVersion::kMaxValue)) {
- return false;
- }
- *rollback_to_target_version =
- static_cast<RollbackToTargetVersion>(rollback_to_target_version_int);
- return true;
-}
-
-bool RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate(
- set<ConnectionType>* allowed_types) const {
- set<string> allowed_types_str;
- if (!policy_provider_->GetDevicePolicy().GetAllowedConnectionTypesForUpdate(
- &allowed_types_str)) {
- return false;
- }
- allowed_types->clear();
- for (auto& type_str : allowed_types_str) {
- ConnectionType type =
- chromeos_update_engine::connection_utils::ParseConnectionType(type_str);
- if (type != ConnectionType::kUnknown) {
- allowed_types->insert(type);
- } else {
- LOG(WARNING) << "Policy includes unknown connection type: " << type_str;
- }
- }
- return true;
-}
-
-bool RealDevicePolicyProvider::ConvertScatterFactor(
- TimeDelta* scatter_factor) const {
- int64_t scatter_factor_in_seconds;
- if (!policy_provider_->GetDevicePolicy().GetScatterFactorInSeconds(
- &scatter_factor_in_seconds)) {
- return false;
- }
- if (scatter_factor_in_seconds < 0) {
- LOG(WARNING) << "Ignoring negative scatter factor: "
- << scatter_factor_in_seconds;
- return false;
- }
- *scatter_factor = TimeDelta::FromSeconds(scatter_factor_in_seconds);
- return true;
-}
-
-bool RealDevicePolicyProvider::ConvertDisallowedTimeIntervals(
- WeeklyTimeIntervalVector* disallowed_intervals_out) const {
- vector<DevicePolicy::WeeklyTimeInterval> parsed_intervals;
- if (!policy_provider_->GetDevicePolicy().GetDisallowedTimeIntervals(
- &parsed_intervals)) {
- return false;
- }
-
- disallowed_intervals_out->clear();
- for (const auto& interval : parsed_intervals) {
- disallowed_intervals_out->emplace_back(
- WeeklyTime(interval.start_day_of_week, interval.start_time),
- WeeklyTime(interval.end_day_of_week, interval.end_time));
- }
- return true;
-}
-
-bool RealDevicePolicyProvider::ConvertHasOwner(bool* has_owner) const {
- string owner;
- if (!policy_provider_->GetDevicePolicy().GetOwner(&owner)) {
- return false;
- }
- *has_owner = !owner.empty();
- 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.";
- }
-
- var_device_policy_is_loaded_.SetValue(
- policy_provider_->device_policy_is_loaded());
-
- 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);
- UpdateVariable(&var_rollback_to_target_version_,
- &RealDevicePolicyProvider::ConvertRollbackToTargetVersion);
- UpdateVariable(&var_rollback_allowed_milestones_,
- &DevicePolicy::GetRollbackAllowedMilestones);
- if (policy_provider_->IsConsumerDevice()) {
- // For consumer devices (which won't ever have policy), set value to 0.
- var_rollback_allowed_milestones_.SetValue(0);
- }
- UpdateVariable(&var_scatter_factor_,
- &RealDevicePolicyProvider::ConvertScatterFactor);
- UpdateVariable(
- &var_allowed_connection_types_for_update_,
- &RealDevicePolicyProvider::ConvertAllowedConnectionTypesForUpdate);
- UpdateVariable(&var_has_owner_, &RealDevicePolicyProvider::ConvertHasOwner);
- UpdateVariable(&var_http_downloads_enabled_,
- &DevicePolicy::GetHttpDownloadsEnabled);
- UpdateVariable(&var_au_p2p_enabled_, &DevicePolicy::GetAuP2PEnabled);
- UpdateVariable(&var_allow_kiosk_app_control_chrome_version_,
- &DevicePolicy::GetAllowKioskAppControlChromeVersion);
- UpdateVariable(&var_auto_launched_kiosk_app_id_,
- &DevicePolicy::GetAutoLaunchedKioskAppId);
- UpdateVariable(&var_disallowed_time_intervals_,
- &RealDevicePolicyProvider::ConvertDisallowedTimeIntervals);
- UpdateVariable(&var_channel_downgrade_behavior_,
- &RealDevicePolicyProvider::ConvertChannelDowngradeBehavior);
- UpdateVariable(&var_device_minimum_version_,
- &DevicePolicy::GetHighestDeviceMinimumVersion);
- UpdateVariable(&var_quick_fix_build_token_,
- &DevicePolicy::GetDeviceQuickFixBuildToken);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_device_policy_provider.h b/update_manager/real_device_policy_provider.h
deleted file mode 100644
index 0f84b770..00000000
--- a/update_manager/real_device_policy_provider.h
+++ /dev/null
@@ -1,249 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
-
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-
-#include <brillo/message_loops/message_loop.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-#include <policy/libpolicy.h>
-#if USE_DBUS
-#include <session_manager/dbus-proxies.h>
-#endif // USE_DBUS
-
-#include "update_engine/update_manager/device_policy_provider.h"
-#include "update_engine/update_manager/generic_variables.h"
-
-namespace chromeos_update_manager {
-
-// |DevicePolicyProvider| concrete implementation.
-class RealDevicePolicyProvider : public DevicePolicyProvider {
- public:
-#if USE_DBUS
- RealDevicePolicyProvider(
- std::unique_ptr<org::chromium::SessionManagerInterfaceProxyInterface>
- session_manager_proxy,
- policy::PolicyProvider* policy_provider)
- : policy_provider_(policy_provider),
- session_manager_proxy_(std::move(session_manager_proxy)) {}
-#endif // USE_DBUS
- explicit RealDevicePolicyProvider(policy::PolicyProvider* policy_provider)
- : policy_provider_(policy_provider) {}
- ~RealDevicePolicyProvider();
-
- // Initializes the provider and returns whether it succeeded.
- bool Init();
-
- Variable<bool>* var_device_policy_is_loaded() override {
- return &var_device_policy_is_loaded_;
- }
-
- Variable<std::string>* var_release_channel() override {
- return &var_release_channel_;
- }
-
- Variable<bool>* var_release_channel_delegated() override {
- 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_;
- }
-
- Variable<std::string>* var_target_version_prefix() override {
- return &var_target_version_prefix_;
- }
-
- Variable<RollbackToTargetVersion>* var_rollback_to_target_version() override {
- return &var_rollback_to_target_version_;
- }
-
- Variable<int>* var_rollback_allowed_milestones() override {
- return &var_rollback_allowed_milestones_;
- }
-
- Variable<base::TimeDelta>* var_scatter_factor() override {
- return &var_scatter_factor_;
- }
-
- Variable<std::set<chromeos_update_engine::ConnectionType>>*
- var_allowed_connection_types_for_update() override {
- return &var_allowed_connection_types_for_update_;
- }
-
- Variable<bool>* var_has_owner() override { return &var_has_owner_; }
-
- Variable<bool>* var_http_downloads_enabled() override {
- return &var_http_downloads_enabled_;
- }
-
- Variable<bool>* var_au_p2p_enabled() override { return &var_au_p2p_enabled_; }
-
- Variable<bool>* var_allow_kiosk_app_control_chrome_version() override {
- return &var_allow_kiosk_app_control_chrome_version_;
- }
-
- Variable<std::string>* var_auto_launched_kiosk_app_id() override {
- return &var_auto_launched_kiosk_app_id_;
- }
-
- Variable<WeeklyTimeIntervalVector>* var_disallowed_time_intervals() override {
- 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_;
- }
-
- Variable<std::string>* var_quick_fix_build_token() override {
- return &var_quick_fix_build_token_;
- }
-
- private:
- FRIEND_TEST(UmRealDevicePolicyProviderTest, RefreshScheduledTest);
- FRIEND_TEST(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded);
- FRIEND_TEST(UmRealDevicePolicyProviderTest, ValuesUpdated);
- FRIEND_TEST(UmRealDevicePolicyProviderTest, HasOwnerConverted);
-
- // A static handler for the |PropertyChangedCompleted| signal from the session
- // manager used as a callback.
- void OnPropertyChangedCompletedSignal(const std::string& success);
-
- // Called when the signal in |UpdateEngineLibcrosProxyResolvedInterface| is
- // connected.
- void OnSignalConnected(const std::string& interface_name,
- const std::string& signal_name,
- bool successful);
-
- // Schedules a call to periodically refresh the device policy.
- void RefreshDevicePolicyAndReschedule();
-
- // Reloads the device policy and updates all the exposed variables.
- void RefreshDevicePolicy();
-
- // Updates the async variable |var| based on the result value of the method
- // passed, which is a DevicePolicy getter method.
- template <typename T>
- void UpdateVariable(AsyncCopyVariable<T>* var,
- bool (policy::DevicePolicy::*getter)(T*) const);
-
- // Updates the async variable |var| based on the result value of the getter
- // method passed, which is a wrapper getter on this class.
- template <typename T>
- void UpdateVariable(AsyncCopyVariable<T>* var,
- bool (RealDevicePolicyProvider::*getter)(T*) const);
-
- // Wrapper for |DevicePolicy::GetRollbackToTargetVersion()| that converts the
- // result to |RollbackToTargetVersion|.
- bool ConvertRollbackToTargetVersion(
- RollbackToTargetVersion* rollback_to_target_version) const;
-
- // Wrapper for |DevicePolicy::GetScatterFactorInSeconds()| that converts the
- // result to a |base::TimeDelta|. It returns the same value as
- // |GetScatterFactorInSeconds()|.
- bool ConvertScatterFactor(base::TimeDelta* scatter_factor) const;
-
- // Wrapper for |DevicePolicy::GetAllowedConnectionTypesForUpdate()| that
- // converts the result to a set of |ConnectionType| elements instead of
- // strings.
- bool ConvertAllowedConnectionTypesForUpdate(
- std::set<chromeos_update_engine::ConnectionType>* allowed_types) const;
-
- // Wrapper for |DevicePolicy::GetUpdateTimeRestrictions()| that converts
- // the |DevicePolicy::WeeklyTimeInterval| structs to |WeeklyTimeInterval|
- // objects, which offer more functionality.
- bool ConvertDisallowedTimeIntervals(
- WeeklyTimeIntervalVector* disallowed_intervals_out) const;
-
- // Wrapper for |DevicePolicy::GetOwner()| that converts the result to a
- // boolean of whether the device has an owner. (Enterprise enrolled
- // 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_;
-
- // Used to schedule refreshes of the device policy.
- brillo::MessageLoop::TaskId scheduled_refresh_{
- brillo::MessageLoop::kTaskIdNull};
-
-#if USE_DBUS
- // The DBus (mockable) session manager proxy.
- std::unique_ptr<org::chromium::SessionManagerInterfaceProxyInterface>
- session_manager_proxy_;
-#endif // USE_DBUS
-
- // Variable exposing whether the policy is loaded.
- AsyncCopyVariable<bool> var_device_policy_is_loaded_{"policy_is_loaded",
- false};
-
- // Variables mapping the exposed methods from the |policy::DevicePolicy|.
- 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"};
- AsyncCopyVariable<RollbackToTargetVersion> var_rollback_to_target_version_{
- "rollback_to_target_version"};
- AsyncCopyVariable<int> var_rollback_allowed_milestones_{
- "rollback_allowed_milestones"};
- AsyncCopyVariable<base::TimeDelta> var_scatter_factor_{"scatter_factor"};
- AsyncCopyVariable<std::set<chromeos_update_engine::ConnectionType>>
- var_allowed_connection_types_for_update_{
- "allowed_connection_types_for_update"};
- AsyncCopyVariable<bool> var_has_owner_{"owner"};
- AsyncCopyVariable<bool> var_http_downloads_enabled_{"http_downloads_enabled"};
- AsyncCopyVariable<bool> var_au_p2p_enabled_{"au_p2p_enabled"};
- AsyncCopyVariable<bool> var_allow_kiosk_app_control_chrome_version_{
- "allow_kiosk_app_control_chrome_version"};
- AsyncCopyVariable<WeeklyTimeIntervalVector> var_disallowed_time_intervals_{
- "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"};
- AsyncCopyVariable<std::string> var_quick_fix_build_token_{
- "quick_fix_build_token"};
-
- DISALLOW_COPY_AND_ASSIGN(RealDevicePolicyProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_DEVICE_POLICY_PROVIDER_H_
diff --git a/update_manager/real_device_policy_provider_unittest.cc b/update_manager/real_device_policy_provider_unittest.cc
deleted file mode 100644
index fd558594..00000000
--- a/update_manager/real_device_policy_provider_unittest.cc
+++ /dev/null
@@ -1,462 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_device_policy_provider.h"
-
-#include <memory>
-#include <vector>
-
-#include <base/memory/ptr_util.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <policy/mock_device_policy.h>
-#include <policy/mock_libpolicy.h>
-#if USE_DBUS
-#include <session_manager/dbus-proxies.h>
-#include <session_manager/dbus-proxy-mocks.h>
-#endif // USE_DBUS
-
-#include "update_engine/common/test_utils.h"
-#if USE_DBUS
-#include "update_engine/cros/dbus_test_utils.h"
-#endif // USE_DBUS
-#include "update_engine/update_manager/umtest_utils.h"
-
-using base::TimeDelta;
-using brillo::MessageLoop;
-using chromeos_update_engine::ConnectionType;
-using policy::DevicePolicy;
-#if USE_DBUS
-using chromeos_update_engine::dbus_test_utils::MockSignalHandler;
-#endif // USE_DBUS
-using std::set;
-using std::string;
-using std::unique_ptr;
-using std::vector;
-using testing::_;
-using testing::DoAll;
-using testing::Mock;
-using testing::Return;
-using testing::ReturnRef;
-using testing::SetArgPointee;
-
-namespace chromeos_update_manager {
-
-class UmRealDevicePolicyProviderTest : public ::testing::Test {
- protected:
- void SetUp() override {
- loop_.SetAsCurrent();
-#if USE_DBUS
- auto session_manager_proxy_mock =
- new org::chromium::SessionManagerInterfaceProxyMock();
- provider_.reset(new RealDevicePolicyProvider(
- base::WrapUnique(session_manager_proxy_mock), &mock_policy_provider_));
-#else
- provider_.reset(new RealDevicePolicyProvider(&mock_policy_provider_));
-#endif // USE_DBUS
- // By default, we have a device policy loaded. Tests can call
- // SetUpNonExistentDevicePolicy() to override this.
- SetUpExistentDevicePolicy();
-
-#if USE_DBUS
- // Setup the session manager_proxy such that it will accept the signal
- // handler and store it in the |property_change_complete_| once registered.
- MOCK_SIGNAL_HANDLER_EXPECT_SIGNAL_HANDLER(property_change_complete_,
- *session_manager_proxy_mock,
- PropertyChangeComplete);
-#endif // USE_DBUS
- }
-
- void TearDown() override {
- provider_.reset();
- // Check for leaked callbacks on the main loop.
- EXPECT_FALSE(loop_.PendingTasks());
- }
-
- void SetUpNonExistentDevicePolicy() {
- ON_CALL(mock_policy_provider_, Reload()).WillByDefault(Return(false));
- ON_CALL(mock_policy_provider_, device_policy_is_loaded())
- .WillByDefault(Return(false));
- EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0);
- }
-
- void SetUpExistentDevicePolicy() {
- // Setup the default behavior of the mocked PolicyProvider.
- ON_CALL(mock_policy_provider_, Reload()).WillByDefault(Return(true));
- ON_CALL(mock_policy_provider_, device_policy_is_loaded())
- .WillByDefault(Return(true));
- ON_CALL(mock_policy_provider_, GetDevicePolicy())
- .WillByDefault(ReturnRef(mock_device_policy_));
- }
-
- brillo::FakeMessageLoop loop_{nullptr};
- testing::NiceMock<policy::MockDevicePolicy> mock_device_policy_;
- testing::NiceMock<policy::MockPolicyProvider> mock_policy_provider_;
- unique_ptr<RealDevicePolicyProvider> provider_;
-
-#if USE_DBUS
- // The registered signal handler for the signal.
- MockSignalHandler<void(const string&)> property_change_complete_;
-#endif // USE_DBUS
-};
-
-TEST_F(UmRealDevicePolicyProviderTest, RefreshScheduledTest) {
- // Check that the RefreshPolicy gets scheduled by checking the TaskId.
- EXPECT_TRUE(provider_->Init());
- EXPECT_NE(MessageLoop::kTaskIdNull, provider_->scheduled_refresh_);
- loop_.RunOnce(false);
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, FirstReload) {
- // Checks that the policy is reloaded and the DevicePolicy is consulted twice:
- // once on Init() and once again when the signal is connected.
- EXPECT_CALL(mock_policy_provider_, Reload());
- EXPECT_TRUE(provider_->Init());
- Mock::VerifyAndClearExpectations(&mock_policy_provider_);
- // We won't be notified that signal is connected without DBus.
-#if USE_DBUS
- EXPECT_CALL(mock_policy_provider_, Reload());
-#endif // USE_DBUS
- loop_.RunOnce(false);
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyReloaded) {
- // Checks that the policy is reloaded by RefreshDevicePolicy().
- SetUpNonExistentDevicePolicy();
- // We won't be notified that signal is connected without DBus.
-#if USE_DBUS
- EXPECT_CALL(mock_policy_provider_, Reload()).Times(3);
-#else
- EXPECT_CALL(mock_policy_provider_, Reload()).Times(2);
-#endif // USE_DBUS
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
- // Force the policy refresh.
- provider_->RefreshDevicePolicy();
-}
-
-#if USE_DBUS
-TEST_F(UmRealDevicePolicyProviderTest, SessionManagerSignalForcesReload) {
- // Checks that a signal from the SessionManager forces a reload.
- SetUpNonExistentDevicePolicy();
- EXPECT_CALL(mock_policy_provider_, Reload()).Times(2);
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
- Mock::VerifyAndClearExpectations(&mock_policy_provider_);
-
- EXPECT_CALL(mock_policy_provider_, Reload());
- ASSERT_TRUE(property_change_complete_.IsHandlerRegistered());
- property_change_complete_.signal_callback().Run("success");
-}
-#endif // USE_DBUS
-
-TEST_F(UmRealDevicePolicyProviderTest, NonExistentDevicePolicyEmptyVariables) {
- SetUpNonExistentDevicePolicy();
- EXPECT_CALL(mock_policy_provider_, GetDevicePolicy()).Times(0);
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(false,
- provider_->var_device_policy_is_loaded());
-
- 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(
- provider_->var_rollback_to_target_version());
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_rollback_allowed_milestones());
- UmTestUtils::ExpectVariableNotSet(provider_->var_scatter_factor());
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_allowed_connection_types_for_update());
- UmTestUtils::ExpectVariableNotSet(provider_->var_has_owner());
- UmTestUtils::ExpectVariableNotSet(provider_->var_http_downloads_enabled());
- UmTestUtils::ExpectVariableNotSet(provider_->var_au_p2p_enabled());
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_allow_kiosk_app_control_chrome_version());
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_auto_launched_kiosk_app_id());
- UmTestUtils::ExpectVariableNotSet(provider_->var_disallowed_time_intervals());
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_channel_downgrade_behavior());
- UmTestUtils::ExpectVariableNotSet(provider_->var_quick_fix_build_token());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, ValuesUpdated) {
- SetUpNonExistentDevicePolicy();
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
- Mock::VerifyAndClearExpectations(&mock_policy_provider_);
-
- // Reload the policy with a good one and set some values as present. The
- // remaining values are false.
- SetUpExistentDevicePolicy();
- EXPECT_CALL(mock_device_policy_, GetReleaseChannel(_))
- .WillOnce(DoAll(SetArgPointee<0>(string("mychannel")), Return(true)));
- EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_))
- .WillOnce(Return(false));
- EXPECT_CALL(mock_device_policy_, GetAllowKioskAppControlChromeVersion(_))
- .WillOnce(DoAll(SetArgPointee<0>(true), Return(true)));
- EXPECT_CALL(mock_device_policy_, GetAutoLaunchedKioskAppId(_))
- .WillOnce(DoAll(SetArgPointee<0>(string("myapp")), Return(true)));
-
- provider_->RefreshDevicePolicy();
-
- UmTestUtils::ExpectVariableHasValue(true,
- provider_->var_device_policy_is_loaded());
-
- // Test that at least one variable is set, to ensure the refresh occurred.
- UmTestUtils::ExpectVariableHasValue(string("mychannel"),
- provider_->var_release_channel());
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_allowed_connection_types_for_update());
- UmTestUtils::ExpectVariableHasValue(
- true, provider_->var_allow_kiosk_app_control_chrome_version());
- UmTestUtils::ExpectVariableHasValue(
- string("myapp"), provider_->var_auto_launched_kiosk_app_id());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, HasOwnerConverted) {
- SetUpExistentDevicePolicy();
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
- Mock::VerifyAndClearExpectations(&mock_policy_provider_);
-
- EXPECT_CALL(mock_device_policy_, GetOwner(_))
- .Times(2)
- .WillOnce(DoAll(SetArgPointee<0>(string("")), Return(true)))
- .WillOnce(DoAll(SetArgPointee<0>(string("abc@test.org")), Return(true)));
-
- // Enterprise enrolled device.
- provider_->RefreshDevicePolicy();
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_has_owner());
-
- // Has a device owner.
- provider_->RefreshDevicePolicy();
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_has_owner());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, RollbackToTargetVersionConverted) {
- SetUpExistentDevicePolicy();
- EXPECT_CALL(mock_device_policy_, GetRollbackToTargetVersion(_))
-#if USE_DBUS
- .Times(2)
-#else
- .Times(1)
-#endif // USE_DBUS
- .WillRepeatedly(DoAll(SetArgPointee<0>(2), Return(true)));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(
- RollbackToTargetVersion::kRollbackAndPowerwash,
- provider_->var_rollback_to_target_version());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, RollbackAllowedMilestonesOobe) {
- SetUpNonExistentDevicePolicy();
- EXPECT_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_)).Times(0);
- ON_CALL(mock_policy_provider_, IsConsumerDevice())
- .WillByDefault(Return(false));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_rollback_allowed_milestones());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, RollbackAllowedMilestonesConsumer) {
- SetUpNonExistentDevicePolicy();
- EXPECT_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_)).Times(0);
- ON_CALL(mock_policy_provider_, IsConsumerDevice())
- .WillByDefault(Return(true));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(
- 0, provider_->var_rollback_allowed_milestones());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest,
- RollbackAllowedMilestonesEnterprisePolicySet) {
- SetUpExistentDevicePolicy();
- ON_CALL(mock_device_policy_, GetRollbackAllowedMilestones(_))
- .WillByDefault(DoAll(SetArgPointee<0>(2), Return(true)));
- ON_CALL(mock_policy_provider_, IsConsumerDevice())
- .WillByDefault(Return(false));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(
- 2, provider_->var_rollback_allowed_milestones());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, ScatterFactorConverted) {
- SetUpExistentDevicePolicy();
- EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_))
-#if USE_DBUS
- .Times(2)
-#else
- .Times(1)
-#endif // USE_DBUS
- .WillRepeatedly(DoAll(SetArgPointee<0>(1234), Return(true)));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(TimeDelta::FromSeconds(1234),
- provider_->var_scatter_factor());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, NegativeScatterFactorIgnored) {
- SetUpExistentDevicePolicy();
- EXPECT_CALL(mock_device_policy_, GetScatterFactorInSeconds(_))
-#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_scatter_factor());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, AllowedTypesConverted) {
- SetUpExistentDevicePolicy();
- EXPECT_CALL(mock_device_policy_, GetAllowedConnectionTypesForUpdate(_))
-#if USE_DBUS
- .Times(2)
-#else
- .Times(1)
-#endif // USE_DBUS
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(set<string>{"ethernet", "wifi", "not-a-type"}),
- Return(true)));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(
- set<ConnectionType>{ConnectionType::kWifi, ConnectionType::kEthernet},
- provider_->var_allowed_connection_types_for_update());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, DisallowedIntervalsConverted) {
- SetUpExistentDevicePolicy();
-
- vector<DevicePolicy::WeeklyTimeInterval> intervals = {
- {5, TimeDelta::FromHours(5), 6, TimeDelta::FromHours(8)},
- {1, TimeDelta::FromHours(1), 3, TimeDelta::FromHours(10)}};
-
- EXPECT_CALL(mock_device_policy_, GetDisallowedTimeIntervals(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(intervals), Return(true)));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(
- WeeklyTimeIntervalVector{
- WeeklyTimeInterval(WeeklyTime(5, TimeDelta::FromHours(5)),
- WeeklyTime(6, TimeDelta::FromHours(8))),
- WeeklyTimeInterval(WeeklyTime(1, TimeDelta::FromHours(1)),
- WeeklyTime(3, TimeDelta::FromHours(10)))},
- 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());
-}
-
-TEST_F(UmRealDevicePolicyProviderTest, DeviceQuickFixBuildTokenSet) {
- SetUpExistentDevicePolicy();
-
- EXPECT_CALL(mock_device_policy_, GetDeviceQuickFixBuildToken(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(string("some_token")), Return(true)));
- EXPECT_TRUE(provider_->Init());
- loop_.RunOnce(false);
-
- UmTestUtils::ExpectVariableHasValue(string("some_token"),
- provider_->var_quick_fix_build_token());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_random_provider.cc b/update_manager/real_random_provider.cc
deleted file mode 100644
index ed0eb4d2..00000000
--- a/update_manager/real_random_provider.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_random_provider.h"
-
-#include <stdio.h>
-#include <unistd.h>
-
-#include <string>
-
-#include <base/files/file_path.h>
-#include <base/files/scoped_file.h>
-#include <base/strings/stringprintf.h>
-
-#include "update_engine/update_manager/variable.h"
-
-using std::string;
-
-namespace {
-
-// The device providing randomness.
-const char* kRandomDevice = "/dev/urandom";
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-// A random seed variable.
-class RandomSeedVariable : public Variable<uint64_t> {
- public:
- // RandomSeedVariable is initialized as kVariableModeConst to let the
- // EvaluationContext cache the value between different evaluations of the same
- // policy request.
- RandomSeedVariable(const string& name, FILE* fp)
- : Variable<uint64_t>(name, kVariableModeConst), fp_(fp) {}
- ~RandomSeedVariable() override {}
-
- protected:
- const uint64_t* GetValue(base::TimeDelta /* timeout */,
- string* errmsg) override {
- uint64_t result;
- // Aliasing via char pointer abides by the C/C++ strict-aliasing rules.
- char* const buf = reinterpret_cast<char*>(&result);
- unsigned int buf_rd = 0;
-
- while (buf_rd < sizeof(result)) {
- int rd = fread(buf + buf_rd, 1, sizeof(result) - buf_rd, fp_.get());
- if (rd == 0 || ferror(fp_.get())) {
- // Either EOF on fp or read failed.
- if (errmsg) {
- *errmsg = base::StringPrintf(
- "Error reading from the random device: %s", kRandomDevice);
- }
- return nullptr;
- }
- buf_rd += rd;
- }
-
- return new uint64_t(result);
- }
-
- private:
- base::ScopedFILE fp_;
-
- DISALLOW_COPY_AND_ASSIGN(RandomSeedVariable);
-};
-
-bool RealRandomProvider::Init(void) {
- FILE* fp = fopen(kRandomDevice, "r");
- if (!fp)
- return false;
- var_seed_.reset(new RandomSeedVariable("seed", fp));
- return true;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_random_provider.h b/update_manager/real_random_provider.h
deleted file mode 100644
index 14ce7a3a..00000000
--- a/update_manager/real_random_provider.h
+++ /dev/null
@@ -1,45 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_RANDOM_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_RANDOM_PROVIDER_H_
-
-#include <memory>
-
-#include "update_engine/update_manager/random_provider.h"
-
-namespace chromeos_update_manager {
-
-// RandomProvider implementation class.
-class RealRandomProvider : public RandomProvider {
- public:
- RealRandomProvider() {}
-
- Variable<uint64_t>* var_seed() override { return var_seed_.get(); }
-
- // Initializes the provider and returns whether it succeeded.
- bool Init();
-
- private:
- // The seed() scoped variable.
- std::unique_ptr<Variable<uint64_t>> var_seed_;
-
- DISALLOW_COPY_AND_ASSIGN(RealRandomProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_RANDOM_PROVIDER_H_
diff --git a/update_manager/real_random_provider_unittest.cc b/update_manager/real_random_provider_unittest.cc
deleted file mode 100644
index 1b220639..00000000
--- a/update_manager/real_random_provider_unittest.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_random_provider.h"
-
-#include <gtest/gtest.h>
-
-#include <memory>
-
-#include "update_engine/update_manager/umtest_utils.h"
-
-using std::unique_ptr;
-
-namespace chromeos_update_manager {
-
-class UmRealRandomProviderTest : public ::testing::Test {
- protected:
- void SetUp() override {
- // The provider initializes correctly.
- provider_.reset(new RealRandomProvider());
- ASSERT_NE(nullptr, provider_.get());
- ASSERT_TRUE(provider_->Init());
-
- provider_->var_seed();
- }
-
- unique_ptr<RealRandomProvider> provider_;
-};
-
-TEST_F(UmRealRandomProviderTest, InitFinalize) {
- // The provider initializes all variables with valid objects.
- EXPECT_NE(nullptr, provider_->var_seed());
-}
-
-TEST_F(UmRealRandomProviderTest, GetRandomValues) {
- // Should not return the same random seed repeatedly.
- unique_ptr<const uint64_t> value(
- provider_->var_seed()->GetValue(UmTestUtils::DefaultTimeout(), nullptr));
- ASSERT_NE(nullptr, value.get());
-
- // Test that at least the returned values are different. This test fails,
- // by design, once every 2^320 runs.
- bool is_same_value = true;
- for (int i = 0; i < 5; i++) {
- unique_ptr<const uint64_t> other_value(provider_->var_seed()->GetValue(
- UmTestUtils::DefaultTimeout(), nullptr));
- ASSERT_NE(nullptr, other_value.get());
- is_same_value = is_same_value && *other_value == *value;
- }
- EXPECT_FALSE(is_same_value);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_shill_provider.cc b/update_manager/real_shill_provider.cc
deleted file mode 100644
index 4d067fd4..00000000
--- a/update_manager/real_shill_provider.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_shill_provider.h"
-
-#include <string>
-
-#include <base/logging.h>
-#include <base/strings/stringprintf.h>
-#include <brillo/type_name_undecorate.h>
-#include <shill/dbus-constants.h>
-#include <shill/dbus-proxies.h>
-
-using chromeos_update_engine::SystemState;
-using chromeos_update_engine::connection_utils::ParseConnectionType;
-using org::chromium::flimflam::ManagerProxyInterface;
-using org::chromium::flimflam::ServiceProxyInterface;
-using std::string;
-
-namespace chromeos_update_manager {
-
-bool RealShillProvider::Init() {
- ManagerProxyInterface* manager_proxy = shill_proxy_->GetManagerProxy();
- if (!manager_proxy)
- return false;
-
- // Subscribe to the manager's PropertyChanged signal.
- manager_proxy->RegisterPropertyChangedSignalHandler(
- base::Bind(&RealShillProvider::OnManagerPropertyChanged,
- base::Unretained(this)),
- base::Bind(&RealShillProvider::OnSignalConnected,
- base::Unretained(this)));
-
- // Attempt to read initial connection status. Even if this fails because shill
- // is not responding (e.g. it is down) we'll be notified via "PropertyChanged"
- // signal as soon as it comes up, so this is not a critical step.
- brillo::VariantDictionary properties;
- brillo::ErrorPtr error;
- if (!manager_proxy->GetProperties(&properties, &error))
- return true;
-
- const auto& prop_default_service =
- properties.find(shill::kDefaultServiceProperty);
- if (prop_default_service != properties.end()) {
- OnManagerPropertyChanged(prop_default_service->first,
- prop_default_service->second);
- }
-
- return true;
-}
-
-void RealShillProvider::OnManagerPropertyChanged(const string& name,
- const brillo::Any& value) {
- if (name == shill::kDefaultServiceProperty) {
- dbus::ObjectPath service_path = value.TryGet<dbus::ObjectPath>();
- if (!service_path.IsValid()) {
- LOG(WARNING) << "Got an invalid DefaultService path. The property value "
- "contains a "
- << value.GetUndecoratedTypeName()
- << ", read as the object path: '" << service_path.value()
- << "'";
- }
- ProcessDefaultService(service_path);
- }
-}
-
-void RealShillProvider::OnSignalConnected(const string& interface_name,
- const string& signal_name,
- bool successful) {
- if (!successful) {
- LOG(ERROR) << "Couldn't connect to the signal " << interface_name << "."
- << signal_name;
- }
-}
-
-bool RealShillProvider::ProcessDefaultService(
- const dbus::ObjectPath& default_service_path) {
- // We assume that if the service path didn't change, then the connection
- // type and the tethering status of it also didn't change.
- if (default_service_path_ == default_service_path)
- return true;
-
- // Update the connection status.
- default_service_path_ = default_service_path;
- bool is_connected =
- (default_service_path_.IsValid() && default_service_path_.value() != "/");
- var_is_connected_.SetValue(is_connected);
- var_conn_last_changed_.SetValue(
- SystemState::Get()->clock()->GetWallclockTime());
-
- if (!is_connected) {
- var_conn_type_.UnsetValue();
- var_conn_tethering_.UnsetValue();
- return true;
- }
-
- // We create and dispose the ServiceProxyInterface on every request.
- std::unique_ptr<ServiceProxyInterface> service =
- shill_proxy_->GetServiceForPath(default_service_path_);
-
- // Get the connection properties synchronously.
- brillo::VariantDictionary properties;
- brillo::ErrorPtr error;
- if (!service->GetProperties(&properties, &error)) {
- var_conn_type_.UnsetValue();
- var_conn_tethering_.UnsetValue();
- return false;
- }
-
- // Get the connection tethering mode.
- const auto& prop_tethering = properties.find(shill::kTetheringProperty);
- if (prop_tethering == properties.end()) {
- // Remove the value if not present on the service. This most likely means an
- // error in shill and the policy will handle it, but we will print a log
- // message as well for accessing an unused variable.
- var_conn_tethering_.UnsetValue();
- LOG(ERROR) << "Could not find connection type (service: "
- << default_service_path_.value() << ")";
- } else {
- // If the property doesn't contain a string value, the empty string will
- // become kUnknown.
- var_conn_tethering_.SetValue(
- chromeos_update_engine::connection_utils::ParseConnectionTethering(
- prop_tethering->second.TryGet<string>()));
- }
-
- // Get the connection type.
- const auto& prop_type = properties.find(shill::kTypeProperty);
- if (prop_type == properties.end()) {
- var_conn_type_.UnsetValue();
- LOG(ERROR) << "Could not find connection tethering mode (service: "
- << default_service_path_.value() << ")";
- } else {
- string type_str = prop_type->second.TryGet<string>();
- if (type_str == shill::kTypeVPN) {
- const auto& prop_physical =
- properties.find(shill::kPhysicalTechnologyProperty);
- if (prop_physical == properties.end()) {
- LOG(ERROR) << "No PhysicalTechnology property found for a VPN"
- << " connection (service: " << default_service_path_.value()
- << "). Using default kUnknown value.";
- var_conn_type_.SetValue(
- chromeos_update_engine::ConnectionType::kUnknown);
- } else {
- var_conn_type_.SetValue(
- ParseConnectionType(prop_physical->second.TryGet<string>()));
- }
- } else {
- var_conn_type_.SetValue(ParseConnectionType(type_str));
- }
- }
-
- return true;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_shill_provider.h b/update_manager/real_shill_provider.h
deleted file mode 100644
index cd53d920..00000000
--- a/update_manager/real_shill_provider.h
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_SHILL_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_SHILL_PROVIDER_H_
-
-// TODO(garnold) Much of the functionality in this module was adapted from the
-// update engine's connection_manager. We need to make sure to deprecate use of
-// connection manager when the time comes.
-
-#include <memory>
-#include <string>
-
-#include <base/time/time.h>
-#include <dbus/object_path.h>
-
-#include "update_engine/common/system_state.h"
-#include "update_engine/cros/shill_proxy_interface.h"
-#include "update_engine/update_manager/generic_variables.h"
-#include "update_engine/update_manager/shill_provider.h"
-
-namespace chromeos_update_manager {
-
-// ShillProvider concrete implementation.
-class RealShillProvider : public ShillProvider {
- public:
- explicit RealShillProvider(
- chromeos_update_engine::ShillProxyInterface* shill_proxy)
- : shill_proxy_(shill_proxy) {}
-
- ~RealShillProvider() override = default;
-
- // Initializes the provider and returns whether it succeeded.
- bool Init();
-
- Variable<bool>* var_is_connected() override { return &var_is_connected_; }
-
- Variable<chromeos_update_engine::ConnectionType>* var_conn_type() override {
- return &var_conn_type_;
- }
-
- Variable<chromeos_update_engine::ConnectionTethering>* var_conn_tethering()
- override {
- return &var_conn_tethering_;
- }
-
- Variable<base::Time>* var_conn_last_changed() override {
- return &var_conn_last_changed_;
- }
-
- private:
- // A handler for ManagerProxy.PropertyChanged signal.
- void OnManagerPropertyChanged(const std::string& name,
- const brillo::Any& value);
-
- // Called when the signal in ManagerProxy.PropertyChanged is connected.
- void OnSignalConnected(const std::string& interface_name,
- const std::string& signal_name,
- bool successful);
-
- // Get the connection and populate the type and tethering status of the given
- // default connection.
- bool ProcessDefaultService(const dbus::ObjectPath& default_service_path);
-
- // The current default service path, if connected. "/" means not connected.
- dbus::ObjectPath default_service_path_{"uninitialized"};
-
- // The mockable interface to access the shill DBus proxies.
- std::unique_ptr<chromeos_update_engine::ShillProxyInterface> shill_proxy_;
-
- // The provider's variables.
- AsyncCopyVariable<bool> var_is_connected_{"is_connected"};
- AsyncCopyVariable<chromeos_update_engine::ConnectionType> var_conn_type_{
- "conn_type"};
- AsyncCopyVariable<chromeos_update_engine::ConnectionTethering>
- var_conn_tethering_{"conn_tethering"};
- AsyncCopyVariable<base::Time> var_conn_last_changed_{"conn_last_changed"};
-
- DISALLOW_COPY_AND_ASSIGN(RealShillProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_SHILL_PROVIDER_H_
diff --git a/update_manager/real_shill_provider_unittest.cc b/update_manager/real_shill_provider_unittest.cc
deleted file mode 100644
index 9a2d8a80..00000000
--- a/update_manager/real_shill_provider_unittest.cc
+++ /dev/null
@@ -1,511 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_shill_provider.h"
-
-#include <memory>
-#include <utility>
-
-#include <base/memory/ptr_util.h>
-#include <base/time/time.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <shill/dbus-constants.h>
-#include <shill/dbus-proxies.h>
-#include <shill/dbus-proxy-mocks.h>
-
-#include "update_engine/common/test_utils.h"
-#include "update_engine/cros/dbus_test_utils.h"
-#include "update_engine/cros/fake_shill_proxy.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/umtest_utils.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::ConnectionTethering;
-using chromeos_update_engine::ConnectionType;
-using chromeos_update_engine::FakeSystemState;
-using org::chromium::flimflam::ManagerProxyMock;
-using org::chromium::flimflam::ServiceProxyMock;
-using std::unique_ptr;
-using testing::_;
-using testing::Mock;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace {
-
-// Fake service paths.
-const char* const kFakeEthernetServicePath = "/fake/ethernet/service";
-const char* const kFakeWifiServicePath = "/fake/wifi/service";
-const char* const kFakeCellularServicePath = "/fake/cellular/service";
-const char* const kFakeVpnServicePath = "/fake/vpn/service";
-const char* const kFakeUnknownServicePath = "/fake/unknown/service";
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-class UmRealShillProviderTest : public ::testing::Test {
- protected:
- // Initialize the RealShillProvider under test.
- void SetUp() override {
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(InitTime());
- loop_.SetAsCurrent();
- fake_shill_proxy_ = new chromeos_update_engine::FakeShillProxy();
- provider_.reset(new RealShillProvider(fake_shill_proxy_));
-
- ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy();
-
- // The PropertyChanged signal should be subscribed to.
- MOCK_SIGNAL_HANDLER_EXPECT_SIGNAL_HANDLER(
- manager_property_changed_, *manager_proxy_mock, PropertyChanged);
- }
-
- void TearDown() override {
- provider_.reset();
- // Check for leaked callbacks on the main loop.
- EXPECT_FALSE(loop_.PendingTasks());
- }
-
- // These methods generate fixed timestamps for use in faking the current time.
- Time InitTime() {
- Time::Exploded now_exp;
- now_exp.year = 2014;
- now_exp.month = 3;
- now_exp.day_of_week = 2;
- now_exp.day_of_month = 18;
- now_exp.hour = 8;
- now_exp.minute = 5;
- now_exp.second = 33;
- now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
- }
-
- Time ConnChangedTime() { return InitTime() + TimeDelta::FromSeconds(10); }
-
- // Sets the default_service object path in the response from the
- // ManagerProxyMock instance.
- void SetManagerReply(const char* default_service, bool reply_succeeds);
-
- // Sets the |service_type|, |physical_technology| and |service_tethering|
- // properties in the mocked service |service_path|. If any of the three
- // const char* is a nullptr, the corresponding property will not be included
- // in the response.
- // Returns the mock object pointer, owned by the |fake_shill_proxy_|.
- ServiceProxyMock* SetServiceReply(const std::string& service_path,
- const char* service_type,
- const char* physical_technology,
- const char* service_tethering);
-
- void InitWithDefaultService(const char* default_service) {
- SetManagerReply(default_service, true);
- // Check that provider initializes correctly.
- EXPECT_TRUE(provider_->Init());
- // RunOnce to notify the signal handler was connected properly.
- EXPECT_TRUE(loop_.RunOnce(false));
- }
-
- // Sends a signal informing the provider about a default connection
- // |service_path|. Sets the fake connection change time in
- // |conn_change_time_p| if provided.
- void SendDefaultServiceSignal(const std::string& service_path,
- Time* conn_change_time_p) {
- const Time conn_change_time = ConnChangedTime();
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(conn_change_time);
- ASSERT_TRUE(manager_property_changed_.IsHandlerRegistered());
- manager_property_changed_.signal_callback().Run(
- shill::kDefaultServiceProperty, dbus::ObjectPath(service_path));
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(
- conn_change_time + TimeDelta::FromSeconds(5));
- if (conn_change_time_p)
- *conn_change_time_p = conn_change_time;
- }
-
- // Sets up expectations for detection of a connection |service_path| with type
- // |shill_type_str| and tethering mode |shill_tethering_str|. Ensures that the
- // new connection status and change time are properly detected by the
- // provider. Writes the fake connection change time to |conn_change_time_p|,
- // if provided.
- void SetupConnectionAndAttrs(const std::string& service_path,
- const char* shill_type,
- const char* shill_tethering,
- Time* conn_change_time_p) {
- SetServiceReply(service_path, shill_type, nullptr, shill_tethering);
- // Note: We don't setup this |service_path| as the default service path but
- // we instead send a signal notifying the change since the code won't call
- // GetProperties on the Manager object at this point.
-
- // Send a signal about a new default service.
- Time conn_change_time;
- SendDefaultServiceSignal(service_path, &conn_change_time);
-
- // Query the connection status, ensure last change time reported correctly.
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
- UmTestUtils::ExpectVariableHasValue(conn_change_time,
- provider_->var_conn_last_changed());
-
- // Write the connection change time to the output argument.
- if (conn_change_time_p)
- *conn_change_time_p = conn_change_time;
- }
-
- // Sets up a connection and tests that its type is being properly detected by
- // the provider.
- void SetupConnectionAndTestType(const char* service_path,
- const char* shill_type,
- ConnectionType expected_conn_type) {
- // Set up and test the connection, record the change time.
- Time conn_change_time;
- SetupConnectionAndAttrs(service_path,
- shill_type,
- shill::kTetheringNotDetectedState,
- &conn_change_time);
-
- // Query the connection type, ensure last change time did not change.
- UmTestUtils::ExpectVariableHasValue(expected_conn_type,
- provider_->var_conn_type());
- UmTestUtils::ExpectVariableHasValue(conn_change_time,
- provider_->var_conn_last_changed());
- }
-
- // Sets up a connection and tests that its tethering mode is being properly
- // detected by the provider.
- void SetupConnectionAndTestTethering(
- const char* service_path,
- const char* shill_tethering,
- ConnectionTethering expected_conn_tethering) {
- // Set up and test the connection, record the change time.
- Time conn_change_time;
- SetupConnectionAndAttrs(
- service_path, shill::kTypeEthernet, shill_tethering, &conn_change_time);
-
- // Query the connection tethering, ensure last change time did not change.
- UmTestUtils::ExpectVariableHasValue(expected_conn_tethering,
- provider_->var_conn_tethering());
- UmTestUtils::ExpectVariableHasValue(conn_change_time,
- provider_->var_conn_last_changed());
- }
-
- brillo::FakeMessageLoop loop_{nullptr};
- chromeos_update_engine::FakeShillProxy* fake_shill_proxy_;
-
- // The registered signal handler for the signal Manager.PropertyChanged.
- chromeos_update_engine::dbus_test_utils::MockSignalHandler<void(
- const std::string&, const brillo::Any&)>
- manager_property_changed_;
-
- unique_ptr<RealShillProvider> provider_;
-};
-
-void UmRealShillProviderTest::SetManagerReply(const char* default_service,
- bool reply_succeeds) {
- ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy();
- if (!reply_succeeds) {
- EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
- .WillOnce(Return(false));
- return;
- }
-
- // Create a dictionary of properties and optionally include the default
- // service.
- brillo::VariantDictionary reply_dict;
- reply_dict["SomeOtherProperty"] = 0xC0FFEE;
-
- if (default_service) {
- reply_dict[shill::kDefaultServiceProperty] =
- dbus::ObjectPath(default_service);
- }
- EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
- .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
-}
-
-ServiceProxyMock* UmRealShillProviderTest::SetServiceReply(
- const std::string& service_path,
- const char* service_type,
- const char* physical_technology,
- const char* service_tethering) {
- brillo::VariantDictionary reply_dict;
- reply_dict["SomeOtherProperty"] = 0xC0FFEE;
-
- if (service_type)
- reply_dict[shill::kTypeProperty] = std::string(service_type);
-
- if (physical_technology) {
- reply_dict[shill::kPhysicalTechnologyProperty] =
- std::string(physical_technology);
- }
-
- if (service_tethering)
- reply_dict[shill::kTetheringProperty] = std::string(service_tethering);
-
- ServiceProxyMock* service_proxy_mock = new ServiceProxyMock();
-
- // Plumb return value into mock object.
- EXPECT_CALL(*service_proxy_mock, GetProperties(_, _, _))
- .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
-
- fake_shill_proxy_->SetServiceForPath(dbus::ObjectPath(service_path),
- base::WrapUnique(service_proxy_mock));
-
- return service_proxy_mock;
-}
-
-// Query the connection status, type and time last changed, as they were set
-// during initialization (no signals).
-TEST_F(UmRealShillProviderTest, ReadBaseValues) {
- InitWithDefaultService("/");
- // Query the provider variables.
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_connected());
- UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
- UmTestUtils::ExpectVariableHasValue(InitTime(),
- provider_->var_conn_last_changed());
-}
-
-// Ensure that invalid DBus paths are ignored.
-TEST_F(UmRealShillProviderTest, InvalidServicePath) {
- InitWithDefaultService("invalid");
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_connected());
- UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
- UmTestUtils::ExpectVariableHasValue(InitTime(),
- provider_->var_conn_last_changed());
-}
-
-// Ensure that a service path property including a different type is ignored.
-TEST_F(UmRealShillProviderTest, InvalidServicePathType) {
- ManagerProxyMock* manager_proxy_mock = fake_shill_proxy_->GetManagerProxy();
- brillo::VariantDictionary reply_dict;
- reply_dict[shill::kDefaultServiceProperty] = "/not/an/object/path";
- EXPECT_CALL(*manager_proxy_mock, GetProperties(_, _, _))
- .WillOnce(DoAll(SetArgPointee<0>(reply_dict), Return(true)));
-
- EXPECT_TRUE(provider_->Init());
- EXPECT_TRUE(loop_.RunOnce(false));
-
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_connected());
-}
-
-// Test that Ethernet connection is identified correctly.
-TEST_F(UmRealShillProviderTest, ReadConnTypeEthernet) {
- InitWithDefaultService("/");
- SetupConnectionAndTestType(kFakeEthernetServicePath,
- shill::kTypeEthernet,
- ConnectionType::kEthernet);
-}
-
-// Test that Wifi connection is identified correctly.
-TEST_F(UmRealShillProviderTest, ReadConnTypeWifi) {
- InitWithDefaultService("/");
- SetupConnectionAndTestType(
- kFakeWifiServicePath, shill::kTypeWifi, ConnectionType::kWifi);
-}
-
-// Test that Cellular connection is identified correctly.
-TEST_F(UmRealShillProviderTest, ReadConnTypeCellular) {
- InitWithDefaultService("/");
- SetupConnectionAndTestType(kFakeCellularServicePath,
- shill::kTypeCellular,
- ConnectionType::kCellular);
-}
-
-// Test that an unknown connection is identified as such.
-TEST_F(UmRealShillProviderTest, ReadConnTypeUnknown) {
- InitWithDefaultService("/");
- SetupConnectionAndTestType(
- kFakeUnknownServicePath, "FooConnectionType", ConnectionType::kUnknown);
-}
-
-// Tests that VPN connection is identified correctly.
-TEST_F(UmRealShillProviderTest, ReadConnTypeVpn) {
- InitWithDefaultService("/");
- // Mock logic for returning a default service path and its type.
- SetServiceReply(kFakeVpnServicePath,
- shill::kTypeVPN,
- shill::kTypeWifi,
- shill::kTetheringNotDetectedState);
-
- // Send a signal about a new default service.
- Time conn_change_time;
- SendDefaultServiceSignal(kFakeVpnServicePath, &conn_change_time);
-
- // Query the connection type, ensure last change time reported correctly.
- UmTestUtils::ExpectVariableHasValue(ConnectionType::kWifi,
- provider_->var_conn_type());
- UmTestUtils::ExpectVariableHasValue(conn_change_time,
- provider_->var_conn_last_changed());
-}
-
-// Ensure that the connection type is properly cached in the provider through
-// subsequent variable readings.
-TEST_F(UmRealShillProviderTest, ConnTypeCacheUsed) {
- InitWithDefaultService("/");
- SetupConnectionAndTestType(kFakeEthernetServicePath,
- shill::kTypeEthernet,
- ConnectionType::kEthernet);
-
- UmTestUtils::ExpectVariableHasValue(ConnectionType::kEthernet,
- provider_->var_conn_type());
-}
-
-// Ensure that the cached connection type remains valid even when a default
-// connection signal occurs but the connection is not changed.
-TEST_F(UmRealShillProviderTest, ConnTypeCacheRemainsValid) {
- InitWithDefaultService("/");
- SetupConnectionAndTestType(kFakeEthernetServicePath,
- shill::kTypeEthernet,
- ConnectionType::kEthernet);
-
- SendDefaultServiceSignal(kFakeEthernetServicePath, nullptr);
-
- UmTestUtils::ExpectVariableHasValue(ConnectionType::kEthernet,
- provider_->var_conn_type());
-}
-
-// Ensure that the cached connection type is invalidated and re-read when the
-// default connection changes.
-TEST_F(UmRealShillProviderTest, ConnTypeCacheInvalidated) {
- InitWithDefaultService("/");
- SetupConnectionAndTestType(kFakeEthernetServicePath,
- shill::kTypeEthernet,
- ConnectionType::kEthernet);
-
- SetupConnectionAndTestType(
- kFakeWifiServicePath, shill::kTypeWifi, ConnectionType::kWifi);
-}
-
-// Test that a non-tethering mode is identified correctly.
-TEST_F(UmRealShillProviderTest, ReadConnTetheringNotDetected) {
- InitWithDefaultService("/");
- SetupConnectionAndTestTethering(kFakeWifiServicePath,
- shill::kTetheringNotDetectedState,
- ConnectionTethering::kNotDetected);
-}
-
-// Test that a suspected tethering mode is identified correctly.
-TEST_F(UmRealShillProviderTest, ReadConnTetheringSuspected) {
- InitWithDefaultService("/");
- SetupConnectionAndTestTethering(kFakeWifiServicePath,
- shill::kTetheringSuspectedState,
- ConnectionTethering::kSuspected);
-}
-
-// Test that a confirmed tethering mode is identified correctly.
-TEST_F(UmRealShillProviderTest, ReadConnTetheringConfirmed) {
- InitWithDefaultService("/");
- SetupConnectionAndTestTethering(kFakeWifiServicePath,
- shill::kTetheringConfirmedState,
- ConnectionTethering::kConfirmed);
-}
-
-// Test that an unknown tethering mode is identified as such.
-TEST_F(UmRealShillProviderTest, ReadConnTetheringUnknown) {
- InitWithDefaultService("/");
- SetupConnectionAndTestTethering(
- kFakeWifiServicePath, "FooConnTethering", ConnectionTethering::kUnknown);
-}
-
-// Ensure that the connection tethering mode is properly cached in the provider.
-TEST_F(UmRealShillProviderTest, ConnTetheringCacheUsed) {
- InitWithDefaultService("/");
- SetupConnectionAndTestTethering(kFakeEthernetServicePath,
- shill::kTetheringNotDetectedState,
- ConnectionTethering::kNotDetected);
-
- UmTestUtils::ExpectVariableHasValue(ConnectionTethering::kNotDetected,
- provider_->var_conn_tethering());
-}
-
-// Ensure that the cached connection tethering mode remains valid even when a
-// default connection signal occurs but the connection is not changed.
-TEST_F(UmRealShillProviderTest, ConnTetheringCacheRemainsValid) {
- InitWithDefaultService("/");
- SetupConnectionAndTestTethering(kFakeEthernetServicePath,
- shill::kTetheringNotDetectedState,
- ConnectionTethering::kNotDetected);
-
- SendDefaultServiceSignal(kFakeEthernetServicePath, nullptr);
-
- UmTestUtils::ExpectVariableHasValue(ConnectionTethering::kNotDetected,
- provider_->var_conn_tethering());
-}
-
-// Ensure that the cached connection tethering mode is invalidated and re-read
-// when the default connection changes.
-TEST_F(UmRealShillProviderTest, ConnTetheringCacheInvalidated) {
- InitWithDefaultService("/");
- SetupConnectionAndTestTethering(kFakeEthernetServicePath,
- shill::kTetheringNotDetectedState,
- ConnectionTethering::kNotDetected);
-
- SetupConnectionAndTestTethering(kFakeWifiServicePath,
- shill::kTetheringConfirmedState,
- ConnectionTethering::kConfirmed);
-}
-
-// Fake two DBus signals prompting a default connection change, but otherwise
-// give the same service path. Check connection status and the time it was last
-// changed, making sure that it is the time when the first signal was sent (and
-// not the second).
-TEST_F(UmRealShillProviderTest, ReadLastChangedTimeTwoSignals) {
- InitWithDefaultService("/");
- // Send a default service signal twice, advancing the clock in between.
- Time conn_change_time;
- SetupConnectionAndAttrs(kFakeEthernetServicePath,
- shill::kTypeEthernet,
- shill::kTetheringNotDetectedState,
- &conn_change_time);
- // This will set the service path to the same value, so it should not call
- // GetProperties() again.
- SendDefaultServiceSignal(kFakeEthernetServicePath, nullptr);
-
- // Query the connection status, ensure last change time reported as the first
- // time the signal was sent.
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
- UmTestUtils::ExpectVariableHasValue(conn_change_time,
- provider_->var_conn_last_changed());
-}
-
-// Make sure that the provider initializes correctly even if shill is not
-// responding, that variables can be obtained, and that they all return a null
-// value (indicating that the underlying values were not set).
-TEST_F(UmRealShillProviderTest, NoInitConnStatusReadBaseValues) {
- // Initialize the provider, no initial connection status response.
- SetManagerReply(nullptr, false);
- EXPECT_TRUE(provider_->Init());
- EXPECT_TRUE(loop_.RunOnce(false));
- UmTestUtils::ExpectVariableNotSet(provider_->var_is_connected());
- UmTestUtils::ExpectVariableNotSet(provider_->var_conn_type());
- UmTestUtils::ExpectVariableNotSet(provider_->var_conn_last_changed());
-}
-
-// Test that, once a signal is received, the connection status and other info
-// can be read correctly.
-TEST_F(UmRealShillProviderTest, NoInitConnStatusReadConnTypeEthernet) {
- // Initialize the provider with no initial connection status response.
- SetManagerReply(nullptr, false);
- EXPECT_TRUE(provider_->Init());
- EXPECT_TRUE(loop_.RunOnce(false));
-
- SetupConnectionAndAttrs(kFakeEthernetServicePath,
- shill::kTypeEthernet,
- shill::kTetheringNotDetectedState,
- nullptr);
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_connected());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_state.h b/update_manager/real_state.h
deleted file mode 100644
index 056d46d5..00000000
--- a/update_manager/real_state.h
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_STATE_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_STATE_H_
-
-#include <memory>
-
-#include "update_engine/update_manager/state.h"
-
-namespace chromeos_update_manager {
-
-// State concrete implementation.
-class RealState : public State {
- public:
- ~RealState() override {}
-
- RealState(ConfigProvider* config_provider,
- DevicePolicyProvider* device_policy_provider,
- RandomProvider* random_provider,
- ShillProvider* shill_provider,
- SystemProvider* system_provider,
- TimeProvider* time_provider,
- UpdaterProvider* updater_provider)
- : config_provider_(config_provider),
- device_policy_provider_(device_policy_provider),
- random_provider_(random_provider),
- shill_provider_(shill_provider),
- system_provider_(system_provider),
- time_provider_(time_provider),
- updater_provider_(updater_provider) {}
-
- // These methods return the given provider.
- ConfigProvider* config_provider() override { return config_provider_.get(); }
- DevicePolicyProvider* device_policy_provider() override {
- return device_policy_provider_.get();
- }
- RandomProvider* random_provider() override { return random_provider_.get(); }
- ShillProvider* shill_provider() override { return shill_provider_.get(); }
- SystemProvider* system_provider() override { return system_provider_.get(); }
- TimeProvider* time_provider() override { return time_provider_.get(); }
- UpdaterProvider* updater_provider() override {
- return updater_provider_.get();
- }
-
- private:
- // Instances of the providers.
- std::unique_ptr<ConfigProvider> config_provider_;
- std::unique_ptr<DevicePolicyProvider> device_policy_provider_;
- std::unique_ptr<RandomProvider> random_provider_;
- std::unique_ptr<ShillProvider> shill_provider_;
- std::unique_ptr<SystemProvider> system_provider_;
- std::unique_ptr<TimeProvider> time_provider_;
- std::unique_ptr<UpdaterProvider> updater_provider_;
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_STATE_H_
diff --git a/update_manager/real_system_provider.cc b/update_manager/real_system_provider.cc
deleted file mode 100644
index 34397f33..00000000
--- a/update_manager/real_system_provider.cc
+++ /dev/null
@@ -1,144 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_system_provider.h"
-
-#include <base/bind.h>
-#include <base/callback.h>
-#include <base/logging.h>
-#include <base/time/time.h>
-#include <kiosk-app/dbus-proxies.h>
-
-#include "update_engine/common/boot_control_interface.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/common/utils.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/update_manager/generic_variables.h"
-#include "update_engine/update_manager/variable.h"
-
-using chromeos_update_engine::SystemState;
-using std::string;
-
-namespace chromeos_update_manager {
-
-namespace {
-
-// The maximum number of consecutive failures before returning the default
-// constructor value for T instead of failure.
-const int kRetryPollVariableMaxRetry = 5;
-
-// The polling interval to be used whenever GetValue() returns an error.
-const int kRetryPollVariableRetryIntervalSeconds = 5 * 60;
-
-// The RetryPollVariable variable is a polling variable that allows the function
-// returning the value to fail a few times and shortens the polling rate when
-// that happens.
-template <typename T>
-class RetryPollVariable : public Variable<T> {
- public:
- RetryPollVariable(const string& name,
- const base::TimeDelta poll_interval,
- base::Callback<bool(T* res)> func)
- : Variable<T>(name, poll_interval),
- func_(func),
- base_interval_(poll_interval) {
- DCHECK_LT(kRetryPollVariableRetryIntervalSeconds,
- base_interval_.InSeconds());
- }
-
- protected:
- // Variable override.
- const T* GetValue(base::TimeDelta /* timeout */,
- string* /* errmsg */) override {
- std::unique_ptr<T> result(new T());
- if (!func_.Run(result.get())) {
- if (failed_attempts_ >= kRetryPollVariableMaxRetry) {
- // Give up on the retries and set back the desired polling interval.
- this->SetPollInterval(base_interval_);
- // Release the result instead of returning a |nullptr| to indicate that
- // the result could not be fetched.
- return result.release();
- }
- this->SetPollInterval(
- base::TimeDelta::FromSeconds(kRetryPollVariableRetryIntervalSeconds));
- failed_attempts_++;
- return nullptr;
- }
- failed_attempts_ = 0;
- this->SetPollInterval(base_interval_);
- return result.release();
- }
-
- private:
- // The function to be called, stored as a base::Callback.
- base::Callback<bool(T*)> func_;
-
- // The desired polling interval when |func_| works and returns true.
- base::TimeDelta base_interval_;
-
- // The number of consecutive failed attempts made.
- int failed_attempts_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(RetryPollVariable);
-};
-
-} // namespace
-
-bool RealSystemProvider::Init() {
- var_is_normal_boot_mode_.reset(new ConstCopyVariable<bool>(
- "is_normal_boot_mode",
- SystemState::Get()->hardware()->IsNormalBootMode()));
-
- var_is_official_build_.reset(new ConstCopyVariable<bool>(
- "is_official_build", SystemState::Get()->hardware()->IsOfficialBuild()));
-
- var_is_oobe_complete_.reset(new CallCopyVariable<bool>(
- "is_oobe_complete",
- base::Bind(&chromeos_update_engine::HardwareInterface::IsOOBEComplete,
- base::Unretained(SystemState::Get()->hardware()),
- nullptr)));
-
- var_num_slots_.reset(new ConstCopyVariable<unsigned int>(
- "num_slots", SystemState::Get()->boot_control()->GetNumSlots()));
-
- var_kiosk_required_platform_version_.reset(new RetryPollVariable<string>(
- "kiosk_required_platform_version",
- base::TimeDelta::FromHours(5), // Same as Chrome's CWS poll.
- base::Bind(&RealSystemProvider::GetKioskAppRequiredPlatformVersion,
- base::Unretained(this))));
-
- var_chromeos_version_.reset(new ConstCopyVariable<base::Version>(
- "chromeos_version",
- base::Version(SystemState::Get()->request_params()->app_version())));
-
- return true;
-}
-
-bool RealSystemProvider::GetKioskAppRequiredPlatformVersion(
- string* required_platform_version) {
- brillo::ErrorPtr error;
- if (!kiosk_app_proxy_->GetRequiredPlatformVersion(required_platform_version,
- &error)) {
- LOG(WARNING) << "Failed to get kiosk required platform version";
- required_platform_version->clear();
- return false;
- }
-
- return true;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_system_provider.h b/update_manager/real_system_provider.h
deleted file mode 100644
index 558d3be4..00000000
--- a/update_manager/real_system_provider.h
+++ /dev/null
@@ -1,87 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_SYSTEM_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_SYSTEM_PROVIDER_H_
-
-#include <memory>
-#include <string>
-
-#include <base/version.h>
-
-#include "update_engine/update_manager/system_provider.h"
-
-namespace org {
-namespace chromium {
-class KioskAppServiceInterfaceProxyInterface;
-} // namespace chromium
-} // namespace org
-
-namespace chromeos_update_manager {
-
-// SystemProvider concrete implementation.
-class RealSystemProvider : public SystemProvider {
- public:
- RealSystemProvider(
- org::chromium::KioskAppServiceInterfaceProxyInterface* kiosk_app_proxy)
- : kiosk_app_proxy_(kiosk_app_proxy) {}
-
- // Initializes the provider and returns whether it succeeded.
- bool Init();
-
- Variable<bool>* var_is_normal_boot_mode() override {
- return var_is_normal_boot_mode_.get();
- }
-
- Variable<bool>* var_is_official_build() override {
- return var_is_official_build_.get();
- }
-
- Variable<bool>* var_is_oobe_complete() override {
- return var_is_oobe_complete_.get();
- }
-
- Variable<unsigned int>* var_num_slots() override {
- return var_num_slots_.get();
- }
-
- Variable<std::string>* var_kiosk_required_platform_version() override {
- return var_kiosk_required_platform_version_.get();
- }
-
- Variable<base::Version>* var_chromeos_version() override {
- return var_chromeos_version_.get();
- }
-
- private:
- bool GetKioskAppRequiredPlatformVersion(
- std::string* required_platform_version);
-
- std::unique_ptr<Variable<bool>> var_is_normal_boot_mode_;
- std::unique_ptr<Variable<bool>> var_is_official_build_;
- std::unique_ptr<Variable<bool>> var_is_oobe_complete_;
- std::unique_ptr<Variable<unsigned int>> var_num_slots_;
- std::unique_ptr<Variable<std::string>> var_kiosk_required_platform_version_;
- std::unique_ptr<Variable<base::Version>> var_chromeos_version_;
-
- org::chromium::KioskAppServiceInterfaceProxyInterface* const kiosk_app_proxy_;
-
- DISALLOW_COPY_AND_ASSIGN(RealSystemProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_SYSTEM_PROVIDER_H_
diff --git a/update_manager/real_system_provider_unittest.cc b/update_manager/real_system_provider_unittest.cc
deleted file mode 100644
index 9abcad06..00000000
--- a/update_manager/real_system_provider_unittest.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_system_provider.h"
-
-#include <memory>
-
-#include <base/time/time.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-#include <kiosk-app/dbus-proxies.h>
-#include <kiosk-app/dbus-proxy-mocks.h>
-
-#include "update_engine/common/fake_boot_control.h"
-#include "update_engine/common/fake_hardware.h"
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/umtest_utils.h"
-
-using chromeos_update_engine::FakeSystemState;
-using org::chromium::KioskAppServiceInterfaceProxyMock;
-using std::unique_ptr;
-using testing::_;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace {
-const char kRequiredPlatformVersion[] = "1234.0.0";
-} // namespace
-
-namespace chromeos_update_manager {
-
-class UmRealSystemProviderTest : public ::testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
- kiosk_app_proxy_mock_.reset(new KioskAppServiceInterfaceProxyMock());
- ON_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
- .WillByDefault(
- DoAll(SetArgPointee<0>(kRequiredPlatformVersion), Return(true)));
-
- provider_.reset(new RealSystemProvider(kiosk_app_proxy_mock_.get()));
- EXPECT_TRUE(provider_->Init());
- }
-
- unique_ptr<RealSystemProvider> provider_;
-
- unique_ptr<KioskAppServiceInterfaceProxyMock> kiosk_app_proxy_mock_;
-};
-
-TEST_F(UmRealSystemProviderTest, InitTest) {
- EXPECT_NE(nullptr, provider_->var_is_normal_boot_mode());
- EXPECT_NE(nullptr, provider_->var_is_official_build());
- EXPECT_NE(nullptr, provider_->var_is_oobe_complete());
- EXPECT_NE(nullptr, provider_->var_kiosk_required_platform_version());
- EXPECT_NE(nullptr, provider_->var_chromeos_version());
-}
-
-TEST_F(UmRealSystemProviderTest, IsOOBECompleteTrue) {
- FakeSystemState::Get()->fake_hardware()->SetIsOOBEComplete(base::Time());
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_is_oobe_complete());
-}
-
-TEST_F(UmRealSystemProviderTest, IsOOBECompleteFalse) {
- FakeSystemState::Get()->fake_hardware()->UnsetIsOOBEComplete();
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_is_oobe_complete());
-}
-
-TEST_F(UmRealSystemProviderTest, VersionFromRequestParams) {
- FakeSystemState::Get()->request_params()->set_app_version("1.2.3");
- // Call |Init| again to pick up the version.
- EXPECT_TRUE(provider_->Init());
-
- base::Version version("1.2.3");
- UmTestUtils::ExpectVariableHasValue(version,
- provider_->var_chromeos_version());
-}
-
-TEST_F(UmRealSystemProviderTest, KioskRequiredPlatformVersion) {
- UmTestUtils::ExpectVariableHasValue(
- std::string(kRequiredPlatformVersion),
- provider_->var_kiosk_required_platform_version());
-}
-
-TEST_F(UmRealSystemProviderTest, KioskRequiredPlatformVersionFailure) {
- EXPECT_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
- .WillOnce(Return(false));
-
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_kiosk_required_platform_version());
-}
-
-TEST_F(UmRealSystemProviderTest,
- KioskRequiredPlatformVersionRecoveryFromFailure) {
- EXPECT_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
- .WillOnce(Return(false));
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_kiosk_required_platform_version());
- testing::Mock::VerifyAndClearExpectations(kiosk_app_proxy_mock_.get());
-
- EXPECT_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion(_, _, _))
- .WillOnce(
- DoAll(SetArgPointee<0>(kRequiredPlatformVersion), Return(true)));
- UmTestUtils::ExpectVariableHasValue(
- std::string(kRequiredPlatformVersion),
- provider_->var_kiosk_required_platform_version());
-}
-
-TEST_F(UmRealSystemProviderTest, KioskRequiredPlatformVersionRepeatedFailure) {
- // Simulate unreadable platform version. The variable should return a
- // null pointer |kRetryPollVariableMaxRetry| times and then return an empty
- // string to indicate that it gave up.
- constexpr int kNumMethodCalls = 5;
- EXPECT_CALL(*kiosk_app_proxy_mock_, GetRequiredPlatformVersion)
- .Times(kNumMethodCalls + 1)
- .WillRepeatedly(Return(false));
- for (int i = 0; i < kNumMethodCalls; ++i) {
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_kiosk_required_platform_version());
- }
- UmTestUtils::ExpectVariableHasValue(
- std::string(""), provider_->var_kiosk_required_platform_version());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_time_provider.cc b/update_manager/real_time_provider.cc
deleted file mode 100644
index 2b71fa0f..00000000
--- a/update_manager/real_time_provider.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_time_provider.h"
-
-#include <string>
-
-#include <base/time/time.h>
-
-#include "update_engine/common/system_state.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::SystemState;
-using std::string;
-
-namespace chromeos_update_manager {
-
-// A variable returning the current date.
-class CurrDateVariable : public Variable<Time> {
- public:
- // TODO(garnold) Turn this into an async variable with the needed callback
- // logic for when it value changes.
- explicit CurrDateVariable(const string& name)
- : Variable<Time>(name, TimeDelta::FromHours(1)) {}
-
- protected:
- virtual const Time* GetValue(TimeDelta /* timeout */, string* /* errmsg */) {
- Time::Exploded now_exp;
- SystemState::Get()->clock()->GetWallclockTime().LocalExplode(&now_exp);
- now_exp.hour = now_exp.minute = now_exp.second = now_exp.millisecond = 0;
- Time* now = new Time();
- bool success = Time::FromLocalExploded(now_exp, now);
- DCHECK(success);
- return now;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CurrDateVariable);
-};
-
-// A variable returning the current hour in local time.
-class CurrHourVariable : public Variable<int> {
- public:
- // TODO(garnold) Turn this into an async variable with the needed callback
- // logic for when it value changes.
- explicit CurrHourVariable(const string& name)
- : Variable<int>(name, TimeDelta::FromMinutes(5)) {}
-
- protected:
- virtual const int* GetValue(TimeDelta /* timeout */, string* /* errmsg */) {
- Time::Exploded exploded;
- SystemState::Get()->clock()->GetWallclockTime().LocalExplode(&exploded);
- return new int(exploded.hour);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CurrHourVariable);
-};
-
-class CurrMinuteVariable : public Variable<int> {
- public:
- explicit CurrMinuteVariable(const string& name)
- : Variable<int>(name, TimeDelta::FromSeconds(15)) {}
-
- protected:
- virtual const int* GetValue(TimeDelta /* timeout */, string* /* errmsg */) {
- Time::Exploded exploded;
- SystemState::Get()->clock()->GetWallclockTime().LocalExplode(&exploded);
- return new int(exploded.minute);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CurrMinuteVariable);
-};
-
-bool RealTimeProvider::Init() {
- var_curr_date_.reset(new CurrDateVariable("curr_date"));
- var_curr_hour_.reset(new CurrHourVariable("curr_hour"));
- var_curr_minute_.reset(new CurrMinuteVariable("curr_minute"));
- return true;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_time_provider.h b/update_manager/real_time_provider.h
deleted file mode 100644
index 58b0fa5c..00000000
--- a/update_manager/real_time_provider.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_TIME_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_TIME_PROVIDER_H_
-
-#include <memory>
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/time_provider.h"
-
-namespace chromeos_update_manager {
-
-// TimeProvider concrete implementation.
-class RealTimeProvider : public TimeProvider {
- public:
- RealTimeProvider() = default;
-
- // Initializes the provider and returns whether it succeeded.
- bool Init();
-
- Variable<base::Time>* var_curr_date() override {
- return var_curr_date_.get();
- }
-
- Variable<int>* var_curr_hour() override { return var_curr_hour_.get(); }
-
- Variable<int>* var_curr_minute() override { return var_curr_minute_.get(); }
-
- private:
- std::unique_ptr<Variable<base::Time>> var_curr_date_;
- std::unique_ptr<Variable<int>> var_curr_hour_;
- std::unique_ptr<Variable<int>> var_curr_minute_;
-
- DISALLOW_COPY_AND_ASSIGN(RealTimeProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_TIME_PROVIDER_H_
diff --git a/update_manager/real_time_provider_unittest.cc b/update_manager/real_time_provider_unittest.cc
deleted file mode 100644
index f8ed0d2c..00000000
--- a/update_manager/real_time_provider_unittest.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_time_provider.h"
-
-#include <memory>
-
-#include <base/logging.h>
-#include <base/time/time.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/umtest_utils.h"
-
-using base::Time;
-using chromeos_update_engine::FakeSystemState;
-using std::unique_ptr;
-
-namespace chromeos_update_manager {
-
-class UmRealTimeProviderTest : public ::testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
- // The provider initializes correctly.
- provider_.reset(new RealTimeProvider());
- ASSERT_NE(nullptr, provider_.get());
- ASSERT_TRUE(provider_->Init());
- }
-
- // Generates a fixed timestamp for use in faking the current time.
- Time CurrTime() {
- Time::Exploded now_exp;
- now_exp.year = 2014;
- now_exp.month = 3;
- now_exp.day_of_week = 2;
- now_exp.day_of_month = 18;
- now_exp.hour = 8;
- now_exp.minute = 5;
- now_exp.second = 33;
- now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
- }
-
- unique_ptr<RealTimeProvider> provider_;
-};
-
-TEST_F(UmRealTimeProviderTest, CurrDateValid) {
- const Time now = CurrTime();
- Time::Exploded exploded;
- now.LocalExplode(&exploded);
- exploded.hour = 0;
- exploded.minute = 0;
- exploded.second = 0;
- exploded.millisecond = 0;
- Time expected;
- ignore_result(Time::FromLocalExploded(exploded, &expected));
-
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(now);
- UmTestUtils::ExpectVariableHasValue(expected, provider_->var_curr_date());
-}
-
-TEST_F(UmRealTimeProviderTest, CurrHourValid) {
- const Time now = CurrTime();
- Time::Exploded expected;
- now.LocalExplode(&expected);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(now);
- UmTestUtils::ExpectVariableHasValue(expected.hour,
- provider_->var_curr_hour());
-}
-
-TEST_F(UmRealTimeProviderTest, CurrMinuteValid) {
- const Time now = CurrTime();
- Time::Exploded expected;
- now.LocalExplode(&expected);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(now);
- UmTestUtils::ExpectVariableHasValue(expected.minute,
- provider_->var_curr_minute());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.cc b/update_manager/real_updater_provider.cc
deleted file mode 100644
index 5b76332a..00000000
--- a/update_manager/real_updater_provider.cc
+++ /dev/null
@@ -1,503 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_updater_provider.h"
-
-#include <inttypes.h>
-
-#include <algorithm>
-#include <string>
-
-#include <base/bind.h>
-#include <base/strings/stringprintf.h>
-#include <base/time/time.h>
-#include <update_engine/dbus-constants.h>
-
-#include "update_engine/client_library/include/update_engine/update_status.h"
-#include "update_engine/common/prefs.h"
-#include "update_engine/common/system_state.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/cros/update_attempter.h"
-#include "update_engine/update_status_utils.h"
-
-using base::StringPrintf;
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::OmahaRequestParams;
-using chromeos_update_engine::SystemState;
-using std::string;
-using update_engine::UpdateAttemptFlags;
-using update_engine::UpdateEngineStatus;
-
-namespace chromeos_update_manager {
-
-// A templated base class for all update related variables. Provides uniform
-// construction and a system state handle.
-template <typename T>
-class UpdaterVariableBase : public Variable<T> {
- public:
- UpdaterVariableBase(const string& name, VariableMode mode)
- : Variable<T>(name, mode) {}
-};
-
-// Helper class for issuing a GetStatus() to the UpdateAttempter.
-class GetStatusHelper {
- public:
- explicit GetStatusHelper(string* errmsg) {
- is_success_ = SystemState::Get()->update_attempter()->GetStatus(
- &update_engine_status_);
- if (!is_success_ && errmsg) {
- *errmsg = "Failed to get a status update from the update engine";
- }
- }
-
- inline bool is_success() { return is_success_; }
- inline int64_t last_checked_time() {
- return update_engine_status_.last_checked_time;
- }
- inline double progress() { return update_engine_status_.progress; }
- inline const string update_status() {
- return chromeos_update_engine::UpdateStatusToString(
- update_engine_status_.status);
- }
- inline const string& new_version() {
- return update_engine_status_.new_version;
- }
- inline uint64_t payload_size() {
- return update_engine_status_.new_size_bytes;
- }
-
- private:
- bool is_success_;
- UpdateEngineStatus update_engine_status_;
-};
-
-// A variable reporting the time when a last update check was issued.
-class LastCheckedTimeVariable : public UpdaterVariableBase<Time> {
- public:
- explicit LastCheckedTimeVariable(const string& name)
- : UpdaterVariableBase<Time>(name, kVariableModePoll) {}
-
- private:
- const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override {
- GetStatusHelper raw(errmsg);
- if (!raw.is_success())
- return nullptr;
-
- return new Time(Time::FromTimeT(raw.last_checked_time()));
- }
-
- DISALLOW_COPY_AND_ASSIGN(LastCheckedTimeVariable);
-};
-
-// A variable reporting the update (download) progress as a decimal fraction
-// between 0.0 and 1.0.
-class ProgressVariable : public UpdaterVariableBase<double> {
- public:
- explicit ProgressVariable(const string& name)
- : UpdaterVariableBase<double>(name, kVariableModePoll) {}
-
- private:
- const double* GetValue(TimeDelta /* timeout */, string* errmsg) override {
- GetStatusHelper raw(errmsg);
- if (!raw.is_success())
- return nullptr;
-
- if (raw.progress() < 0.0 || raw.progress() > 1.0) {
- if (errmsg) {
- *errmsg =
- StringPrintf("Invalid progress value received: %f", raw.progress());
- }
- return nullptr;
- }
-
- return new double(raw.progress());
- }
-
- DISALLOW_COPY_AND_ASSIGN(ProgressVariable);
-};
-
-// A variable reporting the stage in which the update process is.
-class StageVariable : public UpdaterVariableBase<Stage> {
- public:
- explicit StageVariable(const string& name)
- : UpdaterVariableBase<Stage>(name, kVariableModePoll) {}
-
- private:
- struct CurrOpStrToStage {
- const char* str;
- Stage stage;
- };
- static const CurrOpStrToStage curr_op_str_to_stage[];
-
- // Note: the method is defined outside the class so arraysize can work.
- const Stage* GetValue(TimeDelta /* timeout */, string* errmsg) override;
-
- DISALLOW_COPY_AND_ASSIGN(StageVariable);
-};
-
-const StageVariable::CurrOpStrToStage StageVariable::curr_op_str_to_stage[] = {
- {update_engine::kUpdateStatusIdle, Stage::kIdle},
- {update_engine::kUpdateStatusCheckingForUpdate, Stage::kCheckingForUpdate},
- {update_engine::kUpdateStatusUpdateAvailable, Stage::kUpdateAvailable},
- {update_engine::kUpdateStatusDownloading, Stage::kDownloading},
- {update_engine::kUpdateStatusVerifying, Stage::kVerifying},
- {update_engine::kUpdateStatusFinalizing, Stage::kFinalizing},
- {update_engine::kUpdateStatusUpdatedNeedReboot, Stage::kUpdatedNeedReboot},
- {update_engine::kUpdateStatusReportingErrorEvent,
- Stage::kReportingErrorEvent},
- {update_engine::kUpdateStatusAttemptingRollback,
- Stage::kAttemptingRollback},
- {update_engine::kUpdateStatusCleanupPreviousUpdate,
- Stage::kCleanupPreviousUpdate},
-};
-
-const Stage* StageVariable::GetValue(TimeDelta /* timeout */, string* errmsg) {
- GetStatusHelper raw(errmsg);
- if (!raw.is_success())
- return nullptr;
-
- for (auto& key_val : curr_op_str_to_stage)
- if (raw.update_status() == key_val.str)
- return new Stage(key_val.stage);
-
- if (errmsg)
- *errmsg = string("Unknown update status: ") + raw.update_status();
- return nullptr;
-}
-
-// A variable reporting the version number that an update is updating to.
-class NewVersionVariable : public UpdaterVariableBase<string> {
- public:
- explicit NewVersionVariable(const string& name)
- : UpdaterVariableBase<string>(name, kVariableModePoll) {}
-
- private:
- const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
- GetStatusHelper raw(errmsg);
- if (!raw.is_success())
- return nullptr;
-
- return new string(raw.new_version());
- }
-
- DISALLOW_COPY_AND_ASSIGN(NewVersionVariable);
-};
-
-// A variable reporting the size of the update being processed in bytes.
-class PayloadSizeVariable : public UpdaterVariableBase<uint64_t> {
- public:
- explicit PayloadSizeVariable(const string& name)
- : UpdaterVariableBase<uint64_t>(name, kVariableModePoll) {}
-
- private:
- const uint64_t* GetValue(TimeDelta /* timeout */, string* errmsg) override {
- GetStatusHelper raw(errmsg);
- if (!raw.is_success())
- return nullptr;
-
- return new uint64_t(raw.payload_size());
- }
-
- DISALLOW_COPY_AND_ASSIGN(PayloadSizeVariable);
-};
-
-// A variable reporting the point in time an update last completed in the
-// current boot cycle.
-//
-// TODO(garnold) In general, both the current boottime and wallclock time
-// readings should come from the time provider and be moderated by the
-// evaluation context, so that they are uniform throughout the evaluation of a
-// policy request.
-class UpdateCompletedTimeVariable : public UpdaterVariableBase<Time> {
- public:
- explicit UpdateCompletedTimeVariable(const string& name)
- : UpdaterVariableBase<Time>(name, kVariableModePoll) {}
-
- private:
- const Time* GetValue(TimeDelta /* timeout */, string* errmsg) override {
- Time update_boottime;
- if (!SystemState::Get()->update_attempter()->GetBootTimeAtUpdate(
- &update_boottime)) {
- if (errmsg)
- *errmsg = "Update completed time could not be read";
- return nullptr;
- }
-
- const auto* clock = SystemState::Get()->clock();
- Time curr_boottime = clock->GetBootTime();
- if (curr_boottime < update_boottime) {
- if (errmsg)
- *errmsg = "Update completed time more recent than current time";
- return nullptr;
- }
- TimeDelta duration_since_update = curr_boottime - update_boottime;
- return new Time(clock->GetWallclockTime() - duration_since_update);
- }
-
- DISALLOW_COPY_AND_ASSIGN(UpdateCompletedTimeVariable);
-};
-
-// Variables reporting the current image channel.
-class CurrChannelVariable : public UpdaterVariableBase<string> {
- public:
- explicit CurrChannelVariable(const string& name)
- : UpdaterVariableBase<string>(name, kVariableModePoll) {}
-
- private:
- const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
- OmahaRequestParams* request_params = SystemState::Get()->request_params();
- string channel = request_params->current_channel();
- if (channel.empty()) {
- if (errmsg)
- *errmsg = "No current channel";
- return nullptr;
- }
- return new string(channel);
- }
-
- DISALLOW_COPY_AND_ASSIGN(CurrChannelVariable);
-};
-
-// Variables reporting the new image channel.
-class NewChannelVariable : public UpdaterVariableBase<string> {
- public:
- explicit NewChannelVariable(const string& name)
- : UpdaterVariableBase<string>(name, kVariableModePoll) {}
-
- private:
- const string* GetValue(TimeDelta /* timeout */, string* errmsg) override {
- OmahaRequestParams* request_params = SystemState::Get()->request_params();
- string channel = request_params->target_channel();
- if (channel.empty()) {
- if (errmsg)
- *errmsg = "No new channel";
- return nullptr;
- }
- return new string(channel);
- }
-
- DISALLOW_COPY_AND_ASSIGN(NewChannelVariable);
-};
-
-// A variable class for reading Boolean prefs values.
-class BooleanPrefVariable
- : public AsyncCopyVariable<bool>,
- public chromeos_update_engine::PrefsInterface::ObserverInterface {
- public:
- BooleanPrefVariable(const string& name,
- const char* key,
- bool default_val)
- : AsyncCopyVariable<bool>(name),
- key_(key),
- default_val_(default_val) {
- SystemState::Get()->prefs()->AddObserver(key, this);
- OnPrefSet(key);
- }
- ~BooleanPrefVariable() {
- SystemState::Get()->prefs()->RemoveObserver(key_, this);
- }
-
- private:
- // Reads the actual value from the Prefs instance and updates the Variable
- // value.
- void OnPrefSet(const string& key) override {
- bool result = default_val_;
- auto* prefs = SystemState::Get()->prefs();
- if (prefs->Exists(key_) && !prefs->GetBoolean(key_, &result))
- result = default_val_;
- // AsyncCopyVariable will take care of values that didn't change.
- SetValue(result);
- }
-
- void OnPrefDeleted(const string& key) override { SetValue(default_val_); }
-
- // The Boolean preference key and default value.
- const char* const key_;
- const bool default_val_;
-
- DISALLOW_COPY_AND_ASSIGN(BooleanPrefVariable);
-};
-
-// A variable returning the number of consecutive failed update checks.
-class ConsecutiveFailedUpdateChecksVariable
- : public UpdaterVariableBase<unsigned int> {
- public:
- explicit ConsecutiveFailedUpdateChecksVariable(const string& name)
- : UpdaterVariableBase<unsigned int>(name, kVariableModePoll) {}
-
- private:
- const unsigned int* GetValue(TimeDelta /* timeout */,
- string* /* errmsg */) override {
- // NOLINTNEXTLINE(readability/casting)
- return new unsigned int(SystemState::Get()
- ->update_attempter()
- ->consecutive_failed_update_checks());
- }
-
- DISALLOW_COPY_AND_ASSIGN(ConsecutiveFailedUpdateChecksVariable);
-};
-
-// A variable returning the server-dictated poll interval.
-class ServerDictatedPollIntervalVariable
- : public UpdaterVariableBase<unsigned int> {
- public:
- explicit ServerDictatedPollIntervalVariable(const string& name)
- : UpdaterVariableBase<unsigned int>(name, kVariableModePoll) {}
-
- private:
- const unsigned int* GetValue(TimeDelta /* timeout */,
- string* /* errmsg */) override {
- // NOLINTNEXTLINE(readability/casting)
- return new unsigned int(SystemState::Get()
- ->update_attempter()
- ->server_dictated_poll_interval());
- }
-
- DISALLOW_COPY_AND_ASSIGN(ServerDictatedPollIntervalVariable);
-};
-
-// An async variable that tracks changes to forced update requests.
-class ForcedUpdateRequestedVariable
- : public UpdaterVariableBase<UpdateRequestStatus> {
- public:
- explicit ForcedUpdateRequestedVariable(const string& name)
- : UpdaterVariableBase<UpdateRequestStatus>::UpdaterVariableBase(
- name, kVariableModeAsync) {
- SystemState::Get()->update_attempter()->set_forced_update_pending_callback(
- new base::Callback<void(bool, bool)>( // NOLINT(readability/function)
- base::Bind(&ForcedUpdateRequestedVariable::Reset,
- base::Unretained(this))));
- }
-
- private:
- const UpdateRequestStatus* GetValue(TimeDelta /* timeout */,
- string* /* errmsg */) override {
- return new UpdateRequestStatus(update_request_status_);
- }
-
- void Reset(bool forced_update_requested, bool interactive) {
- UpdateRequestStatus new_value = UpdateRequestStatus::kNone;
- if (forced_update_requested)
- new_value = (interactive ? UpdateRequestStatus::kInteractive
- : UpdateRequestStatus::kPeriodic);
- if (update_request_status_ != new_value) {
- update_request_status_ = new_value;
- NotifyValueChanged();
- }
- }
-
- UpdateRequestStatus update_request_status_ = UpdateRequestStatus::kNone;
-
- DISALLOW_COPY_AND_ASSIGN(ForcedUpdateRequestedVariable);
-};
-
-// A variable returning the current update restrictions that are in effect.
-class UpdateRestrictionsVariable
- : public UpdaterVariableBase<UpdateRestrictions> {
- public:
- explicit UpdateRestrictionsVariable(const string& name)
- : UpdaterVariableBase<UpdateRestrictions>(name, kVariableModePoll) {}
-
- private:
- const UpdateRestrictions* GetValue(TimeDelta /* timeout */,
- string* /* errmsg */) override {
- UpdateAttemptFlags attempt_flags =
- SystemState::Get()->update_attempter()->GetCurrentUpdateAttemptFlags();
- UpdateRestrictions restriction_flags = UpdateRestrictions::kNone;
- // Don't blindly copy the whole value, test and set bits that should
- // transfer from one set of flags to the other.
- if (attempt_flags & UpdateAttemptFlags::kFlagRestrictDownload) {
- restriction_flags = static_cast<UpdateRestrictions>(
- restriction_flags | UpdateRestrictions::kRestrictDownloading);
- }
-
- return new UpdateRestrictions(restriction_flags);
- }
-
- DISALLOW_COPY_AND_ASSIGN(UpdateRestrictionsVariable);
-};
-
-// A variable class for reading timeout interval prefs value.
-class TestUpdateCheckIntervalTimeoutVariable : public Variable<int64_t> {
- public:
- explicit TestUpdateCheckIntervalTimeoutVariable(const string& name)
- : Variable<int64_t>(name, kVariableModePoll), read_count_(0) {
- SetMissingOk();
- }
- ~TestUpdateCheckIntervalTimeoutVariable() = default;
-
- private:
- const int64_t* GetValue(TimeDelta /* timeout */,
- string* /* errmsg */) override {
- auto key = chromeos_update_engine::kPrefsTestUpdateCheckIntervalTimeout;
- auto* prefs = SystemState::Get()->prefs();
- int64_t result;
- if (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;
- }
-
- // 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()
- : var_updater_started_time_(
- "updater_started_time",
- SystemState::Get()->clock()->GetWallclockTime()),
- var_last_checked_time_(new LastCheckedTimeVariable("last_checked_time")),
- var_update_completed_time_(
- new UpdateCompletedTimeVariable("update_completed_time")),
- var_progress_(new ProgressVariable("progress")),
- var_stage_(new StageVariable("stage")),
- var_new_version_(new NewVersionVariable("new_version")),
- var_payload_size_(new PayloadSizeVariable("payload_size")),
- var_curr_channel_(new CurrChannelVariable("curr_channel")),
- var_new_channel_(new NewChannelVariable("new_channel")),
- var_p2p_enabled_(new BooleanPrefVariable(
- "p2p_enabled", chromeos_update_engine::kPrefsP2PEnabled, false)),
- var_cellular_enabled_(new BooleanPrefVariable(
- "cellular_enabled",
- chromeos_update_engine::kPrefsUpdateOverCellularPermission,
- false)),
- var_consecutive_failed_update_checks_(
- new ConsecutiveFailedUpdateChecksVariable(
- "consecutive_failed_update_checks")),
- var_server_dictated_poll_interval_(new ServerDictatedPollIntervalVariable(
- "server_dictated_poll_interval")),
- var_forced_update_requested_(
- new ForcedUpdateRequestedVariable("forced_update_requested")),
- var_update_restrictions_(
- new UpdateRestrictionsVariable("update_restrictions")),
- var_test_update_check_interval_timeout_(
- new TestUpdateCheckIntervalTimeoutVariable(
- "test_update_check_interval_timeout")) {}
-} // namespace chromeos_update_manager
diff --git a/update_manager/real_updater_provider.h b/update_manager/real_updater_provider.h
deleted file mode 100644
index 24298d77..00000000
--- a/update_manager/real_updater_provider.h
+++ /dev/null
@@ -1,123 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_REAL_UPDATER_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_REAL_UPDATER_PROVIDER_H_
-
-#include <memory>
-#include <string>
-
-#include "update_engine/update_manager/generic_variables.h"
-#include "update_engine/update_manager/updater_provider.h"
-
-namespace chromeos_update_manager {
-
-// A concrete UpdaterProvider implementation using local (in-process) bindings.
-class RealUpdaterProvider : public UpdaterProvider {
- public:
- // We assume that any other object handle we get from the system state is
- // "volatile", and so must be re-acquired whenever access is needed; this
- // guarantees that parts of the system state can be mocked out at any time
- // during testing. We further assume that, by the time Init() is called, the
- // system state object is fully populated and usable.
- RealUpdaterProvider();
-
- // Initializes the provider and returns whether it succeeded.
- bool Init() { return true; }
-
- Variable<base::Time>* var_updater_started_time() override {
- return &var_updater_started_time_;
- }
-
- Variable<base::Time>* var_last_checked_time() override {
- return var_last_checked_time_.get();
- }
-
- Variable<base::Time>* var_update_completed_time() override {
- return var_update_completed_time_.get();
- }
-
- Variable<double>* var_progress() override { return var_progress_.get(); }
-
- Variable<Stage>* var_stage() override { return var_stage_.get(); }
-
- Variable<std::string>* var_new_version() override {
- return var_new_version_.get();
- }
-
- Variable<uint64_t>* var_payload_size() override {
- return var_payload_size_.get();
- }
-
- Variable<std::string>* var_curr_channel() override {
- return var_curr_channel_.get();
- }
-
- Variable<std::string>* var_new_channel() override {
- return var_new_channel_.get();
- }
-
- Variable<bool>* var_p2p_enabled() override { return var_p2p_enabled_.get(); }
-
- Variable<bool>* var_cellular_enabled() override {
- return var_cellular_enabled_.get();
- }
-
- Variable<unsigned int>* var_consecutive_failed_update_checks() override {
- return var_consecutive_failed_update_checks_.get();
- }
-
- Variable<unsigned int>* var_server_dictated_poll_interval() override {
- return var_server_dictated_poll_interval_.get();
- }
-
- Variable<UpdateRequestStatus>* var_forced_update_requested() override {
- return var_forced_update_requested_.get();
- }
-
- Variable<UpdateRestrictions>* var_update_restrictions() override {
- return var_update_restrictions_.get();
- }
-
- Variable<int64_t>* var_test_update_check_interval_timeout() override {
- return var_test_update_check_interval_timeout_.get();
- }
-
- private:
- // Variable implementations.
- ConstCopyVariable<base::Time> var_updater_started_time_;
- std::unique_ptr<Variable<base::Time>> var_last_checked_time_;
- std::unique_ptr<Variable<base::Time>> var_update_completed_time_;
- std::unique_ptr<Variable<double>> var_progress_;
- std::unique_ptr<Variable<Stage>> var_stage_;
- std::unique_ptr<Variable<std::string>> var_new_version_;
- std::unique_ptr<Variable<uint64_t>> var_payload_size_;
- std::unique_ptr<Variable<std::string>> var_curr_channel_;
- std::unique_ptr<Variable<std::string>> var_new_channel_;
- std::unique_ptr<Variable<bool>> var_p2p_enabled_;
- std::unique_ptr<Variable<bool>> var_cellular_enabled_;
- std::unique_ptr<Variable<unsigned int>> var_consecutive_failed_update_checks_;
- 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);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_REAL_UPDATER_PROVIDER_H_
diff --git a/update_manager/real_updater_provider_unittest.cc b/update_manager/real_updater_provider_unittest.cc
deleted file mode 100644
index 4afe7fc2..00000000
--- a/update_manager/real_updater_provider_unittest.cc
+++ /dev/null
@@ -1,474 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/real_updater_provider.h"
-
-#include <memory>
-#include <string>
-
-#include <base/time/time.h>
-#include <gtest/gtest.h>
-#include <update_engine/dbus-constants.h>
-
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/cros/mock_update_attempter.h"
-#include "update_engine/cros/omaha_request_params.h"
-#include "update_engine/update_manager/umtest_utils.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::FakePrefs;
-using chromeos_update_engine::FakeSystemState;
-using chromeos_update_engine::OmahaRequestParams;
-using std::string;
-using std::unique_ptr;
-using testing::_;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgPointee;
-using update_engine::UpdateAttemptFlags;
-
-namespace {
-
-// Generates a fixed timestamp for use in faking the current time.
-Time FixedTime() {
- Time::Exploded now_exp;
- now_exp.year = 2014;
- now_exp.month = 3;
- now_exp.day_of_week = 2;
- now_exp.day_of_month = 18;
- now_exp.hour = 8;
- now_exp.minute = 5;
- now_exp.second = 33;
- now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
-}
-
-// Rounds down a timestamp to the nearest second. This is useful when faking
-// times that are converted to time_t (no sub-second resolution).
-Time RoundedToSecond(Time time) {
- Time::Exploded exp;
- time.LocalExplode(&exp);
- exp.millisecond = 0;
- Time rounded_time;
- ignore_result(Time::FromLocalExploded(exp, &rounded_time));
- return rounded_time;
-}
-
-ACTION_P(ActionSetUpdateEngineStatusLastCheckedTime, time) {
- arg0->last_checked_time = time;
-};
-
-ACTION_P(ActionSetUpdateEngineStatusProgress, progress) {
- arg0->progress = progress;
-};
-
-ACTION_P(ActionSetUpdateEngineStatusStatus, status) {
- arg0->status = status;
-}
-
-ACTION_P(ActionSetUpdateEngineStatusNewVersion, new_version) {
- arg0->new_version = new_version;
-}
-
-ACTION_P(ActionSetUpdateEngineStatusNewSizeBytes, new_size_bytes) {
- arg0->new_size_bytes = new_size_bytes;
-}
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-class UmRealUpdaterProviderTest : public ::testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
- provider_.reset(new RealUpdaterProvider());
- // Check that provider initializes correctly.
- ASSERT_TRUE(provider_->Init());
- }
-
- // Sets up mock expectations for testing the update completed time reporting.
- // |valid| determines whether the returned time is valid. Returns the expected
- // update completed time value.
- Time SetupUpdateCompletedTime(bool valid) {
- const TimeDelta kDurationSinceUpdate = TimeDelta::FromMinutes(7);
- const Time kUpdateBootTime = Time() + kDurationSinceUpdate * 2;
- const Time kCurrBootTime = (valid ? kUpdateBootTime + kDurationSinceUpdate
- : kUpdateBootTime - kDurationSinceUpdate);
- const Time kCurrWallclockTime = FixedTime();
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(),
- GetBootTimeAtUpdate(_))
- .WillOnce(DoAll(SetArgPointee<0>(kUpdateBootTime), Return(true)));
- FakeSystemState::Get()->fake_clock()->SetBootTime(kCurrBootTime);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(kCurrWallclockTime);
- return kCurrWallclockTime - kDurationSinceUpdate;
- }
-
- unique_ptr<RealUpdaterProvider> provider_;
-};
-
-TEST_F(UmRealUpdaterProviderTest, UpdaterStartedTimeIsWallclockTime) {
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(
- Time::FromDoubleT(123.456));
- FakeSystemState::Get()->fake_clock()->SetMonotonicTime(
- Time::FromDoubleT(456.123));
- // Re-initialize to re-setup the provider under test to use these values.
- provider_.reset(new RealUpdaterProvider());
- ASSERT_TRUE(provider_->Init());
- UmTestUtils::ExpectVariableHasValue(Time::FromDoubleT(123.456),
- provider_->var_updater_started_time());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetLastCheckedTimeOkay) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(
- ActionSetUpdateEngineStatusLastCheckedTime(FixedTime().ToTimeT()),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(RoundedToSecond(FixedTime()),
- provider_->var_last_checked_time());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetLastCheckedTimeFailNoValue) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(Return(false));
- UmTestUtils::ExpectVariableNotSet(provider_->var_last_checked_time());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetProgressOkayMin) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusProgress(0.0), Return(true)));
- UmTestUtils::ExpectVariableHasValue(0.0, provider_->var_progress());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetProgressOkayMid) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusProgress(0.3), Return(true)));
- UmTestUtils::ExpectVariableHasValue(0.3, provider_->var_progress());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetProgressOkayMax) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusProgress(1.0), Return(true)));
- UmTestUtils::ExpectVariableHasValue(1.0, provider_->var_progress());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetProgressFailNoValue) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(Return(false));
- UmTestUtils::ExpectVariableNotSet(provider_->var_progress());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetProgressFailTooSmall) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusProgress(-2.0), Return(true)));
- UmTestUtils::ExpectVariableNotSet(provider_->var_progress());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetProgressFailTooBig) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusProgress(2.0), Return(true)));
- UmTestUtils::ExpectVariableNotSet(provider_->var_progress());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayIdle) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(
- ActionSetUpdateEngineStatusStatus(update_engine::UpdateStatus::IDLE),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kIdle, provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayCheckingForUpdate) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::CHECKING_FOR_UPDATE),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kCheckingForUpdate,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayUpdateAvailable) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::UPDATE_AVAILABLE),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kUpdateAvailable,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayDownloading) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::DOWNLOADING),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kDownloading,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayVerifying) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::VERIFYING),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kVerifying,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayFinalizing) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::FINALIZING),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kFinalizing,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayUpdatedNeedReboot) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::UPDATED_NEED_REBOOT),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kUpdatedNeedReboot,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayReportingErrorEvent) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::REPORTING_ERROR_EVENT),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kReportingErrorEvent,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageOkayAttemptingRollback) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusStatus(
- update_engine::UpdateStatus::ATTEMPTING_ROLLBACK),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(Stage::kAttemptingRollback,
- provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetStageFailNoValue) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(Return(false));
- UmTestUtils::ExpectVariableNotSet(provider_->var_stage());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetNewVersionOkay) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(
- DoAll(ActionSetUpdateEngineStatusNewVersion("1.2.0"), Return(true)));
- UmTestUtils::ExpectVariableHasValue(string("1.2.0"),
- provider_->var_new_version());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetNewVersionFailNoValue) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(Return(false));
- UmTestUtils::ExpectVariableNotSet(provider_->var_new_version());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeOkayZero) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(
- ActionSetUpdateEngineStatusNewSizeBytes(static_cast<uint64_t>(0)),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(static_cast<uint64_t>(0),
- provider_->var_payload_size());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeOkayArbitrary) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusNewSizeBytes(
- static_cast<uint64_t>(567890)),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(static_cast<uint64_t>(567890),
- provider_->var_payload_size());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeOkayTwoGigabytes) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(DoAll(ActionSetUpdateEngineStatusNewSizeBytes(
- static_cast<uint64_t>(1) << 31),
- Return(true)));
- UmTestUtils::ExpectVariableHasValue(static_cast<uint64_t>(1) << 31,
- provider_->var_payload_size());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetPayloadSizeFailNoValue) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(), GetStatus(_))
- .WillOnce(Return(false));
- UmTestUtils::ExpectVariableNotSet(provider_->var_payload_size());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetCurrChannelOkay) {
- const string kChannelName("foo-channel");
- OmahaRequestParams request_params;
- request_params.Init("", "", {});
- request_params.set_current_channel(kChannelName);
- FakeSystemState::Get()->set_request_params(&request_params);
- UmTestUtils::ExpectVariableHasValue(kChannelName,
- provider_->var_curr_channel());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetCurrChannelFailEmpty) {
- OmahaRequestParams request_params;
- request_params.Init("", "", {});
- request_params.set_current_channel("");
- FakeSystemState::Get()->set_request_params(&request_params);
- UmTestUtils::ExpectVariableNotSet(provider_->var_curr_channel());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetNewChannelOkay) {
- const string kChannelName("foo-channel");
- OmahaRequestParams request_params;
- request_params.Init("", "", {});
- request_params.set_target_channel(kChannelName);
- FakeSystemState::Get()->set_request_params(&request_params);
- UmTestUtils::ExpectVariableHasValue(kChannelName,
- provider_->var_new_channel());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetNewChannelFailEmpty) {
- OmahaRequestParams request_params;
- request_params.Init("", "", {});
- request_params.set_target_channel("");
- FakeSystemState::Get()->set_request_params(&request_params);
- UmTestUtils::ExpectVariableNotSet(provider_->var_new_channel());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledOkayPrefDoesntExist) {
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_p2p_enabled());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledOkayPrefReadsFalse) {
- FakeSystemState::Get()->fake_prefs()->SetBoolean(
- chromeos_update_engine::kPrefsP2PEnabled, false);
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_p2p_enabled());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledReadWhenInitialized) {
- FakeSystemState::Get()->fake_prefs()->SetBoolean(
- chromeos_update_engine::kPrefsP2PEnabled, true);
- provider_.reset(new RealUpdaterProvider());
- ASSERT_TRUE(provider_->Init());
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_p2p_enabled());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetP2PEnabledUpdated) {
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- fake_prefs->SetBoolean(chromeos_update_engine::kPrefsP2PEnabled, false);
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_p2p_enabled());
- fake_prefs->SetBoolean(chromeos_update_engine::kPrefsP2PEnabled, true);
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_p2p_enabled());
- fake_prefs->Delete(chromeos_update_engine::kPrefsP2PEnabled);
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_p2p_enabled());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetCellularEnabledOkayPrefDoesntExist) {
- UmTestUtils::ExpectVariableHasValue(false, provider_->var_cellular_enabled());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetCellularEnabledOkayPrefReadsTrue) {
- FakeSystemState::Get()->fake_prefs()->SetBoolean(
- chromeos_update_engine::kPrefsUpdateOverCellularPermission, true);
- UmTestUtils::ExpectVariableHasValue(true, provider_->var_cellular_enabled());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetUpdateCompletedTimeOkay) {
- Time expected = SetupUpdateCompletedTime(true);
- UmTestUtils::ExpectVariableHasValue(expected,
- provider_->var_update_completed_time());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetUpdateCompletedTimeFailNoValue) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(),
- GetBootTimeAtUpdate(_))
- .WillOnce(Return(false));
- UmTestUtils::ExpectVariableNotSet(provider_->var_update_completed_time());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetUpdateCompletedTimeFailInvalidValue) {
- SetupUpdateCompletedTime(false);
- UmTestUtils::ExpectVariableNotSet(provider_->var_update_completed_time());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetConsecutiveFailedUpdateChecks) {
- const unsigned int kNumFailedChecks = 3;
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(),
- consecutive_failed_update_checks())
- .WillRepeatedly(Return(kNumFailedChecks));
- UmTestUtils::ExpectVariableHasValue(
- kNumFailedChecks, provider_->var_consecutive_failed_update_checks());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetServerDictatedPollInterval) {
- const unsigned int kPollInterval = 2 * 60 * 60; // Two hours.
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(),
- server_dictated_poll_interval())
- .WillRepeatedly(Return(kPollInterval));
- UmTestUtils::ExpectVariableHasValue(
- kPollInterval, provider_->var_server_dictated_poll_interval());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetUpdateRestrictions) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(),
- GetCurrentUpdateAttemptFlags())
- .WillRepeatedly(Return(UpdateAttemptFlags::kFlagRestrictDownload |
- UpdateAttemptFlags::kFlagNonInteractive));
- UmTestUtils::ExpectVariableHasValue(UpdateRestrictions::kRestrictDownloading,
- provider_->var_update_restrictions());
-}
-
-TEST_F(UmRealUpdaterProviderTest, GetUpdateRestrictionsNone) {
- EXPECT_CALL(*FakeSystemState::Get()->mock_update_attempter(),
- GetCurrentUpdateAttemptFlags())
- .WillRepeatedly(Return(UpdateAttemptFlags::kNone));
- UmTestUtils::ExpectVariableHasValue(UpdateRestrictions::kNone,
- provider_->var_update_restrictions());
-}
-
-TEST_F(UmRealUpdaterProviderTest, TestUpdateCheckIntervalTimeout) {
- UmTestUtils::ExpectVariableNotSet(
- provider_->var_test_update_check_interval_timeout());
- auto* fake_prefs = FakeSystemState::Get()->fake_prefs();
- 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
deleted file mode 100644
index 6cbc447d..00000000
--- a/update_manager/rollback_prefs.h
+++ /dev/null
@@ -1,53 +0,0 @@
-//
-// Copyright (C) 2018 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_UPDATE_MANAGER_ROLLBACK_PREFS_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_ROLLBACK_PREFS_H_
-
-namespace chromeos_update_manager {
-
-// Value used to represent that kernel key versions can always roll-forward.
-// This is the maximum value of a kernel key version.
-constexpr int kRollforwardInfinity = 0xfffffffe;
-
-// Whether the device should roll back to the target version, and if yes, which
-// type of rollback should it do. Matches chrome_device_policy.proto's
-// AutoUpdateSettingsProto::RollbackToTargetVersion.
-enum class RollbackToTargetVersion {
- kUnspecified = 0,
- kDisabled = 1,
- kRollbackAndPowerwash = 2,
- kRollbackAndRestoreIfPossible = 3,
- // This value must be the last entry.
- 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/shill_provider.h b/update_manager/shill_provider.h
deleted file mode 100644
index ebe7a3ae..00000000
--- a/update_manager/shill_provider.h
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_SHILL_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_SHILL_PROVIDER_H_
-
-#include <base/time/time.h>
-
-#include "update_engine/common/connection_utils.h"
-#include "update_engine/update_manager/provider.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// Provider for networking related information.
-class ShillProvider : public Provider {
- public:
- ~ShillProvider() override {}
-
- // A variable returning whether we currently have network connectivity.
- virtual Variable<bool>* var_is_connected() = 0;
-
- // A variable returning the current network connection type. Unknown if not
- // connected.
- virtual Variable<chromeos_update_engine::ConnectionType>* var_conn_type() = 0;
-
- // A variable returning the tethering mode of a network connection. Unknown if
- // not connected.
- virtual Variable<chromeos_update_engine::ConnectionTethering>*
- var_conn_tethering() = 0;
-
- // A variable returning the time when network connection last changed.
- // Initialized to current time.
- virtual Variable<base::Time>* var_conn_last_changed() = 0;
-
- protected:
- ShillProvider() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ShillProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_SHILL_PROVIDER_H_
diff --git a/update_manager/staging_utils.cc b/update_manager/staging_utils.cc
deleted file mode 100644
index a9929751..00000000
--- a/update_manager/staging_utils.cc
+++ /dev/null
@@ -1,140 +0,0 @@
-//
-// Copyright (C) 2018 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/update_manager/staging_utils.h"
-
-#include <utility>
-#include <vector>
-
-#include <base/logging.h>
-#include <base/rand_util.h>
-#include <base/time/time.h>
-#include <policy/device_policy.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/common/hardware_interface.h"
-#include "update_engine/common/system_state.h"
-
-using base::TimeDelta;
-using chromeos_update_engine::kPrefsWallClockStagingWaitPeriod;
-using chromeos_update_engine::SystemState;
-using policy::DevicePolicy;
-
-namespace chromeos_update_manager {
-
-int GetStagingSchedule(const DevicePolicy* device_policy,
- StagingSchedule* staging_schedule_out) {
- StagingSchedule staging_schedule;
- if (!device_policy->GetDeviceUpdateStagingSchedule(&staging_schedule) ||
- staging_schedule.empty()) {
- return 0;
- }
-
- // Last percentage of the schedule should be 100.
- if (staging_schedule.back().percentage != 100) {
- LOG(ERROR) << "Last percentage of the schedule is not 100, it's: "
- << staging_schedule.back().percentage;
- return 0;
- }
-
- int previous_days = 0;
- int previous_percentage = -1;
- // Ensure that the schedule has a monotonically increasing set of percentages
- // and that days are also monotonically increasing.
- for (const auto& staging_pair : staging_schedule) {
- int days = staging_pair.days;
- if (previous_days >= days) {
- LOG(ERROR) << "Days in staging schedule are not monotonically "
- << "increasing. Previous value: " << previous_days
- << " Current value: " << days;
- return 0;
- }
- previous_days = days;
- int percentage = staging_pair.percentage;
- if (previous_percentage >= percentage) {
- LOG(ERROR) << "Percentages in staging schedule are not monotonically "
- << "increasing. Previous value: " << previous_percentage
- << " Current value: " << percentage;
- return 0;
- }
- previous_percentage = percentage;
- }
- // Modify staging schedule only if the schedule in the device policy is valid.
- if (staging_schedule_out)
- *staging_schedule_out = std::move(staging_schedule);
-
- return previous_days;
-}
-
-int CalculateWaitTimeInDaysFromSchedule(
- const StagingSchedule& staging_schedule) {
- int prev_days = 0;
- int percentage_position = base::RandInt(1, 100);
- for (const auto& staging_pair : staging_schedule) {
- int days = staging_pair.days;
- if (percentage_position <= staging_pair.percentage) {
- // Scatter between the start of the range and the end.
- return prev_days + base::RandInt(1, days - prev_days);
- }
- prev_days = days;
- }
- // Something went wrong.
- NOTREACHED();
- return 0;
-}
-
-StagingCase CalculateStagingCase(const DevicePolicy* device_policy,
- TimeDelta* staging_wait_time,
- StagingSchedule* staging_schedule) {
- // Check that the schedule in the device policy is correct.
- StagingSchedule new_staging_schedule;
- int max_days = GetStagingSchedule(device_policy, &new_staging_schedule);
- if (max_days == 0)
- return StagingCase::kOff;
-
- // Calculate the new wait time.
- TimeDelta new_staging_wait_time = TimeDelta::FromDays(
- CalculateWaitTimeInDaysFromSchedule(new_staging_schedule));
- DCHECK_GT(new_staging_wait_time.InSeconds(), 0);
- if (staging_wait_time->InSeconds() > 0) {
- // If there hasn't been any changes to the schedule and there is a value
- // set, don't change the waiting time.
- if (new_staging_schedule == *staging_schedule) {
- return StagingCase::kNoAction;
- }
- // Otherwise, update the schedule and wait time.
- *staging_wait_time = new_staging_wait_time;
- *staging_schedule = std::move(new_staging_schedule);
- return StagingCase::kNoSavedValue;
- }
- // Getting this means the schedule changed, update the old schedule.
- *staging_schedule = std::move(new_staging_schedule);
-
- int64_t wait_period_in_days;
- // There exists a persisted value that is valid. That is, it's smaller than
- // the maximum amount of days of staging set by the user.
- if (SystemState::Get()->prefs()->GetInt64(kPrefsWallClockStagingWaitPeriod,
- &wait_period_in_days) &&
- wait_period_in_days > 0 && wait_period_in_days <= max_days) {
- *staging_wait_time = TimeDelta::FromDays(wait_period_in_days);
- return StagingCase::kSetStagingFromPref;
- }
-
- *staging_wait_time = new_staging_wait_time;
- return StagingCase::kNoSavedValue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/staging_utils.h b/update_manager/staging_utils.h
deleted file mode 100644
index 0de1dfdc..00000000
--- a/update_manager/staging_utils.h
+++ /dev/null
@@ -1,70 +0,0 @@
-//
-// Copyright (C) 2018 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_UPDATE_MANAGER_STAGING_UTILS_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_STAGING_UTILS_H_
-
-#include <utility>
-#include <vector>
-
-#include <base/time/time.h>
-#include <policy/device_policy.h>
-
-#include "update_engine/common/prefs_interface.h"
-
-namespace chromeos_update_manager {
-
-using StagingSchedule = std::vector<policy::DevicePolicy::DayPercentagePair>;
-
-// Possible cases that staging might run into based on the inputs.
-enum class StagingCase {
- // Staging is off, remove the persisted value.
- kOff,
- // Staging is enabled, but there is no valid persisted value, saved value or
- // the value of the schedule has changed.
- kNoSavedValue,
- // Staging is enabled, and there is a valid persisted value.
- kSetStagingFromPref,
- // Staging is enabled, and there have been no changes to the schedule.
- kNoAction
-};
-
-// Calculate the bucket in which the device belongs based on a given staging
-// schedule. |staging_schedule| is assumed to have already been validated.
-int CalculateWaitTimeInDaysFromSchedule(
- const StagingSchedule& staging_schedule);
-
-// Verifies that |device_policy| contains a valid staging schedule. If
-// |device_policy| contains a valid staging schedule, move it into
-// |staging_schedule_out| and return the total number of days spanned by the
-// schedule. Otherwise, don't modify |staging_schedule_out| and return 0 (which
-// is an invalid value for the length of a schedule).
-int GetStagingSchedule(const policy::DevicePolicy* device_policy,
- StagingSchedule* staging_schedule_out);
-
-// Uses the given arguments to check whether staging is on, and whether the
-// state should be updated with a new waiting time or not. |staging_wait_time|
-// should contain the old value of the wait time, it will be replaced with the
-// new calculated wait time value if staging is on. |staging_schedule| should
-// contain the previous staging schedule, if there is a new schedule found, its
-// value will be replaced with the new one.
-StagingCase CalculateStagingCase(const policy::DevicePolicy* device_policy,
- base::TimeDelta* staging_wait_time,
- StagingSchedule* staging_schedule);
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_STAGING_UTILS_H_
diff --git a/update_manager/staging_utils_unittest.cc b/update_manager/staging_utils_unittest.cc
deleted file mode 100644
index 126617f1..00000000
--- a/update_manager/staging_utils_unittest.cc
+++ /dev/null
@@ -1,174 +0,0 @@
-//
-// Copyright (C) 2018 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/update_manager/staging_utils.h"
-
-#include <memory>
-#include <utility>
-
-#include <base/time/time.h>
-#include <gtest/gtest.h>
-#include <policy/mock_device_policy.h>
-
-#include "update_engine/common/constants.h"
-#include "update_engine/cros/fake_system_state.h"
-
-using base::TimeDelta;
-using chromeos_update_engine::FakeSystemState;
-using chromeos_update_engine::kPrefsWallClockStagingWaitPeriod;
-using testing::_;
-using testing::DoAll;
-using testing::Return;
-using testing::SetArgPointee;
-
-namespace chromeos_update_manager {
-
-constexpr TimeDelta kDay = TimeDelta::FromDays(1);
-constexpr int kMaxDays = 28;
-constexpr int kValidDaySum = 14;
-const StagingSchedule valid_schedule = {{2, 0}, {7, 50}, {9, 80}, {14, 100}};
-
-class StagingUtilsScheduleTest : public testing::Test {
- protected:
- void SetUp() override {
- FakeSystemState::CreateInstance();
- test_wait_time_ = TimeDelta();
- test_staging_schedule_ = StagingSchedule();
- }
-
- void SetStagingSchedule(const StagingSchedule& staging_schedule) {
- EXPECT_CALL(device_policy_, GetDeviceUpdateStagingSchedule(_))
- .WillRepeatedly(
- DoAll(SetArgPointee<0>(staging_schedule), Return(true)));
- }
-
- void SetPersistedStagingVal(int64_t wait_time) {
- EXPECT_TRUE(FakeSystemState::Get()->fake_prefs()->SetInt64(
- kPrefsWallClockStagingWaitPeriod, wait_time));
- }
-
- void TestStagingCase(const StagingCase& expected) {
- EXPECT_EQ(expected,
- CalculateStagingCase(&device_policy_,
- &test_wait_time_,
- &test_staging_schedule_));
- }
-
- void ExpectNoChanges() {
- EXPECT_EQ(TimeDelta(), test_wait_time_);
- EXPECT_EQ(StagingSchedule(), test_staging_schedule_);
- }
-
- policy::MockDevicePolicy device_policy_;
- TimeDelta test_wait_time_;
- StagingSchedule test_staging_schedule_;
-};
-
-// Last element should be 100, if not return false.
-TEST_F(StagingUtilsScheduleTest, GetStagingScheduleInvalidLastElem) {
- SetStagingSchedule(StagingSchedule{{2, 10}, {4, 20}, {5, 40}});
- EXPECT_EQ(0, GetStagingSchedule(&device_policy_, &test_staging_schedule_));
- ExpectNoChanges();
-}
-
-// Percentage should be monotonically increasing.
-TEST_F(StagingUtilsScheduleTest, GetStagingScheduleNonMonotonic) {
- SetStagingSchedule(StagingSchedule{{2, 10}, {6, 20}, {11, 20}, {12, 100}});
- EXPECT_EQ(0, GetStagingSchedule(&device_policy_, &test_staging_schedule_));
- ExpectNoChanges();
-}
-
-// The days should be monotonically increasing.
-TEST_F(StagingUtilsScheduleTest, GetStagingScheduleOverMaxDays) {
- SetStagingSchedule(StagingSchedule{{2, 10}, {4, 20}, {15, 30}, {10, 100}});
- EXPECT_EQ(0, GetStagingSchedule(&device_policy_, &test_staging_schedule_));
- ExpectNoChanges();
-}
-
-TEST_F(StagingUtilsScheduleTest, GetStagingScheduleValid) {
- SetStagingSchedule(valid_schedule);
- EXPECT_EQ(kValidDaySum,
- GetStagingSchedule(&device_policy_, &test_staging_schedule_));
- EXPECT_EQ(test_staging_schedule_, valid_schedule);
-}
-
-TEST_F(StagingUtilsScheduleTest, StagingOffNoSchedule) {
- // If the function returns false, the schedule shouldn't get used.
- EXPECT_CALL(device_policy_, GetDeviceUpdateStagingSchedule(_))
- .WillRepeatedly(DoAll(SetArgPointee<0>(valid_schedule), Return(false)));
- TestStagingCase(StagingCase::kOff);
- ExpectNoChanges();
-}
-
-TEST_F(StagingUtilsScheduleTest, StagingOffEmptySchedule) {
- SetStagingSchedule(StagingSchedule());
- TestStagingCase(StagingCase::kOff);
- ExpectNoChanges();
-}
-
-TEST_F(StagingUtilsScheduleTest, StagingOffInvalidSchedule) {
- // Any invalid schedule should return |StagingCase::kOff|.
- SetStagingSchedule(StagingSchedule{{3, 30}, {6, 40}});
- TestStagingCase(StagingCase::kOff);
- ExpectNoChanges();
-}
-
-TEST_F(StagingUtilsScheduleTest, StagingOnNoAction) {
- test_wait_time_ = kDay;
- // Same as valid schedule, just using std::pair types.
- StagingSchedule valid_schedule_pairs = {{2, 0}, {7, 50}, {9, 80}, {14, 100}};
- test_staging_schedule_ = valid_schedule_pairs;
- SetStagingSchedule(valid_schedule);
- TestStagingCase(StagingCase::kNoAction);
- // Vars should not be changed.
- EXPECT_EQ(kDay, test_wait_time_);
- EXPECT_EQ(test_staging_schedule_, valid_schedule_pairs);
-}
-
-TEST_F(StagingUtilsScheduleTest, StagingNoSavedValueChangePolicy) {
- test_wait_time_ = kDay;
- SetStagingSchedule(valid_schedule);
- TestStagingCase(StagingCase::kNoSavedValue);
- // Vars should change since < 2 days should not be possible due to
- // valid_schedule's value.
- EXPECT_NE(kDay, test_wait_time_);
- EXPECT_EQ(test_staging_schedule_, valid_schedule);
- EXPECT_LE(test_wait_time_, kDay * kMaxDays);
-}
-
-// Tests the case where there was a reboot and there is no persisted value.
-TEST_F(StagingUtilsScheduleTest, StagingNoSavedValueNoPersisted) {
- SetStagingSchedule(valid_schedule);
- TestStagingCase(StagingCase::kNoSavedValue);
- // Vars should change since there are no preset values and there is a new
- // staging schedule.
- EXPECT_NE(TimeDelta(), test_wait_time_);
- EXPECT_EQ(test_staging_schedule_, valid_schedule);
- EXPECT_LE(test_wait_time_, kDay * kMaxDays);
-}
-
-// If there is a pref set and its value is less than the day count, use that
-// pref.
-TEST_F(StagingUtilsScheduleTest, StagingSetFromPref) {
- SetStagingSchedule(valid_schedule);
- SetPersistedStagingVal(5);
- TestStagingCase(StagingCase::kSetStagingFromPref);
- // Vars should change.
- EXPECT_EQ(kDay * 5, test_wait_time_);
- EXPECT_EQ(test_staging_schedule_, valid_schedule);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/state.h b/update_manager/state.h
deleted file mode 100644
index d4280599..00000000
--- a/update_manager/state.h
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_STATE_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_STATE_H_
-
-#include "update_engine/update_manager/config_provider.h"
-#include "update_engine/update_manager/device_policy_provider.h"
-#include "update_engine/update_manager/random_provider.h"
-#include "update_engine/update_manager/shill_provider.h"
-#include "update_engine/update_manager/system_provider.h"
-#include "update_engine/update_manager/time_provider.h"
-#include "update_engine/update_manager/updater_provider.h"
-
-namespace chromeos_update_manager {
-
-// The State class is an interface to the ensemble of providers. This class
-// gives visibility of the state providers to policy implementations.
-class State {
- public:
- virtual ~State() {}
-
- // These methods return the given provider.
- virtual ConfigProvider* config_provider() = 0;
- virtual DevicePolicyProvider* device_policy_provider() = 0;
- virtual RandomProvider* random_provider() = 0;
- virtual ShillProvider* shill_provider() = 0;
- virtual SystemProvider* system_provider() = 0;
- virtual TimeProvider* time_provider() = 0;
- virtual UpdaterProvider* updater_provider() = 0;
-
- protected:
- State() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(State);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_STATE_H_
diff --git a/update_manager/state_factory.cc b/update_manager/state_factory.cc
deleted file mode 100644
index 0ab4f7be..00000000
--- a/update_manager/state_factory.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/state_factory.h"
-
-#include <memory>
-
-#include <base/logging.h>
-#if USE_DBUS
-#include <session_manager/dbus-proxies.h>
-#endif // USE_DBUS
-
-#if USE_DBUS
-#include "update_engine/cros/dbus_connection.h"
-#endif // USE_DBUS
-#include "update_engine/common/system_state.h"
-#include "update_engine/cros/shill_proxy.h"
-#include "update_engine/update_manager/fake_shill_provider.h"
-#include "update_engine/update_manager/real_config_provider.h"
-#include "update_engine/update_manager/real_device_policy_provider.h"
-#include "update_engine/update_manager/real_random_provider.h"
-#include "update_engine/update_manager/real_shill_provider.h"
-#include "update_engine/update_manager/real_state.h"
-#include "update_engine/update_manager/real_system_provider.h"
-#include "update_engine/update_manager/real_time_provider.h"
-#include "update_engine/update_manager/real_updater_provider.h"
-
-using chromeos_update_engine::SystemState;
-using std::unique_ptr;
-
-namespace chromeos_update_manager {
-
-State* DefaultStateFactory(
- policy::PolicyProvider* policy_provider,
- org::chromium::KioskAppServiceInterfaceProxyInterface* kiosk_app_proxy) {
- unique_ptr<RealConfigProvider> config_provider(
- new RealConfigProvider(SystemState::Get()->hardware()));
-#if USE_DBUS
- scoped_refptr<dbus::Bus> bus =
- chromeos_update_engine::DBusConnection::Get()->GetDBus();
- unique_ptr<RealDevicePolicyProvider> device_policy_provider(
- new RealDevicePolicyProvider(
- std::make_unique<org::chromium::SessionManagerInterfaceProxy>(bus),
- policy_provider));
-#else
- unique_ptr<RealDevicePolicyProvider> device_policy_provider(
- new RealDevicePolicyProvider(policy_provider));
-#endif // USE_DBUS
- unique_ptr<RealShillProvider> shill_provider(
- new RealShillProvider(new chromeos_update_engine::ShillProxy()));
- unique_ptr<RealRandomProvider> random_provider(new RealRandomProvider());
- unique_ptr<RealSystemProvider> system_provider(
- new RealSystemProvider(kiosk_app_proxy));
-
- unique_ptr<RealTimeProvider> time_provider(new RealTimeProvider());
- unique_ptr<RealUpdaterProvider> updater_provider(new RealUpdaterProvider());
-
- if (!(config_provider->Init() && device_policy_provider->Init() &&
- random_provider->Init() &&
- shill_provider->Init() &&
- system_provider->Init() && time_provider->Init() &&
- updater_provider->Init())) {
- LOG(ERROR) << "Error initializing providers";
- return nullptr;
- }
-
- return new RealState(config_provider.release(),
- device_policy_provider.release(),
- random_provider.release(),
- shill_provider.release(),
- system_provider.release(),
- time_provider.release(),
- updater_provider.release());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/state_factory.h b/update_manager/state_factory.h
deleted file mode 100644
index c53bb9cb..00000000
--- a/update_manager/state_factory.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_STATE_FACTORY_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_STATE_FACTORY_H_
-
-#include "update_engine/update_manager/state.h"
-
-namespace org {
-namespace chromium {
-class KioskAppServiceInterfaceProxyInterface;
-} // namespace chromium
-} // namespace org
-
-namespace chromeos_update_manager {
-
-// Creates and initializes a new UpdateManager State instance containing real
-// providers instantiated using the passed interfaces. The State doesn't take
-// ownership of the passed interfaces, which need to remain available during the
-// life of this instance. Returns null if one of the underlying providers fails
-// to initialize.
-State* DefaultStateFactory(
- policy::PolicyProvider* policy_provider,
- org::chromium::KioskAppServiceInterfaceProxyInterface* kiosk_app_proxy);
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_STATE_FACTORY_H_
diff --git a/update_manager/system_provider.h b/update_manager/system_provider.h
deleted file mode 100644
index 8eb14e3b..00000000
--- a/update_manager/system_provider.h
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_SYSTEM_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_SYSTEM_PROVIDER_H_
-
-#include <string>
-
-#include <base/version.h>
-
-#include "update_engine/update_manager/provider.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// Provider for system information, mostly constant, such as the information
-// reported by crossystem, the kernel boot command line and the partition table.
-class SystemProvider : public Provider {
- public:
- ~SystemProvider() override {}
-
- // Returns true if the boot mode is normal or if it's unable to
- // determine the boot mode. Returns false if the boot mode is
- // developer.
- virtual Variable<bool>* var_is_normal_boot_mode() = 0;
-
- // Returns whether this is an official Chrome OS build.
- virtual Variable<bool>* var_is_official_build() = 0;
-
- // Returns a variable that tells whether OOBE was completed.
- virtual Variable<bool>* var_is_oobe_complete() = 0;
-
- // Returns a variable that tells the number of slots in the system.
- virtual Variable<unsigned int>* var_num_slots() = 0;
-
- // Returns the required platform version of the configured auto launch
- // with zero delay kiosk app if any.
- virtual Variable<std::string>* var_kiosk_required_platform_version() = 0;
-
- // Chrome OS version number as provided by |ImagePropeties|.
- virtual Variable<base::Version>* var_chromeos_version() = 0;
-
- protected:
- SystemProvider() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SystemProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_SYSTEM_PROVIDER_H_
diff --git a/update_manager/time_provider.h b/update_manager/time_provider.h
deleted file mode 100644
index 94f4a8f0..00000000
--- a/update_manager/time_provider.h
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_TIME_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_TIME_PROVIDER_H_
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/provider.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// Provider for time related information.
-class TimeProvider : public Provider {
- public:
- ~TimeProvider() override {}
-
- // Returns the current date. The time of day component will be zero.
- virtual Variable<base::Time>* var_curr_date() = 0;
-
- // Returns the current hour (0 to 23) in local time. The type is int to keep
- // consistent with base::Time.
- virtual Variable<int>* var_curr_hour() = 0;
-
- // Returns the current minutes (0 to 60) in local time.
- virtual Variable<int>* var_curr_minute() = 0;
-
- protected:
- TimeProvider() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TimeProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_TIME_PROVIDER_H_
diff --git a/update_manager/umtest_utils.cc b/update_manager/umtest_utils.cc
deleted file mode 100644
index aa88141c..00000000
--- a/update_manager/umtest_utils.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/umtest_utils.h"
-
-#include <base/time/time.h>
-
-namespace chromeos_update_manager {
-
-const unsigned UmTestUtils::kDefaultTimeoutInSeconds = 1;
-
-void PrintTo(const EvalStatus& status, ::std::ostream* os) {
- *os << ToString(status);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/umtest_utils.h b/update_manager/umtest_utils.h
deleted file mode 100644
index 576f53c9..00000000
--- a/update_manager/umtest_utils.h
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_UMTEST_UTILS_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_UMTEST_UTILS_H_
-
-#include <iostream> // NOLINT(readability/streams)
-#include <memory>
-
-#include <base/time/time.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/update_manager/policy.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-// A help class with common functionality for use in Update Manager testing.
-class UmTestUtils {
- public:
- // A default timeout to use when making various queries.
- static const base::TimeDelta DefaultTimeout() {
- return base::TimeDelta::FromSeconds(kDefaultTimeoutInSeconds);
- }
-
- // Calls GetValue on |variable| and expects its result to be |expected|.
- template <typename T>
- static void ExpectVariableHasValue(const T& expected, Variable<T>* variable) {
- ASSERT_NE(nullptr, variable);
- std::unique_ptr<const T> value(
- variable->GetValue(DefaultTimeout(), nullptr));
- ASSERT_NE(nullptr, value.get()) << "Variable: " << variable->GetName();
- EXPECT_EQ(expected, *value) << "Variable: " << variable->GetName();
- }
-
- // Calls GetValue on |variable| and expects its result to be null.
- template <typename T>
- static void ExpectVariableNotSet(Variable<T>* variable) {
- ASSERT_NE(nullptr, variable);
- std::unique_ptr<const T> value(
- variable->GetValue(DefaultTimeout(), nullptr));
- EXPECT_EQ(nullptr, value.get()) << "Variable: " << variable->GetName();
- }
-
- private:
- static const unsigned kDefaultTimeoutInSeconds;
-};
-
-// PrintTo() functions are used by gtest to print these values. They need to be
-// defined on the same namespace where the type was defined.
-void PrintTo(const EvalStatus& status, ::std::ostream* os);
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_UMTEST_UTILS_H_
diff --git a/update_manager/update_manager-inl.h b/update_manager/update_manager-inl.h
deleted file mode 100644
index 045ecffa..00000000
--- a/update_manager/update_manager-inl.h
+++ /dev/null
@@ -1,166 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
-
-#include <memory>
-#include <string>
-
-#include <base/bind.h>
-#include <base/location.h>
-#include <brillo/message_loops/message_loop.h>
-
-#include "update_engine/update_manager/evaluation_context.h"
-
-namespace chromeos_update_manager {
-
-template <typename R, typename... Args>
-EvalStatus UpdateManager::EvaluatePolicy(
- EvaluationContext* ec,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, Args...) const,
- R* result,
- Args... args) {
- // If expiration timeout fired, dump the context and reset expiration.
- // IMPORTANT: We must still proceed with evaluation of the policy in this
- // case, so that the evaluation time (and corresponding reevaluation timeouts)
- // are readjusted.
- if (ec->is_expired()) {
- LOG(WARNING) << "Request timed out, evaluation context: "
- << ec->DumpContext();
- ec->ResetExpiration();
- }
-
- // Reset the evaluation context.
- ec->ResetEvaluation();
-
- const std::string policy_name = policy_->PolicyRequestName(policy_method);
-
- // First try calling the actual policy.
- std::string error;
- EvalStatus status = (policy_.get()->*policy_method)(
- ec, state_.get(), &error, result, args...);
- // If evaluating the main policy failed, defer to the default policy.
- if (status == EvalStatus::kFailed) {
- LOG(WARNING) << "Evaluating policy failed: " << error
- << "\nEvaluation context: " << ec->DumpContext();
- error.clear();
- status = (default_policy_.*policy_method)(
- ec, state_.get(), &error, result, args...);
- if (status == EvalStatus::kFailed) {
- LOG(WARNING) << "Evaluating default policy failed: " << error;
- } else if (status == EvalStatus::kAskMeAgainLater) {
- LOG(ERROR)
- << "Default policy would block; this is a bug, forcing failure.";
- status = EvalStatus::kFailed;
- }
- }
-
- return status;
-}
-
-template <typename R, typename... Args>
-void UpdateManager::OnPolicyReadyToEvaluate(
- std::shared_ptr<EvaluationContext> ec,
- base::Callback<void(EvalStatus status, const R& result)> callback,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, Args...) const,
- Args... args) {
- // Evaluate the policy.
- R result;
- EvalStatus status = EvaluatePolicy(ec.get(), policy_method, &result, args...);
-
- if (status != EvalStatus::kAskMeAgainLater) {
- // AsyncPolicyRequest finished.
- callback.Run(status, result);
- return;
- }
-
- // Re-schedule the policy request based on used variables.
- base::Closure reeval_callback =
- base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, Args...>,
- base::Unretained(this),
- ec,
- callback,
- policy_method,
- args...);
- if (ec->RunOnValueChangeOrTimeout(reeval_callback))
- return; // Reevaluation scheduled successfully.
-
- // Scheduling a reevaluation can fail because policy method didn't use any
- // non-const variable nor there's any time-based event that will change the
- // status of evaluation. Alternatively, this may indicate an error in the use
- // of the scheduling interface.
- LOG(ERROR) << "Failed to schedule a reevaluation of policy "
- << policy_->PolicyRequestName(policy_method) << "; this is a bug.";
- callback.Run(status, result);
-}
-
-template <typename R, typename... ActualArgs, typename... ExpectedArgs>
-EvalStatus UpdateManager::PolicyRequest(
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
- R* result,
- ActualArgs... args) {
- auto ec = std::make_shared<EvaluationContext>(evaluation_timeout_);
- // A PolicyRequest always consists on a single evaluation on a new
- // EvaluationContext.
- // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
- // explicitly instantiate EvaluatePolicy with the latter in lieu of the
- // former.
- EvalStatus ret = EvaluatePolicy<R, ExpectedArgs...>(
- ec.get(), policy_method, result, args...);
- // Sync policy requests must not block, if they do then this is an error.
- DCHECK(EvalStatus::kAskMeAgainLater != ret);
- LOG_IF(WARNING, EvalStatus::kAskMeAgainLater == ret)
- << "Sync request used with an async policy; this is a bug";
- return ret;
-}
-
-template <typename R, typename... ActualArgs, typename... ExpectedArgs>
-void UpdateManager::AsyncPolicyRequest(
- base::Callback<void(EvalStatus, const R& result)> callback,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
- ActualArgs... args) {
- auto ec = std::make_shared<EvaluationContext>(
- evaluation_timeout_,
- expiration_timeout_,
- std::unique_ptr<base::Callback<void(EvaluationContext*)>>(
- new base::Callback<void(EvaluationContext*)>(
- base::Bind(&UpdateManager::UnregisterEvalContext,
- weak_ptr_factory_.GetWeakPtr()))));
- if (!ec_repo_.insert(ec).second) {
- LOG(ERROR) << "Failed to register evaluation context; this is a bug.";
- }
-
- // IMPORTANT: To ensure that ActualArgs can be converted to ExpectedArgs, we
- // explicitly instantiate UpdateManager::OnPolicyReadyToEvaluate with the
- // latter in lieu of the former.
- base::Closure eval_callback =
- base::Bind(&UpdateManager::OnPolicyReadyToEvaluate<R, ExpectedArgs...>,
- base::Unretained(this),
- ec,
- callback,
- policy_method,
- args...);
- brillo::MessageLoop::current()->PostTask(FROM_HERE, eval_callback);
-}
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_INL_H_
diff --git a/update_manager/update_manager.cc b/update_manager/update_manager.cc
deleted file mode 100644
index dbb6b336..00000000
--- a/update_manager/update_manager.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/update_manager.h"
-#include "update_engine/update_manager/state.h"
-
-namespace chromeos_update_manager {
-
-UpdateManager::UpdateManager(base::TimeDelta evaluation_timeout,
- base::TimeDelta expiration_timeout,
- State* state)
- : policy_(GetSystemPolicy()),
- state_(state),
- evaluation_timeout_(evaluation_timeout),
- expiration_timeout_(expiration_timeout),
- weak_ptr_factory_(this) {}
-
-UpdateManager::~UpdateManager() {
- // Remove pending main loop events associated with any of the outstanding
- // evaluation contexts. This will prevent dangling pending events, causing
- // these contexts to be destructed once the repo itself is destructed.
- for (auto& ec : ec_repo_)
- ec->RemoveObserversAndTimeout();
-}
-
-void UpdateManager::AsyncPolicyRequestUpdateCheckAllowed(
- base::Callback<void(EvalStatus, const UpdateCheckParams& result)> callback,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, UpdateCheckParams*) const) {
- AsyncPolicyRequest(callback, policy_method);
-}
-
-void UpdateManager::UnregisterEvalContext(EvaluationContext* ec) {
- // Since |ec_repo_|'s compare function is based on the value of the raw
- // pointer |ec|, we can just create a |shared_ptr| here and pass it along to
- // be erased.
- if (!ec_repo_.erase(
- std::shared_ptr<EvaluationContext>(ec, [](EvaluationContext*) {}))) {
- LOG(ERROR) << "Unregistering an unknown evaluation context, this is a bug.";
- }
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/update_manager.conf.example b/update_manager/update_manager.conf.example
deleted file mode 100644
index 2d77974e..00000000
--- a/update_manager/update_manager.conf.example
+++ /dev/null
@@ -1,18 +0,0 @@
-# Configuration file for the update-manager component of update_engine.
-#
-# Normally this file is loaded from /etc/update_manager.conf. If
-# running update_engine in developer mode (and only if running in
-# developer mode), we attempt to load
-#
-# /mnt/stateful_partition/etc/update_manager.conf
-#
-# and use it if it exists. If it doesn't exist, we fall back to
-# /etc/update_manager.conf.
-#
-# Note: changes to this file are not automatically applied. Use the
-# command "restart update-engine" from a root shell to make your
-# changes take effect.
-
-# Set to true if the device supports the concept of OOBE
-# (Out-Of-the-Box-Experience), false if it doesn't.
-is_oobe_enabled=true
diff --git a/update_manager/update_manager.h b/update_manager/update_manager.h
deleted file mode 100644
index e266b574..00000000
--- a/update_manager/update_manager.h
+++ /dev/null
@@ -1,187 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_UPDATE_MANAGER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_H_
-
-#include <memory>
-#include <set>
-#include <string>
-
-#include <base/callback.h>
-#include <base/time/time.h>
-
-#include "update_engine/common/system_state.h"
-#include "update_engine/update_manager/default_policy.h"
-#include "update_engine/update_manager/evaluation_context.h"
-#include "update_engine/update_manager/policy.h"
-#include "update_engine/update_manager/state.h"
-
-namespace chromeos_update_manager {
-
-// Please do not move this class into a new file for simplicity.
-// This pure virtual class is purely created for purpose of testing. The reason
-// was that |UpdateManager|'s member functions are templatized, which does not
-// play nicely when testing (mocking + faking). Whenever a specialized member of
-// |UpdateManager| must be tested, please add a specialized template member
-// function within this class for testing.
-class SpecializedPolicyRequestInterface {
- public:
- virtual ~SpecializedPolicyRequestInterface() = default;
-
- virtual void AsyncPolicyRequestUpdateCheckAllowed(
- base::Callback<void(EvalStatus, const UpdateCheckParams& result)>
- callback,
- EvalStatus (Policy::*policy_method)(EvaluationContext*,
- State*,
- std::string*,
- UpdateCheckParams*) const) = 0;
-};
-
-// The main Update Manager singleton class.
-class UpdateManager : public SpecializedPolicyRequestInterface {
- public:
- // Creates the UpdateManager instance, assuming ownership on the provided
- // |state|.
- UpdateManager(base::TimeDelta evaluation_timeout,
- base::TimeDelta expiration_timeout,
- State* state);
-
- virtual ~UpdateManager();
-
- // PolicyRequest() evaluates the given policy with the provided arguments and
- // returns the result. The |policy_method| is the pointer-to-method of the
- // Policy class for the policy request to call. The UpdateManager will call
- // this method on the right policy. The pointer |result| must not be null
- // and the remaining |args| depend on the arguments required by the passed
- // |policy_method|.
- //
- // When the policy request succeeds, the |result| is set and the method
- // returns EvalStatus::kSucceeded, otherwise, the |result| may not be set. A
- // policy called with this method should not block (i.e. return
- // EvalStatus::kAskMeAgainLater), which is considered a programming error. On
- // failure, EvalStatus::kFailed is returned.
- //
- // An example call to this method is:
- // um.PolicyRequest(&Policy::SomePolicyMethod, &bool_result, arg1, arg2);
- template <typename R, typename... ActualArgs, typename... ExpectedArgs>
- EvalStatus PolicyRequest(
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
- R* result,
- ActualArgs...);
-
- // Evaluates the given |policy_method| policy with the provided |args|
- // arguments and calls the |callback| callback with the result when done.
- //
- // If the policy implementation should block, returning a
- // EvalStatus::kAskMeAgainLater status the Update Manager will re-evaluate the
- // policy until another status is returned. If the policy implementation based
- // its return value solely on const variables, the callback will be called
- // with the EvalStatus::kAskMeAgainLater status (which indicates an error).
- template <typename R, typename... ActualArgs, typename... ExpectedArgs>
- void AsyncPolicyRequest(
- base::Callback<void(EvalStatus, const R& result)> callback,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, ExpectedArgs...) const,
- ActualArgs... args);
-
- void AsyncPolicyRequestUpdateCheckAllowed(
- base::Callback<void(EvalStatus, const UpdateCheckParams& result)>
- callback,
- EvalStatus (Policy::*policy_method)(EvaluationContext*,
- State*,
- std::string*,
- UpdateCheckParams*) const) override;
-
- protected:
- // The UpdateManager receives ownership of the passed Policy instance.
- void set_policy(const Policy* policy) { policy_.reset(policy); }
-
- // State getter used for testing.
- State* state() { return state_.get(); }
-
- private:
- FRIEND_TEST(UmUpdateManagerTest, PolicyRequestCallsPolicy);
- FRIEND_TEST(UmUpdateManagerTest, PolicyRequestCallsDefaultOnError);
- FRIEND_TEST(UmUpdateManagerTest, PolicyRequestDoesntBlockDeathTest);
- FRIEND_TEST(UmUpdateManagerTest, AsyncPolicyRequestDelaysEvaluation);
- FRIEND_TEST(UmUpdateManagerTest, AsyncPolicyRequestTimeoutDoesNotFire);
- FRIEND_TEST(UmUpdateManagerTest, AsyncPolicyRequestTimesOut);
-
- // EvaluatePolicy() evaluates the passed |policy_method| method on the current
- // policy with the given |args| arguments. If the method fails, the default
- // policy is used instead.
- template <typename R, typename... Args>
- EvalStatus EvaluatePolicy(
- EvaluationContext* ec,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, Args...) const,
- R* result,
- Args... args);
-
- // OnPolicyReadyToEvaluate() is called by the main loop when the evaluation
- // of the given |policy_method| should be executed. If the evaluation finishes
- // the |callback| callback is called passing the |result| and the |status|
- // returned by the policy. If the evaluation returns an
- // EvalStatus::kAskMeAgainLater state, the |callback| will NOT be called and
- // the evaluation will be re-scheduled to be called later.
- template <typename R, typename... Args>
- void OnPolicyReadyToEvaluate(
- std::shared_ptr<EvaluationContext> ec,
- base::Callback<void(EvalStatus status, const R& result)> callback,
- EvalStatus (Policy::*policy_method)(
- EvaluationContext*, State*, std::string*, R*, Args...) const,
- Args... args);
-
- // Unregisters (removes from repo) a previously created EvaluationContext.
- void UnregisterEvalContext(EvaluationContext* ec);
-
- // The policy used by the UpdateManager. Note that since it is a const Policy,
- // policy implementations are not allowed to persist state on this class.
- std::unique_ptr<const Policy> policy_;
-
- // A safe default value to the current policy. This policy is used whenever
- // a policy implementation fails with EvalStatus::kFailed.
- const DefaultPolicy default_policy_;
-
- // State Providers.
- std::unique_ptr<State> state_;
-
- // Timeout for a policy evaluation.
- const base::TimeDelta evaluation_timeout_;
-
- // Timeout for expiration of the evaluation context, used for async requests.
- const base::TimeDelta expiration_timeout_;
-
- // Repository of previously created EvaluationContext objects. These are being
- // unregistered (and the reference released) when the context is being
- // destructed; alternatively, when the UpdateManager instance is destroyed, it
- // will remove all pending events associated with all outstanding contexts
- // (which should, in turn, trigger their destruction).
- std::set<std::shared_ptr<EvaluationContext>> ec_repo_;
-
- base::WeakPtrFactory<UpdateManager> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(UpdateManager);
-};
-
-} // namespace chromeos_update_manager
-
-// Include the implementation of the template methods.
-#include "update_engine/update_manager/update_manager-inl.h"
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_MANAGER_H_
diff --git a/update_manager/update_manager_unittest.cc b/update_manager/update_manager_unittest.cc
deleted file mode 100644
index a02d7ef5..00000000
--- a/update_manager/update_manager_unittest.cc
+++ /dev/null
@@ -1,333 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/update_manager.h"
-
-#include <unistd.h>
-
-#include <algorithm>
-#include <memory>
-#include <string>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include <base/bind.h>
-#include <base/test/simple_test_clock.h>
-#include <base/time/time.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/default_policy.h"
-#include "update_engine/update_manager/fake_state.h"
-#include "update_engine/update_manager/mock_policy.h"
-#include "update_engine/update_manager/umtest_utils.h"
-
-using base::Bind;
-using base::Callback;
-using base::Time;
-using base::TimeDelta;
-using brillo::MessageLoop;
-using brillo::MessageLoopRunMaxIterations;
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::FakeClock;
-using chromeos_update_engine::FakeSystemState;
-using std::pair;
-using std::string;
-using std::tuple;
-using std::unique_ptr;
-using std::vector;
-
-namespace {
-
-// Generates a fixed timestamp for use in faking the current time.
-Time FixedTime() {
- Time::Exploded now_exp;
- now_exp.year = 2014;
- now_exp.month = 3;
- now_exp.day_of_week = 2;
- now_exp.day_of_month = 18;
- now_exp.hour = 8;
- now_exp.minute = 5;
- now_exp.second = 33;
- now_exp.millisecond = 675;
- Time time;
- ignore_result(Time::FromLocalExploded(now_exp, &time));
- return time;
-}
-
-} // namespace
-
-namespace chromeos_update_manager {
-
-class UmUpdateManagerTest : public ::testing::Test {
- protected:
- void SetUp() override {
- loop_.SetAsCurrent();
- FakeSystemState::CreateInstance();
- fake_state_ = new FakeState();
- umut_.reset(new UpdateManager(
- TimeDelta::FromSeconds(5), TimeDelta::FromSeconds(1), fake_state_));
- }
-
- void TearDown() override { EXPECT_FALSE(loop_.PendingTasks()); }
-
- base::SimpleTestClock test_clock_;
- brillo::FakeMessageLoop loop_{&test_clock_};
- FakeState* fake_state_; // Owned by the umut_.
- unique_ptr<UpdateManager> umut_;
-};
-
-// The FailingPolicy implements a single method and make it always fail. This
-// class extends the DefaultPolicy class to allow extensions of the Policy
-// class without extending nor changing this test.
-class FailingPolicy : public DefaultPolicy {
- public:
- explicit FailingPolicy(int* num_called_p) : num_called_p_(num_called_p) {}
- FailingPolicy() : FailingPolicy(nullptr) {}
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- string* error,
- UpdateCheckParams* result) const override {
- if (num_called_p_)
- (*num_called_p_)++;
- *error = "FailingPolicy failed.";
- return EvalStatus::kFailed;
- }
-
- protected:
- string PolicyName() const override { return "FailingPolicy"; }
-
- private:
- int* num_called_p_;
-};
-
-// The LazyPolicy always returns EvalStatus::kAskMeAgainLater.
-class LazyPolicy : public DefaultPolicy {
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- string* error,
- UpdateCheckParams* result) const override {
- return EvalStatus::kAskMeAgainLater;
- }
-
- protected:
- string PolicyName() const override { return "LazyPolicy"; }
-};
-
-// A policy that sleeps for a predetermined amount of time, then checks for a
-// wallclock-based time threshold (if given) and returns
-// EvalStatus::kAskMeAgainLater if not passed; otherwise, returns
-// EvalStatus::kSucceeded. Increments a counter every time it is being queried,
-// if a pointer to it is provided.
-class DelayPolicy : public DefaultPolicy {
- public:
- DelayPolicy(int sleep_secs, Time time_threshold, int* num_called_p)
- : sleep_secs_(sleep_secs),
- time_threshold_(time_threshold),
- num_called_p_(num_called_p) {}
- EvalStatus UpdateCheckAllowed(EvaluationContext* ec,
- State* state,
- string* error,
- UpdateCheckParams* result) const override {
- if (num_called_p_)
- (*num_called_p_)++;
-
- // Sleep for a predetermined amount of time.
- if (sleep_secs_ > 0)
- sleep(sleep_secs_);
-
- // Check for a time threshold. This can be used to ensure that the policy
- // has some non-constant dependency.
- if (time_threshold_ < Time::Max() &&
- ec->IsWallclockTimeGreaterThan(time_threshold_))
- return EvalStatus::kSucceeded;
-
- return EvalStatus::kAskMeAgainLater;
- }
-
- protected:
- string PolicyName() const override { return "DelayPolicy"; }
-
- private:
- int sleep_secs_;
- Time time_threshold_;
- int* num_called_p_;
-};
-
-// AccumulateCallsCallback() adds to the passed |acc| accumulator vector pairs
-// of EvalStatus and T instances. This allows to create a callback that keeps
-// track of when it is called and the arguments passed to it, to be used with
-// the UpdateManager::AsyncPolicyRequest().
-template <typename T>
-static void AccumulateCallsCallback(vector<pair<EvalStatus, T>>* acc,
- EvalStatus status,
- const T& result) {
- acc->push_back(std::make_pair(status, result));
-}
-
-// Tests that policy requests are completed successfully. It is important that
-// this tests cover all policy requests as defined in Policy.
-TEST_F(UmUpdateManagerTest, PolicyRequestCallUpdateCheckAllowed) {
- UpdateCheckParams result;
- EXPECT_EQ(EvalStatus::kSucceeded,
- umut_->PolicyRequest(&Policy::UpdateCheckAllowed, &result));
-}
-
-TEST_F(UmUpdateManagerTest, PolicyRequestCallUpdateCanStart) {
- UpdateState update_state = UpdateState();
- update_state.interactive = true;
- update_state.is_delta_payload = false;
- update_state.first_seen = FixedTime();
- update_state.num_checks = 1;
- update_state.num_failures = 0;
- update_state.failures_last_updated = Time();
- update_state.download_urls = vector<string>{"http://fake/url/"};
- update_state.download_errors_max = 10;
- update_state.p2p_downloading_disabled = false;
- update_state.p2p_sharing_disabled = false;
- update_state.p2p_num_attempts = 0;
- update_state.p2p_first_attempted = Time();
- update_state.last_download_url_idx = -1;
- update_state.last_download_url_num_errors = 0;
- update_state.download_errors = vector<tuple<int, ErrorCode, Time>>();
- update_state.backoff_expiry = Time();
- update_state.is_backoff_disabled = false;
- update_state.scatter_wait_period = TimeDelta::FromSeconds(15);
- update_state.scatter_check_threshold = 4;
- update_state.scatter_wait_period_max = TimeDelta::FromSeconds(60);
- update_state.scatter_check_threshold_min = 2;
- update_state.scatter_check_threshold_max = 8;
-
- UpdateDownloadParams result;
- EXPECT_EQ(
- EvalStatus::kSucceeded,
- umut_->PolicyRequest(&Policy::UpdateCanStart, &result, update_state));
-}
-
-TEST_F(UmUpdateManagerTest, PolicyRequestCallsDefaultOnError) {
- umut_->set_policy(new FailingPolicy());
-
- // Tests that the DefaultPolicy instance is called when the method fails,
- // which will set this as true.
- UpdateCheckParams result;
- result.updates_enabled = false;
- EvalStatus status =
- umut_->PolicyRequest(&Policy::UpdateCheckAllowed, &result);
- EXPECT_EQ(EvalStatus::kSucceeded, status);
- EXPECT_TRUE(result.updates_enabled);
-}
-
-// This test only applies to debug builds where DCHECK is enabled.
-#if DCHECK_IS_ON
-TEST_F(UmUpdateManagerTest, PolicyRequestDoesntBlockDeathTest) {
- // The update manager should die (DCHECK) if a policy called synchronously
- // returns a kAskMeAgainLater value.
- UpdateCheckParams result;
- umut_->set_policy(new LazyPolicy());
- EXPECT_DEATH(umut_->PolicyRequest(&Policy::UpdateCheckAllowed, &result), "");
-}
-#endif // DCHECK_IS_ON
-
-TEST_F(UmUpdateManagerTest, AsyncPolicyRequestDelaysEvaluation) {
- // To avoid differences in code execution order between an AsyncPolicyRequest
- // call on a policy that returns AskMeAgainLater the first time and one that
- // succeeds the first time, we ensure that the passed callback is called from
- // the main loop in both cases even when we could evaluate it right now.
- umut_->set_policy(new FailingPolicy());
-
- vector<pair<EvalStatus, UpdateCheckParams>> calls;
- Callback<void(EvalStatus, const UpdateCheckParams&)> callback =
- Bind(AccumulateCallsCallback<UpdateCheckParams>, &calls);
-
- umut_->AsyncPolicyRequest(callback, &Policy::UpdateCheckAllowed);
- // The callback should wait until we run the main loop for it to be executed.
- EXPECT_EQ(0U, calls.size());
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_EQ(1U, calls.size());
-}
-
-TEST_F(UmUpdateManagerTest, AsyncPolicyRequestTimeoutDoesNotFire) {
- // Set up an async policy call to return immediately, then wait a little and
- // ensure that the timeout event does not fire.
- int num_called = 0;
- umut_->set_policy(new FailingPolicy(&num_called));
-
- vector<pair<EvalStatus, UpdateCheckParams>> calls;
- Callback<void(EvalStatus, const UpdateCheckParams&)> callback =
- Bind(AccumulateCallsCallback<UpdateCheckParams>, &calls);
-
- umut_->AsyncPolicyRequest(callback, &Policy::UpdateCheckAllowed);
- // Run the main loop, ensure that policy was attempted once before deferring
- // to the default.
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_EQ(1, num_called);
- ASSERT_EQ(1U, calls.size());
- EXPECT_EQ(EvalStatus::kSucceeded, calls[0].first);
- // Wait for the timeout to expire, run the main loop again, ensure that
- // nothing happened.
- test_clock_.Advance(TimeDelta::FromSeconds(2));
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- EXPECT_EQ(1, num_called);
- EXPECT_EQ(1U, calls.size());
-}
-
-TEST_F(UmUpdateManagerTest, AsyncPolicyRequestTimesOut) {
- auto* fake_clock = FakeSystemState::Get()->fake_clock();
- // Set up an async policy call to exceed its expiration timeout, make sure
- // that the default policy was not used (no callback) and that evaluation is
- // reattempted.
- int num_called = 0;
- umut_->set_policy(new DelayPolicy(
- 0,
- fake_clock->GetWallclockTime() + TimeDelta::FromSeconds(3),
- &num_called));
-
- vector<pair<EvalStatus, UpdateCheckParams>> calls;
- Callback<void(EvalStatus, const UpdateCheckParams&)> callback =
- Bind(AccumulateCallsCallback<UpdateCheckParams>, &calls);
-
- umut_->AsyncPolicyRequest(callback, &Policy::UpdateCheckAllowed);
- // Run the main loop, ensure that policy was attempted once but the callback
- // was not invoked.
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
- EXPECT_EQ(1, num_called);
- EXPECT_EQ(0U, calls.size());
- // Wait for the expiration timeout to expire, run the main loop again,
- // ensure that reevaluation occurred but callback was not invoked (i.e.
- // default policy was not consulted).
- test_clock_.Advance(TimeDelta::FromSeconds(2));
- fake_clock->SetWallclockTime(fake_clock->GetWallclockTime() +
- TimeDelta::FromSeconds(2));
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- EXPECT_EQ(2, num_called);
- EXPECT_EQ(0U, calls.size());
- // Wait for reevaluation due to delay to happen, ensure that it occurs and
- // that the callback is invoked.
- test_clock_.Advance(TimeDelta::FromSeconds(2));
- fake_clock->SetWallclockTime(fake_clock->GetWallclockTime() +
- TimeDelta::FromSeconds(2));
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- EXPECT_EQ(3, num_called);
- ASSERT_EQ(1U, calls.size());
- EXPECT_EQ(EvalStatus::kSucceeded, calls[0].first);
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/update_time_restrictions_monitor.cc b/update_manager/update_time_restrictions_monitor.cc
deleted file mode 100644
index 00e6ec3e..00000000
--- a/update_manager/update_time_restrictions_monitor.cc
+++ /dev/null
@@ -1,132 +0,0 @@
-//
-// 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/update_manager/update_time_restrictions_monitor.h"
-
-#include <base/bind.h>
-#include <base/time/time.h>
-
-#include "update_engine/common/system_state.h"
-
-using base::TimeDelta;
-using brillo::MessageLoop;
-using chromeos_update_engine::SystemState;
-
-namespace chromeos_update_manager {
-
-namespace {
-
-const WeeklyTimeInterval* FindNextNearestInterval(
- const WeeklyTimeIntervalVector& intervals, const WeeklyTime& now) {
- const WeeklyTimeInterval* result_interval = nullptr;
- // As we are dealing with weekly time here, the maximum duration can be one
- // week.
- TimeDelta duration_till_next_interval = TimeDelta::FromDays(7);
- for (const auto& interval : intervals) {
- if (interval.InRange(now)) {
- return &interval;
- }
- const TimeDelta current_duration = now.GetDurationTo(interval.start());
- if (current_duration < duration_till_next_interval) {
- result_interval = &interval;
- duration_till_next_interval = current_duration;
- }
- }
- return result_interval;
-}
-
-WeeklyTime Now() {
- return WeeklyTime::FromTime(SystemState::Get()->clock()->GetWallclockTime());
-}
-
-} // namespace
-
-UpdateTimeRestrictionsMonitor::UpdateTimeRestrictionsMonitor(
- DevicePolicyProvider* device_policy_provider, Delegate* delegate)
- : evaluation_context_(/* evaluation_timeout = */ TimeDelta::Max(),
- /* expiration_timeout = */ TimeDelta::Max(),
- /* unregister_cb = */ {}),
- device_policy_provider_(device_policy_provider),
- delegate_(delegate),
- weak_ptr_factory_(this) {
- if (device_policy_provider_ != nullptr && delegate_ != nullptr)
- StartMonitoring();
-}
-
-UpdateTimeRestrictionsMonitor::~UpdateTimeRestrictionsMonitor() {
- StopMonitoring();
-}
-
-void UpdateTimeRestrictionsMonitor::StartMonitoring() {
- DCHECK(device_policy_provider_);
- const WeeklyTimeIntervalVector* new_intervals = evaluation_context_.GetValue(
- device_policy_provider_->var_disallowed_time_intervals());
- if (new_intervals && !new_intervals->empty())
- WaitForRestrictedIntervalStarts(*new_intervals);
-
- const bool is_registered = evaluation_context_.RunOnValueChangeOrTimeout(
- base::Bind(&UpdateTimeRestrictionsMonitor::OnIntervalsChanged,
- base::Unretained(this)));
- DCHECK(is_registered);
-}
-
-void UpdateTimeRestrictionsMonitor::WaitForRestrictedIntervalStarts(
- const WeeklyTimeIntervalVector& restricted_time_intervals) {
- DCHECK(!restricted_time_intervals.empty());
-
- const WeeklyTimeInterval* current_interval =
- FindNextNearestInterval(restricted_time_intervals, Now());
- if (current_interval == nullptr) {
- LOG(WARNING) << "Could not find next nearest restricted interval.";
- return;
- }
-
- // If |current_interval| happens right now, set delay to zero.
- const TimeDelta duration_till_start =
- current_interval->InRange(Now())
- ? TimeDelta::FromMicroseconds(0)
- : Now().GetDurationTo(current_interval->start());
- LOG(INFO) << "Found restricted interval starting at "
- << (SystemState::Get()->clock()->GetWallclockTime() +
- duration_till_start);
-
- timeout_event_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&UpdateTimeRestrictionsMonitor::HandleRestrictedIntervalStarts,
- weak_ptr_factory_.GetWeakPtr()),
- duration_till_start);
-}
-
-void UpdateTimeRestrictionsMonitor::HandleRestrictedIntervalStarts() {
- timeout_event_ = MessageLoop::kTaskIdNull;
- if (delegate_)
- delegate_->OnRestrictedIntervalStarts();
-}
-
-void UpdateTimeRestrictionsMonitor::StopMonitoring() {
- MessageLoop::current()->CancelTask(timeout_event_);
- timeout_event_ = MessageLoop::kTaskIdNull;
-}
-
-void UpdateTimeRestrictionsMonitor::OnIntervalsChanged() {
- DCHECK(!evaluation_context_.is_expired());
-
- StopMonitoring();
- evaluation_context_.ResetEvaluation();
- StartMonitoring();
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/update_time_restrictions_monitor.h b/update_manager/update_time_restrictions_monitor.h
deleted file mode 100644
index 034ac872..00000000
--- a/update_manager/update_time_restrictions_monitor.h
+++ /dev/null
@@ -1,105 +0,0 @@
-//
-// 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_UPDATE_MANAGER_UPDATE_TIME_RESTRICTIONS_MONITOR_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_TIME_RESTRICTIONS_MONITOR_H_
-
-#include <memory>
-
-#include <base/memory/weak_ptr.h>
-#include <brillo/message_loops/message_loop.h>
-
-#include "update_engine/update_manager/device_policy_provider.h"
-#include "update_engine/update_manager/evaluation_context.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-namespace chromeos_update_manager {
-
-// Represents a monitor tracking start of restricted time intervals during which
-// update download is not allowed. It reads |var_disallowed_time_intervals|,
-// chooses the next interval according to current time, awaits its start and
-// notifies the delegate. If the chosen interval is already happening, the
-// monitor notifies immediately. The monitor will never notify the delegate
-// while the current list of restricted intervals is empty.
-//
-// The monitor detects changes in the restricted intervals and handles the
-// change with following cases:
-// 1. No restricted time intervals or none of the intervals is in progress -> no
-// new restricted intervals or none of the new intervals matches the current
-// time.
-// The monitor starts tracking the next interval from the new ones, if any.
-// 2. No restricted time intervals or none of the intervals is in progress ->
-// there is a new interval matching current time.
-// The monitor shall pick this new interval and notify the delegate
-// immediately about the start of the restricted interval.
-class UpdateTimeRestrictionsMonitor {
- public:
- // Interface to handle start of a restricted time interval.
- class Delegate {
- public:
- virtual ~Delegate() = default;
-
- virtual void OnRestrictedIntervalStarts() = 0;
- };
-
- // Creates an instance and starts monitoring the next nearest restricted time
- // interval if present. If no intervals are available yet the monitor will be
- // idle until intervals list changes.
- UpdateTimeRestrictionsMonitor(DevicePolicyProvider* device_policy_provider,
- Delegate* delegate);
-
- UpdateTimeRestrictionsMonitor(const UpdateTimeRestrictionsMonitor&) = delete;
- UpdateTimeRestrictionsMonitor& operator=(
- const UpdateTimeRestrictionsMonitor&) = delete;
-
- ~UpdateTimeRestrictionsMonitor();
-
- bool IsMonitoringInterval() {
- return timeout_event_ != brillo::MessageLoop::kTaskIdNull;
- }
-
- private:
- // Starts monitoring the start of nearest restricted time interval if present
- // and any change in restricted time intervals from policy.
- void StartMonitoring();
- void WaitForRestrictedIntervalStarts(
- const WeeklyTimeIntervalVector& restricted_time_intervals);
-
- // Called when current time lies within a restricted interval.
- void HandleRestrictedIntervalStarts();
-
- // Stop monotoring any restricted intervals.
- void StopMonitoring();
-
- // Called upon change of restricted intervals.
- void OnIntervalsChanged();
-
- // To access restricted time intervals from |device_policy_provider_|.
- EvaluationContext evaluation_context_;
-
- DevicePolicyProvider* const device_policy_provider_;
- Delegate* const delegate_;
-
- // The TaskId returned by the message loop identifying the timeout callback.
- // Used for cancelling the timeout callback.
- brillo::MessageLoop::TaskId timeout_event_{brillo::MessageLoop::kTaskIdNull};
-
- base::WeakPtrFactory<UpdateTimeRestrictionsMonitor> weak_ptr_factory_;
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_TIME_RESTRICTIONS_MONITOR_H_
diff --git a/update_manager/update_time_restrictions_monitor_unittest.cc b/update_manager/update_time_restrictions_monitor_unittest.cc
deleted file mode 100644
index 2e474e25..00000000
--- a/update_manager/update_time_restrictions_monitor_unittest.cc
+++ /dev/null
@@ -1,279 +0,0 @@
-//
-// 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 <memory>
-
-#include <base/optional.h>
-#include <base/time/time.h>
-#include <base/test/simple_test_clock.h>
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/cros/fake_system_state.h"
-#include "update_engine/update_manager/fake_state.h"
-#include "update_engine/update_manager/update_time_restrictions_monitor.h"
-
-using brillo::FakeMessageLoop;
-using brillo::MessageLoop;
-using brillo::MessageLoopRunMaxIterations;
-using chromeos_update_engine::FakeSystemState;
-
-namespace chromeos_update_manager {
-
-namespace {
-
-constexpr base::TimeDelta kDurationOffset = base::TimeDelta::FromMinutes(1);
-constexpr base::TimeDelta kHourDuration = base::TimeDelta::FromHours(1);
-constexpr base::TimeDelta kMinuteDuration = base::TimeDelta::FromMinutes(1);
-// Initial time: Monday, May 4th 2020 8:13 AM before interval.
-constexpr base::Time::Exploded kInitialTimeBeforeInterval{
- 2020, 5, 0, 4, 10, 13, 0, 0};
-// Initial time: Monday, May 4th 2020 10:20 AM within interval.
-constexpr base::Time::Exploded kInitialTimeWithinInterval{
- 2020, 5, 0, 4, 10, 20, 0, 0};
-const int current_restricted_interval_index = 0;
-
-const WeeklyTimeIntervalVector kTestOneDisallowedTimeIntervals{
- // Monday 8:15 AM to Monday 9:30 PM.
- WeeklyTimeInterval(WeeklyTime(1, kHourDuration * 8 + kMinuteDuration * 15),
- WeeklyTime(1, kHourDuration * 9 + kMinuteDuration * 30)),
-};
-
-const WeeklyTimeIntervalVector kTestTwoDisallowedTimeIntervals{
- // Monday 10:15 AM to Monday 3:30 PM.
- WeeklyTimeInterval(
- WeeklyTime(1, kHourDuration * 10 + kMinuteDuration * 15),
- WeeklyTime(1, kHourDuration * 15 + kMinuteDuration * 30)),
- // Wednesday 8:30 PM to Thursday 8:40 AM.
- WeeklyTimeInterval(WeeklyTime(3, kHourDuration * 20 + kMinuteDuration * 30),
- WeeklyTime(4, kHourDuration * 8 + kMinuteDuration * 40)),
-};
-
-} // namespace
-
-class MockUpdateTimeRestrictionsMonitorDelegate
- : public UpdateTimeRestrictionsMonitor::Delegate {
- public:
- virtual ~MockUpdateTimeRestrictionsMonitorDelegate() = default;
-
- MOCK_METHOD0(OnRestrictedIntervalStarts, void());
-};
-
-class UmUpdateTimeRestrictionsMonitorTest : public ::testing::Test {
- protected:
- UmUpdateTimeRestrictionsMonitorTest() {
- fake_loop_.SetAsCurrent();
- FakeSystemState::CreateInstance();
- }
-
- void TearDown() override { EXPECT_FALSE(fake_loop_.PendingTasks()); }
-
- bool SetNow(const base::Time::Exploded& exploded_now) {
- base::Time now;
- if (!base::Time::FromLocalExploded(exploded_now, &now))
- return false;
-
- test_clock_.SetNow(now);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(now);
- return true;
- }
-
- void AdvanceAfterTimestamp(const WeeklyTime& timestamp) {
- const WeeklyTime now = WeeklyTime::FromTime(test_clock_.Now());
- const base::TimeDelta duration =
- now.GetDurationTo(timestamp) + kDurationOffset;
- test_clock_.Advance(duration);
- FakeSystemState::Get()->fake_clock()->SetWallclockTime(test_clock_.Now());
- }
-
- void VerifyExpectationsOnDelegate() {
- testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
- }
-
- void UpdateRestrictedIntervals(const WeeklyTimeIntervalVector& policy_value) {
- auto* policy_variable =
- fake_state_.device_policy_provider()->var_disallowed_time_intervals();
- policy_variable->reset(new WeeklyTimeIntervalVector(policy_value));
- policy_variable->NotifyValueChanged();
- }
-
- bool IsMonitoringInterval() {
- return monitor_.has_value() && monitor_.value().IsMonitoringInterval();
- }
-
- void BuildMonitorAndVerify(const WeeklyTimeIntervalVector* policy_value,
- bool expect_delegate_called,
- bool expect_monitoring) {
- if (expect_delegate_called)
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(1);
- else
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(0);
-
- fake_state_.device_policy_provider()
- ->var_disallowed_time_intervals()
- ->reset(policy_value != nullptr
- ? new WeeklyTimeIntervalVector(*policy_value)
- : nullptr);
- monitor_.emplace(fake_state_.device_policy_provider(), &mock_delegate_);
- if (expect_delegate_called)
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
-
- if (expect_monitoring)
- EXPECT_TRUE(IsMonitoringInterval());
- else
- EXPECT_FALSE(IsMonitoringInterval());
- }
-
- base::SimpleTestClock test_clock_;
- FakeMessageLoop fake_loop_{&test_clock_};
- FakeState fake_state_;
- MockUpdateTimeRestrictionsMonitorDelegate mock_delegate_;
- base::Optional<UpdateTimeRestrictionsMonitor> monitor_;
-};
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest, PolicyIsNotSet) {
- BuildMonitorAndVerify(
- nullptr, /*expect_delegate_called=*/false, /*expect_monitoring=*/false);
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest, PolicyHasEmptyIntervalList) {
- WeeklyTimeIntervalVector empty_policy;
- BuildMonitorAndVerify(&empty_policy,
- /*expect_delegate_called=*/false,
- /*expect_monitoring=*/false);
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest,
- CurrentTimeOutsideOfRestrictedInterval) {
- ASSERT_TRUE(SetNow(kInitialTimeBeforeInterval));
- BuildMonitorAndVerify(&kTestTwoDisallowedTimeIntervals,
- /*expect_delegate_called=*/false,
- /*expect_monitoring=*/true);
-
- // Monitor should only notify start when passing start of interval.
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(1);
- AdvanceAfterTimestamp(
- kTestTwoDisallowedTimeIntervals[current_restricted_interval_index]
- .start());
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest,
- CurrentTimeWithinRestrictedInterval) {
- // Monitor should notify start when it is built with current
- // time within interval.
- ASSERT_TRUE(SetNow(kInitialTimeWithinInterval));
- BuildMonitorAndVerify(&kTestTwoDisallowedTimeIntervals,
- /*expect_delegate_called=*/true,
- /*expect_monitoring=*/false);
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest,
- PolicyChangeFromNotSetToOutsideInterval) {
- // Build monitor with empty initial list of intervals.
- BuildMonitorAndVerify(
- nullptr, /*expect_delegate_called=*/false, /*expect_monitoring=*/false);
-
- // Monitor should not do any notification right after intervals update.
- ASSERT_TRUE(SetNow(kInitialTimeBeforeInterval));
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(0);
- UpdateRestrictedIntervals(kTestTwoDisallowedTimeIntervals);
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
- EXPECT_TRUE(IsMonitoringInterval());
-
- // Advance time within new interval and check that notification happen.
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(1);
- AdvanceAfterTimestamp(
- kTestTwoDisallowedTimeIntervals[current_restricted_interval_index]
- .start());
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest,
- PolicyChangeFromNotSetToWithinInterval) {
- // Build monitor with empty initial list of intervals.
- BuildMonitorAndVerify(
- nullptr, /*expect_delegate_called=*/false, /*expect_monitoring=*/false);
-
- // Advance time inside upcoming new interval and update the intervals.
- // Monitor should immediately notify about started interval.
- ASSERT_TRUE(SetNow(kInitialTimeWithinInterval));
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(1);
- UpdateRestrictedIntervals(kTestTwoDisallowedTimeIntervals);
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest,
- PolicyChangeFromNotSetToEmptyInterval) {
- BuildMonitorAndVerify(
- nullptr, /*expect_delegate_called=*/false, /*expect_monitoring=*/false);
-
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(0);
- UpdateRestrictedIntervals(WeeklyTimeIntervalVector());
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
- EXPECT_FALSE(IsMonitoringInterval());
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest,
- PolicyChangeFromOneOutsideIntervalToAnother) {
- // Build monitor with current time outside the intervals.
- BuildMonitorAndVerify(&kTestTwoDisallowedTimeIntervals,
- /*expect_delegate_called=*/false,
- /*expect_monitoring=*/true);
-
- // Update the intervals to outide of current time and no notification should
- // happen yet.
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(0);
- UpdateRestrictedIntervals(kTestOneDisallowedTimeIntervals);
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
-
- // Advance time within new interval. Monitor should notify about started
- // interval.
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(1);
- AdvanceAfterTimestamp(
- kTestOneDisallowedTimeIntervals[current_restricted_interval_index]
- .start());
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
-}
-
-TEST_F(UmUpdateTimeRestrictionsMonitorTest,
- PolicyChangeFromOutsideIntervalToWithin) {
- ASSERT_TRUE(SetNow(kInitialTimeWithinInterval));
-
- // Build monitor with current time outside the intervals.
- BuildMonitorAndVerify(&kTestOneDisallowedTimeIntervals,
- /*expect_delegate_called=*/false,
- /*expect_monitoring=*/true);
-
- // Update interval such that current time is within it. Monitor should notify
- // about started interval.
- EXPECT_CALL(mock_delegate_, OnRestrictedIntervalStarts()).Times(1);
- UpdateRestrictedIntervals(kTestTwoDisallowedTimeIntervals);
- MessageLoopRunMaxIterations(MessageLoop::current(), 10);
- VerifyExpectationsOnDelegate();
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/update_time_restrictions_policy_impl.cc b/update_manager/update_time_restrictions_policy_impl.cc
deleted file mode 100644
index f9b83dee..00000000
--- a/update_manager/update_time_restrictions_policy_impl.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// Copyright (C) 2018 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/update_manager/update_time_restrictions_policy_impl.h"
-
-#include <memory>
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/device_policy_provider.h"
-#include "update_engine/update_manager/system_provider.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-using base::Time;
-using base::TimeDelta;
-
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-
-namespace chromeos_update_manager {
-
-EvalStatus UpdateTimeRestrictionsPolicyImpl::UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- ErrorCode* result,
- InstallPlan* install_plan) const {
- DevicePolicyProvider* const dp_provider = state->device_policy_provider();
- TimeProvider* const time_provider = state->time_provider();
-
- // If kiosk mode is not enabled, don't restrict updates.
- if (!ec->GetValue(dp_provider->var_auto_launched_kiosk_app_id()))
- return EvalStatus::kContinue;
-
- const Time* curr_date = ec->GetValue(time_provider->var_curr_date());
- const int* curr_hour = ec->GetValue(time_provider->var_curr_hour());
- const int* curr_minute = ec->GetValue(time_provider->var_curr_minute());
- if (!curr_date || !curr_hour || !curr_minute) {
- LOG(WARNING) << "Unable to access local time.";
- return EvalStatus::kContinue;
- }
-
- WeeklyTime now = WeeklyTime::FromTime(*curr_date);
- now.AddTime(TimeDelta::FromHours(*curr_hour) +
- TimeDelta::FromMinutes(*curr_minute));
-
- const WeeklyTimeIntervalVector* intervals =
- ec->GetValue(dp_provider->var_disallowed_time_intervals());
- if (!intervals) {
- return EvalStatus::kContinue;
- }
- for (const auto& interval : *intervals) {
- if (interval.InRange(now)) {
- *result = ErrorCode::kOmahaUpdateDeferredPerPolicy;
- return EvalStatus::kSucceeded;
- }
- }
-
- return EvalStatus::kContinue;
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/update_time_restrictions_policy_impl.h b/update_manager/update_time_restrictions_policy_impl.h
deleted file mode 100644
index 11cbceb6..00000000
--- a/update_manager/update_time_restrictions_policy_impl.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// Copyright (C) 2018 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_UPDATE_MANAGER_UPDATE_TIME_RESTRICTIONS_POLICY_IMPL_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_TIME_RESTRICTIONS_POLICY_IMPL_H_
-
-#include <string>
-
-#include <base/time/time.h>
-
-#include "update_engine/common/error_code.h"
-#include "update_engine/payload_consumer/install_plan.h"
-#include "update_engine/update_manager/policy_utils.h"
-
-namespace chromeos_update_manager {
-
-// Policy that allows administrators to set time intervals during which
-// automatic update checks are disallowed. This implementation then checks if
-// the current time falls in the range spanned by the time intervals. If the
-// current time falls in one of the intervals then the update check is
-// blocked by this policy.
-class UpdateTimeRestrictionsPolicyImpl : public PolicyImplBase {
- public:
- UpdateTimeRestrictionsPolicyImpl() = default;
- ~UpdateTimeRestrictionsPolicyImpl() override = default;
-
- // When the current time is inside one of the intervals returns
- // kSucceeded and sets |result| to kOmahaUpdateDeferredPerPolicy. If the
- // current time is not inside any intervals returns kContinue. In case of
- // errors, i.e. cannot access intervals or time, return kContinue.
- EvalStatus UpdateCanBeApplied(
- EvaluationContext* ec,
- State* state,
- std::string* error,
- chromeos_update_engine::ErrorCode* result,
- chromeos_update_engine::InstallPlan* install_plan) const override;
-
- protected:
- std::string PolicyName() const override {
- return "UpdateTimeRestrictionsPolicyImpl";
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(UpdateTimeRestrictionsPolicyImpl);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATE_TIME_RESTRICTIONS_POLICY_IMPL_H_
diff --git a/update_manager/update_time_restrictions_policy_impl_unittest.cc b/update_manager/update_time_restrictions_policy_impl_unittest.cc
deleted file mode 100644
index f99a2854..00000000
--- a/update_manager/update_time_restrictions_policy_impl_unittest.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-//
-// Copyright (C) 2018 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/update_manager/update_time_restrictions_policy_impl.h"
-
-#include <memory>
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/policy_test_utils.h"
-#include "update_engine/update_manager/weekly_time.h"
-
-using base::Time;
-using base::TimeDelta;
-using chromeos_update_engine::ErrorCode;
-using chromeos_update_engine::InstallPlan;
-using std::string;
-
-namespace chromeos_update_manager {
-
-constexpr TimeDelta kHour = TimeDelta::FromHours(1);
-constexpr TimeDelta kMinute = TimeDelta::FromMinutes(1);
-
-const WeeklyTimeIntervalVector kTestIntervals{
- // Monday 10:15 AM to Monday 3:30 PM.
- WeeklyTimeInterval(WeeklyTime(1, kHour * 10 + kMinute * 15),
- WeeklyTime(1, kHour * 15 + kMinute * 30)),
- // Wednesday 8:30 PM to Thursday 8:40 AM.
- WeeklyTimeInterval(WeeklyTime(3, kHour * 20 + kMinute * 30),
- WeeklyTime(4, kHour * 8 + kMinute * 40)),
-};
-
-class UmUpdateTimeRestrictionsPolicyImplTest : public UmPolicyTestBase {
- protected:
- UmUpdateTimeRestrictionsPolicyImplTest() {
- policy_ = std::make_unique<UpdateTimeRestrictionsPolicyImpl>();
- }
-
- void TestPolicy(const Time::Exploded& exploded,
- const WeeklyTimeIntervalVector& test_intervals,
- const EvalStatus& expected_value,
- bool kiosk) {
- if (kiosk)
- fake_state_.device_policy_provider()
- ->var_auto_launched_kiosk_app_id()
- ->reset(new string("myapp"));
-
- Time time;
- EXPECT_TRUE(Time::FromLocalExploded(exploded, &time));
- fake_clock_->SetWallclockTime(time);
- SetUpDefaultTimeProvider();
- fake_state_.device_policy_provider()
- ->var_disallowed_time_intervals()
- ->reset(new WeeklyTimeIntervalVector(test_intervals));
- ErrorCode result;
- InstallPlan install_plan;
- ExpectPolicyStatus(
- expected_value, &Policy::UpdateCanBeApplied, &result, &install_plan);
- if (expected_value == EvalStatus::kSucceeded)
- EXPECT_EQ(result, ErrorCode::kOmahaUpdateDeferredPerPolicy);
- }
-};
-
-// If there are no intervals, then the check should always return kContinue.
-TEST_F(UmUpdateTimeRestrictionsPolicyImplTest, NoIntervalsSetTest) {
- Time::Exploded random_time{2018, 7, 1, 9, 12, 30, 0, 0};
- TestPolicy(random_time,
- WeeklyTimeIntervalVector(),
- EvalStatus::kContinue,
- /* kiosk = */ true);
-}
-
-// Check that all intervals are checked.
-TEST_F(UmUpdateTimeRestrictionsPolicyImplTest, TimeInRange) {
- // Monday, July 9th 2018 12:30 PM.
- Time::Exploded first_interval_time{2018, 7, 1, 9, 12, 30, 0, 0};
- TestPolicy(first_interval_time,
- kTestIntervals,
- EvalStatus::kSucceeded,
- /* kiosk = */ true);
-
- // Check second interval.
- // Thursday, July 12th 2018 4:30 AM.
- Time::Exploded second_interval_time{2018, 7, 4, 12, 4, 30, 0, 0};
- TestPolicy(second_interval_time,
- kTestIntervals,
- EvalStatus::kSucceeded,
- /* kiosk = */ true);
-}
-
-TEST_F(UmUpdateTimeRestrictionsPolicyImplTest, TimeOutOfRange) {
- // Monday, July 9th 2018 6:30 PM.
- Time::Exploded out_of_range_time{2018, 7, 1, 9, 18, 30, 0, 0};
- TestPolicy(out_of_range_time,
- kTestIntervals,
- EvalStatus::kContinue,
- /* kiosk = */ true);
-}
-
-TEST_F(UmUpdateTimeRestrictionsPolicyImplTest, NoKioskDisablesPolicy) {
- Time::Exploded in_range_time{2018, 7, 1, 9, 12, 30, 0, 0};
- TestPolicy(in_range_time,
- kTestIntervals,
- EvalStatus::kContinue,
- /* kiosk = */ false);
-}
-} // namespace chromeos_update_manager
diff --git a/update_manager/updater_provider.h b/update_manager/updater_provider.h
deleted file mode 100644
index 86af1c8a..00000000
--- a/update_manager/updater_provider.h
+++ /dev/null
@@ -1,132 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_UPDATER_PROVIDER_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_UPDATER_PROVIDER_H_
-
-#include <string>
-
-#include <base/time/time.h>
-
-#include "update_engine/update_manager/provider.h"
-#include "update_engine/update_manager/variable.h"
-
-namespace chromeos_update_manager {
-
-enum class Stage {
- kIdle,
- kCheckingForUpdate,
- kUpdateAvailable,
- kDownloading,
- kVerifying,
- kFinalizing,
- kUpdatedNeedReboot,
- kReportingErrorEvent,
- kAttemptingRollback,
- kCleanupPreviousUpdate,
-};
-
-enum class UpdateRequestStatus {
- kNone,
- kInteractive,
- kPeriodic,
-};
-
-// These enum values are a bit-field.
-enum UpdateRestrictions : int {
- kNone,
- kRestrictDownloading = (1 << 0),
-};
-
-// Provider for Chrome OS update related information.
-class UpdaterProvider : public Provider {
- public:
- ~UpdaterProvider() override {}
-
- // A variable returning the timestamp when the update engine was started in
- // wallclock time.
- virtual Variable<base::Time>* var_updater_started_time() = 0;
-
- // A variable returning the last update check time.
- virtual Variable<base::Time>* var_last_checked_time() = 0;
-
- // A variable reporting the time when an update was last completed in the
- // current boot cycle. Returns an error if an update completed time could not
- // be read (e.g. no update was completed in the current boot cycle) or is
- // invalid.
- //
- // IMPORTANT: The time reported is not the wallclock time reading at the time
- // of the update, rather it is the point in time when the update completed
- // relative to the current wallclock time reading. Therefore, the gap between
- // the reported value and the current wallclock time is guaranteed to be
- // monotonically increasing.
- virtual Variable<base::Time>* var_update_completed_time() = 0;
-
- // A variable returning the update progress (0.0 to 1.0).
- virtual Variable<double>* var_progress() = 0;
-
- // A variable returning the current update status.
- virtual Variable<Stage>* var_stage() = 0;
-
- // A variable returning the update target version.
- virtual Variable<std::string>* var_new_version() = 0;
-
- // A variable returning the update payload size. The payload size is
- // guaranteed to be non-negative.
- virtual Variable<uint64_t>* var_payload_size() = 0;
-
- // A variable returning the current channel.
- virtual Variable<std::string>* var_curr_channel() = 0;
-
- // A variable returning the update target channel.
- virtual Variable<std::string>* var_new_channel() = 0;
-
- // A variable indicating whether user settings allow P2P updates.
- virtual Variable<bool>* var_p2p_enabled() = 0;
-
- // A variable indicating whether user settings allow updates over a cellular
- // network.
- virtual Variable<bool>* var_cellular_enabled() = 0;
-
- // A variable returning the number of consecutive failed update checks.
- virtual Variable<unsigned int>* var_consecutive_failed_update_checks() = 0;
-
- // A server-dictated update check interval in seconds, if one was given.
- virtual Variable<unsigned int>* var_server_dictated_poll_interval() = 0;
-
- // A variable denoting whether a forced update was request but no update check
- // performed yet; also tells whether this request is for an interactive or
- // scheduled update.
- virtual Variable<UpdateRequestStatus>* var_forced_update_requested() = 0;
-
- // A variable that returns the update restriction flags that are set
- // 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() {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(UpdaterProvider);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_UPDATER_PROVIDER_H_
diff --git a/update_manager/variable.h b/update_manager/variable.h
deleted file mode 100644
index 9ac7dae6..00000000
--- a/update_manager/variable.h
+++ /dev/null
@@ -1,230 +0,0 @@
-//
-// Copyright (C) 2014 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_UPDATE_MANAGER_VARIABLE_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
-
-#include <algorithm>
-#include <list>
-#include <string>
-
-#include <base/bind.h>
-#include <base/location.h>
-#include <base/logging.h>
-#include <base/time/time.h>
-#include <brillo/message_loops/message_loop.h>
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
-namespace chromeos_update_manager {
-
-// The VariableMode specifies important behavior of the variable in terms of
-// whether, how and when the value of the variable changes.
-enum VariableMode {
- // Const variables never changes during the life of a policy request, so the
- // EvaluationContext caches the value even between different evaluations of
- // the same policy request.
- kVariableModeConst,
-
- // Poll variables, or synchronous variables, represent a variable with a value
- // that can be queried at any time, but it is not known when the value
- // changes on the source of information. In order to detect if the value of
- // the variable changes, it has to be queried again.
- kVariableModePoll,
-
- // Async variables are able to produce a signal or callback whenever the
- // value changes. This means that it's not required to poll the value to
- // detect when it changes, instead, you should register an observer to get
- // a notification when that happens.
- kVariableModeAsync,
-};
-
-// This class is a base class with the common functionality that doesn't
-// depend on the variable's type, implemented by all the variables.
-class BaseVariable {
- public:
- // Interface for observing changes on variable value.
- class ObserverInterface {
- public:
- virtual ~ObserverInterface() {}
-
- // Called when the value on the variable changes.
- virtual void ValueChanged(BaseVariable* variable) = 0;
- };
-
- virtual ~BaseVariable() {
- if (!observer_list_.empty()) {
- LOG(WARNING) << "Variable " << name_ << " deleted with "
- << observer_list_.size() << " observers.";
- }
- DCHECK(observer_list_.empty()) << "Don't destroy the variable without "
- "removing the observers.";
- }
-
- // Returns the variable name as a string.
- const std::string& GetName() const { return name_; }
-
- // Returns the variable mode.
- VariableMode GetMode() const { return mode_; }
-
- // For VariableModePoll variables, it returns the polling interval of this
- // 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.
- virtual void AddObserver(BaseVariable::ObserverInterface* observer) {
- if (std::find(observer_list_.begin(), observer_list_.end(), observer) ==
- observer_list_.end()) {
- observer_list_.push_back(observer);
- }
- }
-
- virtual void RemoveObserver(BaseVariable::ObserverInterface* observer) {
- observer_list_.remove(observer);
- }
-
- protected:
- // Creates a BaseVariable using the default polling interval (5 minutes).
- BaseVariable(const std::string& name, VariableMode mode)
- : BaseVariable(
- name, mode, base::TimeDelta::FromMinutes(kDefaultPollMinutes)) {}
-
- // Creates a BaseVariable with mode kVariableModePoll and the provided
- // polling interval.
- BaseVariable(const std::string& name, base::TimeDelta poll_interval)
- : BaseVariable(name, kVariableModePoll, poll_interval) {}
-
- // Reset the poll interval on a polling variable to the given one.
- void SetPollInterval(base::TimeDelta poll_interval) {
- DCHECK_EQ(kVariableModePoll, mode_)
- << "Can't set the poll_interval on a " << mode_ << " variable";
- 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
- // to avoid scheduling these callbacks when it is not needed, we check
- // first the list of observers.
- if (!observer_list_.empty()) {
- brillo::MessageLoop::current()->PostTask(
- FROM_HERE,
- base::Bind(&BaseVariable::OnValueChangedNotification,
- base::Unretained(this)));
- }
- }
-
- private:
- friend class UmEvaluationContextTest;
- FRIEND_TEST(UmBaseVariableTest, RepeatedObserverTest);
- FRIEND_TEST(UmBaseVariableTest, NotifyValueChangedTest);
- FRIEND_TEST(UmBaseVariableTest, NotifyValueRemovesObserversTest);
-
- BaseVariable(const std::string& name,
- VariableMode mode,
- base::TimeDelta poll_interval)
- : name_(name),
- mode_(mode),
- poll_interval_(mode == kVariableModePoll ? poll_interval
- : base::TimeDelta()),
- missing_ok_(false) {}
-
- void OnValueChangedNotification() {
- // A ValueChanged() method can change the list of observers, for example
- // removing itself and invalidating the iterator, so we create a snapshot
- // of the observers first. Also, to support the case when *another* observer
- // is removed, we check for them.
- std::list<BaseVariable::ObserverInterface*> observer_list_copy(
- observer_list_);
-
- for (auto& observer : observer_list_copy) {
- if (std::find(observer_list_.begin(), observer_list_.end(), observer) !=
- observer_list_.end()) {
- observer->ValueChanged(this);
- }
- }
- }
-
- // The default PollInterval in minutes.
- static constexpr int kDefaultPollMinutes = 5;
-
- // The variable's name as a string.
- const std::string name_;
-
- // The variable's mode.
- const VariableMode mode_;
-
- // The variable's polling interval for VariableModePoll variable and 0 for
- // other modes.
- base::TimeDelta poll_interval_;
-
- // 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);
-};
-
-// Interface to an Update Manager variable of a given type. Implementation
-// internals are hidden as protected members, since policies should not be
-// using them directly.
-template <typename T>
-class Variable : public BaseVariable {
- public:
- ~Variable() override {}
-
- protected:
- // Only allow to get values through the EvaluationContext class and not
- // directly from the variable.
- friend class EvaluationContext;
-
- // Needed to be able to verify variable contents during unit testing.
- friend class UmTestUtils;
- FRIEND_TEST(UmRealRandomProviderTest, GetRandomValues);
-
- Variable(const std::string& name, VariableMode mode)
- : BaseVariable(name, mode) {}
-
- Variable(const std::string& name, const base::TimeDelta poll_interval)
- : BaseVariable(name, poll_interval) {}
-
- // Gets the current value of the variable. The current value is copied to a
- // new object and returned. The caller of this method owns the object and
- // should delete it.
- //
- // In case of and error getting the current value or the |timeout| timeout is
- // exceeded, a null value is returned and the |errmsg| is set.
- //
- // The caller can pass a null value for |errmsg|, in which case the error
- // message won't be set.
- virtual const T* GetValue(base::TimeDelta timeout, std::string* errmsg) = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Variable);
-};
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_VARIABLE_H_
diff --git a/update_manager/variable_unittest.cc b/update_manager/variable_unittest.cc
deleted file mode 100644
index fe40ce58..00000000
--- a/update_manager/variable_unittest.cc
+++ /dev/null
@@ -1,176 +0,0 @@
-//
-// Copyright (C) 2014 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/update_manager/variable.h"
-
-#include <vector>
-
-#include <brillo/message_loops/fake_message_loop.h>
-#include <brillo/message_loops/message_loop.h>
-#include <brillo/message_loops/message_loop_utils.h>
-#include <gtest/gtest.h>
-
-using base::TimeDelta;
-using brillo::MessageLoop;
-using brillo::MessageLoopRunMaxIterations;
-using std::string;
-using std::vector;
-
-namespace chromeos_update_manager {
-
-// Variable class that returns a value constructed with the default value.
-template <typename T>
-class DefaultVariable : public Variable<T> {
- public:
- DefaultVariable(const string& name, VariableMode mode)
- : Variable<T>(name, mode) {}
- DefaultVariable(const string& name, const TimeDelta& poll_interval)
- : Variable<T>(name, poll_interval) {}
- ~DefaultVariable() override {}
-
- protected:
- const T* GetValue(TimeDelta /* timeout */, string* /* errmsg */) override {
- return new T();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DefaultVariable);
-};
-
-class UmBaseVariableTest : public ::testing::Test {
- protected:
- void SetUp() override { loop_.SetAsCurrent(); }
-
- brillo::FakeMessageLoop loop_{nullptr};
-};
-
-TEST_F(UmBaseVariableTest, GetNameTest) {
- DefaultVariable<int> var("var", kVariableModeConst);
- EXPECT_EQ(var.GetName(), string("var"));
-}
-
-TEST_F(UmBaseVariableTest, GetModeTest) {
- DefaultVariable<int> var("var", kVariableModeConst);
- EXPECT_EQ(var.GetMode(), kVariableModeConst);
- DefaultVariable<int> other_var("other_var", kVariableModePoll);
- EXPECT_EQ(other_var.GetMode(), kVariableModePoll);
-}
-
-TEST_F(UmBaseVariableTest, DefaultPollIntervalTest) {
- DefaultVariable<int> const_var("const_var", kVariableModeConst);
- EXPECT_EQ(const_var.GetPollInterval(), TimeDelta());
- DefaultVariable<int> poll_var("poll_var", kVariableModePoll);
- EXPECT_EQ(poll_var.GetPollInterval(), TimeDelta::FromMinutes(5));
-}
-
-TEST_F(UmBaseVariableTest, GetPollIntervalTest) {
- DefaultVariable<int> var("var", TimeDelta::FromMinutes(3));
- EXPECT_EQ(var.GetMode(), kVariableModePoll);
- EXPECT_EQ(var.GetPollInterval(), TimeDelta::FromMinutes(3));
-}
-
-class BaseVariableObserver : public BaseVariable::ObserverInterface {
- public:
- void ValueChanged(BaseVariable* variable) { calls_.push_back(variable); }
-
- // List of called functions.
- vector<BaseVariable*> calls_;
-};
-
-TEST_F(UmBaseVariableTest, RepeatedObserverTest) {
- DefaultVariable<int> var("var", kVariableModeAsync);
- BaseVariableObserver observer;
- var.AddObserver(&observer);
- EXPECT_EQ(1U, var.observer_list_.size());
- var.AddObserver(&observer);
- EXPECT_EQ(1U, var.observer_list_.size());
- var.RemoveObserver(&observer);
- EXPECT_EQ(0U, var.observer_list_.size());
- var.RemoveObserver(&observer);
- EXPECT_EQ(0U, var.observer_list_.size());
-}
-
-TEST_F(UmBaseVariableTest, NotifyValueChangedTest) {
- DefaultVariable<int> var("var", kVariableModeAsync);
- BaseVariableObserver observer1;
- var.AddObserver(&observer1);
- // Simulate a value change on the variable's implementation.
- var.NotifyValueChanged();
- ASSERT_EQ(0U, observer1.calls_.size());
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
-
- ASSERT_EQ(1U, observer1.calls_.size());
- // Check that the observer is called with the right argument.
- EXPECT_EQ(&var, observer1.calls_[0]);
-
- BaseVariableObserver observer2;
- var.AddObserver(&observer2);
- var.NotifyValueChanged();
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
-
- // Check that all the observers are called.
- EXPECT_EQ(2U, observer1.calls_.size());
- EXPECT_EQ(1U, observer2.calls_.size());
-
- var.RemoveObserver(&observer1);
- var.RemoveObserver(&observer2);
-}
-
-class BaseVariableObserverRemover : public BaseVariable::ObserverInterface {
- public:
- BaseVariableObserverRemover() : calls_(0) {}
-
- void ValueChanged(BaseVariable* variable) override {
- for (auto& observer : remove_observers_) {
- variable->RemoveObserver(observer);
- }
- calls_++;
- }
-
- void OnCallRemoveObserver(BaseVariable::ObserverInterface* observer) {
- remove_observers_.push_back(observer);
- }
-
- int get_calls() { return calls_; }
-
- private:
- vector<BaseVariable::ObserverInterface*> remove_observers_;
- int calls_;
-};
-
-// Tests that we can remove an observer from a Variable on the ValueChanged()
-// call to that observer.
-TEST_F(UmBaseVariableTest, NotifyValueRemovesObserversTest) {
- DefaultVariable<int> var("var", kVariableModeAsync);
- BaseVariableObserverRemover observer1;
- BaseVariableObserverRemover observer2;
-
- var.AddObserver(&observer1);
- var.AddObserver(&observer2);
-
- // Make each observer remove both observers on ValueChanged.
- observer1.OnCallRemoveObserver(&observer1);
- observer1.OnCallRemoveObserver(&observer2);
- observer2.OnCallRemoveObserver(&observer1);
- observer2.OnCallRemoveObserver(&observer2);
-
- var.NotifyValueChanged();
- MessageLoopRunMaxIterations(MessageLoop::current(), 100);
-
- EXPECT_EQ(1, observer1.get_calls() + observer2.get_calls());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/weekly_time.cc b/update_manager/weekly_time.cc
deleted file mode 100644
index e478f9fb..00000000
--- a/update_manager/weekly_time.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-//
-// Copyright (C) 2018 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/update_manager/weekly_time.h"
-
-#include <base/strings/string_number_conversions.h>
-#include <base/strings/stringprintf.h>
-#include <base/time/time.h>
-
-using base::Time;
-using base::TimeDelta;
-using std::string;
-
-namespace {
-const int kDaysInWeek = 7;
-}
-
-namespace chromeos_update_manager {
-
-TimeDelta WeeklyTime::GetDurationTo(const WeeklyTime& other) const {
- if (other.TimeFromStartOfWeek() < TimeFromStartOfWeek()) {
- return other.TimeFromStartOfWeek() +
- (TimeDelta::FromDays(kDaysInWeek) - TimeFromStartOfWeek());
- }
- return other.TimeFromStartOfWeek() - TimeFromStartOfWeek();
-}
-
-TimeDelta WeeklyTime::TimeFromStartOfWeek() const {
- return TimeDelta::FromDays(day_of_week_) + time_;
-}
-
-void WeeklyTime::AddTime(const TimeDelta& offset) {
- time_ += offset;
- int days_over = time_.InDays();
- time_ -= TimeDelta::FromDays(days_over);
- day_of_week_ = (day_of_week_ + days_over - 1) % kDaysInWeek + 1;
-}
-
-// static
-WeeklyTime WeeklyTime::FromTime(const Time& time) {
- Time::Exploded exploded;
- time.LocalExplode(&exploded);
- return WeeklyTime(exploded.day_of_week,
- TimeDelta::FromHours(exploded.hour) +
- TimeDelta::FromMinutes(exploded.minute));
-}
-
-bool WeeklyTimeInterval::InRange(const WeeklyTime& time) const {
- return time == start_ ||
- (time.GetDurationTo(start_) >= time.GetDurationTo(end_) &&
- time != end_);
-}
-
-string WeeklyTimeInterval::ToString() const {
- return base::StringPrintf(
- "Start: day_of_week=%d time=%d\nEnd: day_of_week=%d time=%d",
- start_.day_of_week(),
- start_.time().InMinutes(),
- end_.day_of_week(),
- end_.time().InMinutes());
-}
-
-} // namespace chromeos_update_manager
diff --git a/update_manager/weekly_time.h b/update_manager/weekly_time.h
deleted file mode 100644
index 9e3a039d..00000000
--- a/update_manager/weekly_time.h
+++ /dev/null
@@ -1,97 +0,0 @@
-//
-// Copyright (C) 2018 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_UPDATE_MANAGER_WEEKLY_TIME_H_
-#define UPDATE_ENGINE_UPDATE_MANAGER_WEEKLY_TIME_H_
-
-#include <string>
-#include <vector>
-
-#include <base/time/time.h>
-
-namespace chromeos_update_manager {
-
-// Represents a day of the week and the time since it started.
-class WeeklyTime {
- public:
- // Day of week (Sunday = 0 and so on) and time since start of the day (12 AM).
- WeeklyTime(const int& day_of_week, const base::TimeDelta& time)
- : day_of_week_(day_of_week), time_(time) {}
-
- // Create a weekly time from a time object.
- static WeeklyTime FromTime(const base::Time& time);
-
- bool operator==(const WeeklyTime& other) const {
- return time_ == other.time() && day_of_week_ == other.day_of_week();
- }
-
- bool operator!=(const WeeklyTime& other) const { return !(*this == other); }
-
- // Return the duration between WeeklyTime and |other|. |other| is always
- // considered to be after WeeklyTime. i.e. calling this function on [Friday
- // 12:00, Monday 12:00] would return 3 days.
- base::TimeDelta GetDurationTo(const WeeklyTime& other) const;
-
- // Gets the weekly time represented as a time delta.
- base::TimeDelta TimeFromStartOfWeek() const;
-
- // Adds the given |offset| to the time with proper wraparound (e.g. Sunday + 1
- // day = Monday).
- void AddTime(const base::TimeDelta& offset);
-
- int day_of_week() const { return day_of_week_; }
-
- base::TimeDelta time() const { return time_; }
-
- private:
- int day_of_week_;
- base::TimeDelta time_;
-};
-
-// Represents an interval of time during a week represented with WeeklyTime
-// objects. This interval can span at most 7 days. |end| is always considered to
-// be after |start|, this is possible since the times of the week are cyclic.
-// For example, the interval [Thursday 12:00, Monday 12:00) will span the time
-// between Thursday and Monday.
-class WeeklyTimeInterval {
- public:
- WeeklyTimeInterval(const WeeklyTime& start, const WeeklyTime& end)
- : start_(start), end_(end) {}
-
- // Determines if |time| is in this interval.
- bool InRange(const WeeklyTime& time) const;
-
- WeeklyTime start() const { return start_; }
-
- WeeklyTime end() const { return end_; }
-
- bool operator==(const WeeklyTimeInterval& other) const {
- return start_ == other.start() && end_ == other.end();
- }
-
- // Converts the interval to a string. Used for the BoxedValue ToString
- // function.
- std::string ToString() const;
-
- private:
- WeeklyTime start_;
- WeeklyTime end_;
-};
-
-using WeeklyTimeIntervalVector = std::vector<WeeklyTimeInterval>;
-
-} // namespace chromeos_update_manager
-
-#endif // UPDATE_ENGINE_UPDATE_MANAGER_WEEKLY_TIME_H_
diff --git a/update_manager/weekly_time_unittest.cc b/update_manager/weekly_time_unittest.cc
deleted file mode 100644
index 52c5425d..00000000
--- a/update_manager/weekly_time_unittest.cc
+++ /dev/null
@@ -1,212 +0,0 @@
-//
-// Copyright (C) 2018 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/update_manager/weekly_time.h"
-
-#include <tuple>
-
-#include <base/time/time.h>
-#include <gtest/gtest.h>
-
-using base::TimeDelta;
-using std::tuple;
-
-namespace chromeos_update_manager {
-
-namespace {
-
-enum {
- kSunday = 0,
- kMonday,
- kTuesday,
- kWednesday,
- kThursday,
- kFriday,
- kSaturday
-};
-
-} // namespace
-
-class WeeklyTimeDurationTest
- : public testing::TestWithParam<tuple<int /* start_day_of_week */,
- TimeDelta /* start_time */,
- int /* end_day_of_week */,
- TimeDelta /* end_time */,
- TimeDelta /* expected result */>> {
- protected:
- int start_day_of_week() { return std::get<0>(GetParam()); }
- TimeDelta start_time() { return std::get<1>(GetParam()); }
- int end_day_of_week() { return std::get<2>(GetParam()); }
- TimeDelta end_time() { return std::get<3>(GetParam()); }
- TimeDelta result() { return std::get<4>(GetParam()); }
-};
-
-TEST_P(WeeklyTimeDurationTest, GetDurationTo) {
- WeeklyTime start = WeeklyTime(start_day_of_week(), start_time());
- WeeklyTime end = WeeklyTime(end_day_of_week(), end_time());
-
- EXPECT_EQ(result(), start.GetDurationTo(end));
-}
-
-INSTANTIATE_TEST_CASE_P(
- SameMinutes,
- WeeklyTimeDurationTest,
- testing::Values(std::make_tuple(kThursday,
- TimeDelta::FromMinutes(30),
- kSaturday,
- TimeDelta::FromMinutes(30),
- TimeDelta::FromDays(2))));
-
-INSTANTIATE_TEST_CASE_P(
- DifferentMinutes,
- WeeklyTimeDurationTest,
- testing::Values(std::make_tuple(kMonday,
- TimeDelta::FromMinutes(10),
- kWednesday,
- TimeDelta::FromMinutes(30),
- TimeDelta::FromDays(2) +
- TimeDelta::FromMinutes(20))));
-
-INSTANTIATE_TEST_CASE_P(
- EndLessThanStartSameMinutes,
- WeeklyTimeDurationTest,
- testing::Values(std::make_tuple(kSaturday,
- TimeDelta::FromMinutes(100),
- kTuesday,
- TimeDelta::FromMinutes(100),
- TimeDelta::FromDays(3))));
-
-INSTANTIATE_TEST_CASE_P(
- EndLessThanStartDifferentMinutes,
- WeeklyTimeDurationTest,
- testing::Values(std::make_tuple(kSaturday,
- TimeDelta::FromMinutes(150),
- kMonday,
- TimeDelta::FromMinutes(10),
- TimeDelta::FromDays(2) -
- TimeDelta::FromMinutes(140))));
-
-class WeeklyTimeOffsetTest
- : public testing::TestWithParam<tuple<int /* day_of_week */,
- TimeDelta /* time */,
- TimeDelta /* offset */,
- WeeklyTime /* expected result */>> {
- protected:
- int day_of_week() { return std::get<0>(GetParam()); }
- TimeDelta time() { return std::get<1>(GetParam()); }
- TimeDelta offset() { return std::get<2>(GetParam()); }
- WeeklyTime result() { return std::get<3>(GetParam()); }
-};
-
-TEST_P(WeeklyTimeOffsetTest, WeekTimeAddTime) {
- WeeklyTime test_time = WeeklyTime(day_of_week(), time());
- test_time.AddTime(offset());
-
- EXPECT_EQ(result(), test_time);
-}
-
-INSTANTIATE_TEST_CASE_P(
- SameDayTest,
- WeeklyTimeOffsetTest,
- testing::Values(std::make_tuple(kTuesday,
- TimeDelta::FromMinutes(200),
- TimeDelta::FromMinutes(400),
- WeeklyTime(kTuesday,
- TimeDelta::FromMinutes(600)))));
-
-INSTANTIATE_TEST_CASE_P(DayChangeTest,
- WeeklyTimeOffsetTest,
- testing::Values(std::make_tuple(
- kThursday,
- TimeDelta::FromHours(23),
- TimeDelta::FromHours(2),
- WeeklyTime(kFriday, TimeDelta::FromHours(1)))));
-
-INSTANTIATE_TEST_CASE_P(DayChangeTestOver7,
- WeeklyTimeOffsetTest,
- testing::Values(std::make_tuple(
- kSunday,
- TimeDelta::FromHours(20),
- TimeDelta::FromDays(3),
- WeeklyTime(kWednesday, TimeDelta::FromHours(20)))));
-
-class WeeklyTimeIntervalRangeTest
- : public testing::TestWithParam<tuple<int /* test_day_of_week */,
- int /* test_time */,
- bool /* in regular interval */,
- bool /* in short interval */,
- bool /* |start| < | */>> {
- protected:
- int day_of_week() { return std::get<0>(GetParam()); }
- int minutes() { return std::get<1>(GetParam()); }
- bool regular_result() { return std::get<2>(GetParam()); }
- bool short_result() { return std::get<3>(GetParam()); }
- bool wraparound_result() { return std::get<4>(GetParam()); }
-};
-
-TEST_P(WeeklyTimeIntervalRangeTest, InRange) {
- WeeklyTime test =
- WeeklyTime(day_of_week(), TimeDelta::FromMinutes(minutes()));
- WeeklyTimeInterval interval_regular =
- WeeklyTimeInterval(WeeklyTime(kMonday, TimeDelta::FromMinutes(10)),
- WeeklyTime(kWednesday, TimeDelta::FromMinutes(30)));
- WeeklyTimeInterval interval_short =
- WeeklyTimeInterval(WeeklyTime(kThursday, TimeDelta::FromMinutes(10)),
- WeeklyTime(kThursday, TimeDelta::FromMinutes(11)));
-
- WeeklyTimeInterval interval_wraparound =
- WeeklyTimeInterval(WeeklyTime(kFriday, TimeDelta::FromMinutes(10)),
- WeeklyTime(kTuesday, TimeDelta::FromMinutes(30)));
-
- EXPECT_EQ(regular_result(), interval_regular.InRange(test));
- EXPECT_EQ(short_result(), interval_short.InRange(test));
- EXPECT_EQ(wraparound_result(), interval_wraparound.InRange(test));
-}
-
-// Test the left side of the range being inclusive.
-INSTANTIATE_TEST_CASE_P(
- InclusiveSuccessLeft,
- WeeklyTimeIntervalRangeTest,
- testing::Values(std::make_tuple(kThursday, 10, false, true, false)));
-
-// Test the right side of the range being exclusive.
-INSTANTIATE_TEST_CASE_P(
- ExclusiveSuccessRight,
- WeeklyTimeIntervalRangeTest,
- testing::Values(std::make_tuple(kThursday, 11, false, false, false)));
-
-// Test falling out of the interval by a small amount.
-INSTANTIATE_TEST_CASE_P(
- FailOutsideRangeSmall,
- WeeklyTimeIntervalRangeTest,
- testing::Values(std::make_tuple(kThursday, 12, false, false, false)));
-
-// These test cases check that intervals wrap around properly.
-INSTANTIATE_TEST_CASE_P(
- WraparoundOutside,
- WeeklyTimeIntervalRangeTest,
- testing::Values(std::make_tuple(kWednesday, 10, true, false, false)));
-
-INSTANTIATE_TEST_CASE_P(
- WraparoundInsideRight,
- WeeklyTimeIntervalRangeTest,
- testing::Values(std::make_tuple(kSaturday, 10, false, false, true)));
-
-INSTANTIATE_TEST_CASE_P(
- WraparoundInsideLeft,
- WeeklyTimeIntervalRangeTest,
- testing::Values(std::make_tuple(kMonday, 0, false, false, true)));
-
-} // namespace chromeos_update_manager
diff --git a/update_metadata.proto b/update_metadata.proto
index 93e4e2e1..3f454add 100644
--- a/update_metadata.proto
+++ b/update_metadata.proto
@@ -146,25 +146,6 @@ message PartitionInfo {
optional bytes hash = 2;
}
-// Describe an image we are based on in a human friendly way.
-// Examples:
-// dev-channel, x86-alex, 1.2.3, mp-v3
-// nplusone-channel, x86-alex, 1.2.4, mp-v3, dev-channel, 1.2.3
-//
-// All fields will be set, if this message is present.
-message ImageInfo {
- optional string board = 1 [deprecated = true];
- optional string key = 2 [deprecated = true];
- optional string channel = 3 [deprecated = true];
- optional string version = 4 [deprecated = true];
-
- // If these values aren't present, they should be assumed to match
- // the equivalent value above. They are normally only different for
- // special image types such as nplusone images.
- optional string build_channel = 5 [deprecated = true];
- optional string build_version = 6 [deprecated = true];
-}
-
message InstallOperation {
enum Type {
REPLACE = 0; // Replace destination extents w/ attached data.
@@ -187,6 +168,13 @@ message InstallOperation {
// On minor version 5 or newer, these operations are supported:
PUFFDIFF = 9; // The data is in puffdiff format.
+
+ // On minor version 8 or newer, these operations are supported:
+ ZUCCHINI = 11;
+
+ // On minor version 9 or newer, these operations are supported:
+ LZ4DIFF_BSDIFF = 12;
+ LZ4DIFF_PUFFDIFF = 13;
}
required Type type = 1;
@@ -233,12 +221,22 @@ message InstallOperation {
// read after write, similar to the inplace update schema.
message CowMergeOperation {
enum Type {
- COW_COPY = 0; // identical blocks
+ COW_COPY = 0; // identical blocks
+ COW_XOR = 1; // used when src/dst blocks are highly similar
+ COW_REPLACE = 2; // Raw replace operation
}
optional Type type = 1;
optional Extent src_extent = 2;
optional Extent dst_extent = 3;
+ // For COW_XOR, source location might be unaligned, so this field is in range
+ // [0, block_size), representing how much should the src_extent shift toward
+ // larger block number. If this field is non-zero, then src_extent will
+ // include 1 extra block in the end, as the merge op actually references the
+ // first |src_offset| bytes of that extra block. For example, if |dst_extent|
+ // is [10, 15], |src_offset| is 500, then src_extent might look like [25, 31].
+ // Note that |src_extent| contains 1 extra block than the |dst_extent|.
+ optional uint32 src_offset = 4;
}
// Describes the update to apply to a single partition.
@@ -384,8 +382,7 @@ message DeltaArchiveManifest {
// Only present in major version = 1. List of install operations for the
// kernel and rootfs partitions. For major version = 2 see the |partitions|
// field.
- repeated InstallOperation install_operations = 1 [deprecated = true];
- repeated InstallOperation kernel_install_operations = 2 [deprecated = true];
+ reserved 1, 2;
// (At time of writing) usually 4096
optional uint32 block_size = 3 [default = 4096];
@@ -398,17 +395,8 @@ message DeltaArchiveManifest {
optional uint64 signatures_offset = 4;
optional uint64 signatures_size = 5;
- // Only present in major version = 1. Partition metadata used to validate the
- // update. For major version = 2 see the |partitions| field.
- optional PartitionInfo old_kernel_info = 6 [deprecated = true];
- optional PartitionInfo new_kernel_info = 7 [deprecated = true];
- optional PartitionInfo old_rootfs_info = 8 [deprecated = true];
- optional PartitionInfo new_rootfs_info = 9 [deprecated = true];
-
- // old_image_info will only be present for delta images.
- optional ImageInfo old_image_info = 10 [deprecated = true];
-
- optional ImageInfo new_image_info = 11 [deprecated = true];
+ // Fields deprecated in major version 2.
+ reserved 6,7,8,9,10,11;
// The minor version, also referred as "delta version", of the payload.
// Minor version 0 is full payload, everything else is delta payload.
diff --git a/update_status_utils.cc b/update_status_utils.cc
index a702c61a..6b96dda6 100644
--- a/update_status_utils.cc
+++ b/update_status_utils.cc
@@ -18,7 +18,6 @@
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include <brillo/key_value_store.h>
-#include <update_engine/dbus-constants.h>
using brillo::KeyValueStore;
using std::string;
@@ -40,6 +39,27 @@ const char kNewVersion[] = "NEW_VERSION";
const char kProgress[] = "PROGRESS";
const char kWillPowerwashAfterReboot[] = "WILL_POWERWASH_AFTER_REBOOT";
+namespace update_engine {
+const char kUpdateStatusIdle[] = "UPDATE_STATUS_IDLE";
+const char kUpdateStatusCheckingForUpdate[] =
+ "UPDATE_STATUS_CHECKING_FOR_UPDATE";
+const char kUpdateStatusUpdateAvailable[] = "UPDATE_STATUS_UPDATE_AVAILABLE";
+const char kUpdateStatusDownloading[] = "UPDATE_STATUS_DOWNLOADING";
+const char kUpdateStatusVerifying[] = "UPDATE_STATUS_VERIFYING";
+const char kUpdateStatusFinalizing[] = "UPDATE_STATUS_FINALIZING";
+const char kUpdateStatusUpdatedNeedReboot[] =
+ "UPDATE_STATUS_UPDATED_NEED_REBOOT";
+const char kUpdateStatusReportingErrorEvent[] =
+ "UPDATE_STATUS_REPORTING_ERROR_EVENT";
+const char kUpdateStatusAttemptingRollback[] =
+ "UPDATE_STATUS_ATTEMPTING_ROLLBACK";
+const char kUpdateStatusDisabled[] = "UPDATE_STATUS_DISABLED";
+const char kUpdateStatusNeedPermissionToUpdate[] =
+ "UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE";
+const char kUpdateStatusCleanupPreviousUpdate[] =
+ "UPDATE_STATUS_CLEANUP_PREVIOUS_UPDATE";
+} // namespace update_engine
+
} // namespace
const char* UpdateStatusToString(const UpdateStatus& status) {