blob: 9c0843cccc3d628ffbfbc77b71be9c1cb50de080 [file] [log] [blame]
Yifan Hongdad0af82020-02-19 17:19:49 -08001//
2// Copyright (C) 2020 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Amin Hassaniec7bc112020-10-29 16:47:58 -070016#include "update_engine/aosp/cleanup_previous_update_action.h"
Yifan Hongdad0af82020-02-19 17:19:49 -080017
Kelvin Zhang8bcb2212023-11-16 10:45:29 -080018#include <algorithm>
Kelvin Zhanga4650bd2023-12-20 13:52:31 -080019#include <chrono>
Yifan Hongdad0af82020-02-19 17:19:49 -080020#include <functional>
21#include <string>
Yifan Hong24031712020-03-19 19:25:38 -070022#include <type_traits>
Yifan Hongdad0af82020-02-19 17:19:49 -080023
David Anderson0c37f622021-03-11 18:40:25 -080024#include <android-base/chrono_utils.h>
Yifan Hongdad0af82020-02-19 17:19:49 -080025#include <android-base/properties.h>
26#include <base/bind.h>
Kelvin Zhanga4650bd2023-12-20 13:52:31 -080027#include <libsnapshot/snapshot.h>
Yifan Hongdad0af82020-02-19 17:19:49 -080028
Nikita Putikhine788f952024-03-11 19:21:24 +010029#if !defined(__ANDROID_RECOVERY__) && !defined(UE_DISABLE_STATS)
Vova Sharaienkod62c81b2022-09-21 05:32:43 +000030#include <statslog_ue.h>
Yifan Hongd976cc52020-02-25 14:51:42 -080031#endif
32
Yifan Hongdad0af82020-02-19 17:19:49 -080033#include "update_engine/common/utils.h"
34#include "update_engine/payload_consumer/delta_performer.h"
35
Howard Chen224aed92020-04-17 11:22:13 +080036using android::base::GetBoolProperty;
Yifan Hongf9cb4492020-04-15 13:00:20 -070037using android::snapshot::ISnapshotManager;
Yifan Hongd976cc52020-02-25 14:51:42 -080038using android::snapshot::SnapshotMergeStats;
Yifan Hongdad0af82020-02-19 17:19:49 -080039using android::snapshot::UpdateState;
40using brillo::MessageLoop;
41
42constexpr char kBootCompletedProp[] = "sys.boot_completed";
Kelvin Zhang8bcb2212023-11-16 10:45:29 -080043constexpr auto&& kMergeDelaySecondsProp = "ro.virtual_ab.merge_delay_seconds";
44constexpr size_t kMaxMergeDelaySeconds = 600;
Yifan Hongdad0af82020-02-19 17:19:49 -080045// Interval to check sys.boot_completed.
46constexpr auto kCheckBootCompletedInterval = base::TimeDelta::FromSeconds(2);
47// Interval to check IBootControl::isSlotMarkedSuccessful
48constexpr auto kCheckSlotMarkedSuccessfulInterval =
49 base::TimeDelta::FromSeconds(2);
50// Interval to call SnapshotManager::ProcessUpdateState
51constexpr auto kWaitForMergeInterval = base::TimeDelta::FromSeconds(2);
52
Yifan Hong5cd63fa2020-03-16 12:31:16 -070053#ifdef __ANDROID_RECOVERY__
54static constexpr bool kIsRecovery = true;
55#else
56static constexpr bool kIsRecovery = false;
57#endif
58
Yifan Hongdad0af82020-02-19 17:19:49 -080059namespace chromeos_update_engine {
60
61CleanupPreviousUpdateAction::CleanupPreviousUpdateAction(
62 PrefsInterface* prefs,
63 BootControlInterface* boot_control,
Yifan Hongf9cb4492020-04-15 13:00:20 -070064 android::snapshot::ISnapshotManager* snapshot,
Yifan Hongdad0af82020-02-19 17:19:49 -080065 CleanupPreviousUpdateActionDelegateInterface* delegate)
66 : prefs_(prefs),
67 boot_control_(boot_control),
68 snapshot_(snapshot),
69 delegate_(delegate),
70 running_(false),
71 cancel_failed_(false),
Yifan Hongd976cc52020-02-25 14:51:42 -080072 last_percentage_(0),
Yifan Hongf9cb4492020-04-15 13:00:20 -070073 merge_stats_(nullptr) {}
Yifan Hongdad0af82020-02-19 17:19:49 -080074
Yifan Hongd1d52a02020-09-25 15:09:07 -070075CleanupPreviousUpdateAction::~CleanupPreviousUpdateAction() {
76 StopActionInternal();
77}
78
Yifan Hongdad0af82020-02-19 17:19:49 -080079void CleanupPreviousUpdateAction::PerformAction() {
Yifan Hongd506dee2020-09-25 15:08:19 -070080 StartActionInternal();
Yifan Hongdad0af82020-02-19 17:19:49 -080081}
82
83void CleanupPreviousUpdateAction::TerminateProcessing() {
Yifan Hongd506dee2020-09-25 15:08:19 -070084 StopActionInternal();
Yifan Hongdad0af82020-02-19 17:19:49 -080085}
86
87void CleanupPreviousUpdateAction::ResumeAction() {
Yifan Hongdad0af82020-02-19 17:19:49 -080088 StartActionInternal();
89}
90
91void CleanupPreviousUpdateAction::SuspendAction() {
Yifan Hongd506dee2020-09-25 15:08:19 -070092 StopActionInternal();
Yifan Hongdad0af82020-02-19 17:19:49 -080093}
94
95void CleanupPreviousUpdateAction::ActionCompleted(ErrorCode error_code) {
Yifan Hongd506dee2020-09-25 15:08:19 -070096 StopActionInternal();
Yifan Hongd976cc52020-02-25 14:51:42 -080097 ReportMergeStats();
Yifan Hong5cd63fa2020-03-16 12:31:16 -070098 metadata_device_ = nullptr;
Yifan Hongdad0af82020-02-19 17:19:49 -080099}
100
101std::string CleanupPreviousUpdateAction::Type() const {
102 return StaticType();
103}
104
105std::string CleanupPreviousUpdateAction::StaticType() {
106 return "CleanupPreviousUpdateAction";
107}
108
Yifan Hongd1d52a02020-09-25 15:09:07 -0700109// This function is called at the beginning of all delayed functions. By
110// resetting |scheduled_task_|, the delayed function acknowledges that the task
111// has already been executed, therefore there's no need to cancel it in the
112// future. This avoids StopActionInternal() from resetting task IDs in an
113// unexpected way because task IDs could be reused.
114void CleanupPreviousUpdateAction::AcknowledgeTaskExecuted() {
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800115 if (scheduled_task_.IsScheduled()) {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700116 LOG(INFO) << "Executing task " << scheduled_task_;
117 }
Yifan Hongd1d52a02020-09-25 15:09:07 -0700118}
119
120// Check that scheduled_task_ is a valid task ID. Otherwise, terminate the
121// action.
122void CleanupPreviousUpdateAction::CheckTaskScheduled(std::string_view name) {
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800123 if (!scheduled_task_.IsScheduled()) {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700124 LOG(ERROR) << "Unable to schedule " << name;
125 processor_->ActionComplete(this, ErrorCode::kError);
126 } else {
127 LOG(INFO) << "CleanupPreviousUpdateAction scheduled task ID "
128 << scheduled_task_ << " for " << name;
129 }
130}
131
Yifan Hongd506dee2020-09-25 15:08:19 -0700132void CleanupPreviousUpdateAction::StopActionInternal() {
133 LOG(INFO) << "Stopping/suspending/completing CleanupPreviousUpdateAction";
134 running_ = false;
Yifan Hongd1d52a02020-09-25 15:09:07 -0700135
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800136 if (scheduled_task_.IsScheduled()) {
137 if (scheduled_task_.Cancel()) {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700138 LOG(INFO) << "CleanupPreviousUpdateAction cancelled pending task ID "
139 << scheduled_task_;
140 } else {
141 LOG(ERROR) << "CleanupPreviousUpdateAction unable to cancel task ID "
142 << scheduled_task_;
143 }
144 }
Yifan Hongd506dee2020-09-25 15:08:19 -0700145}
146
Yifan Hongdad0af82020-02-19 17:19:49 -0800147void CleanupPreviousUpdateAction::StartActionInternal() {
Yifan Hongd506dee2020-09-25 15:08:19 -0700148 CHECK(prefs_);
149 CHECK(boot_control_);
150
151 LOG(INFO) << "Starting/resuming CleanupPreviousUpdateAction";
152 running_ = true;
Yifan Hongdad0af82020-02-19 17:19:49 -0800153 // Do nothing on non-VAB device.
154 if (!boot_control_->GetDynamicPartitionControl()
155 ->GetVirtualAbFeatureFlag()
156 .IsEnabled()) {
157 processor_->ActionComplete(this, ErrorCode::kSuccess);
158 return;
159 }
Yifan Hongf9cb4492020-04-15 13:00:20 -0700160 // SnapshotManager must be available on VAB devices.
161 CHECK(snapshot_ != nullptr);
162 merge_stats_ = snapshot_->GetSnapshotMergeStatsInstance();
163 CHECK(merge_stats_ != nullptr);
Yifan Hongdad0af82020-02-19 17:19:49 -0800164 WaitBootCompletedOrSchedule();
165}
166
167void CleanupPreviousUpdateAction::ScheduleWaitBootCompleted() {
168 TEST_AND_RETURN(running_);
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800169 if (!scheduled_task_.PostTask(
170 FROM_HERE,
171 base::Bind(&CleanupPreviousUpdateAction::WaitBootCompletedOrSchedule,
172 base::Unretained(this)),
173 kCheckBootCompletedInterval)) {
174 CheckTaskScheduled("WaitBootCompleted");
175 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800176}
177
178void CleanupPreviousUpdateAction::WaitBootCompletedOrSchedule() {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700179 AcknowledgeTaskExecuted();
Yifan Hongdad0af82020-02-19 17:19:49 -0800180 TEST_AND_RETURN(running_);
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700181 if (!kIsRecovery &&
182 !android::base::GetBoolProperty(kBootCompletedProp, false)) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800183 // repeat
184 ScheduleWaitBootCompleted();
185 return;
186 }
187
David Anderson0c37f622021-03-11 18:40:25 -0800188 auto boot_time = std::chrono::duration_cast<std::chrono::milliseconds>(
189 android::base::boot_clock::now().time_since_epoch());
190 merge_stats_->set_boot_complete_time_ms(boot_time.count());
191
Yifan Hongdad0af82020-02-19 17:19:49 -0800192 LOG(INFO) << "Boot completed, waiting on markBootSuccessful()";
193 CheckSlotMarkedSuccessfulOrSchedule();
194}
195
196void CleanupPreviousUpdateAction::ScheduleWaitMarkBootSuccessful() {
197 TEST_AND_RETURN(running_);
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800198 if (!scheduled_task_.PostTask(
199 FROM_HERE,
200 base::Bind(
201 &CleanupPreviousUpdateAction::CheckSlotMarkedSuccessfulOrSchedule,
202 base::Unretained(this)),
203 kCheckSlotMarkedSuccessfulInterval)) {
204 CheckTaskScheduled("WaitMarkBootSuccessful");
205 }
206}
207
208void CleanupPreviousUpdateAction::CheckForMergeDelay() {
Kelvin Zhanga4650bd2023-12-20 13:52:31 -0800209 if (!android::snapshot::SnapshotManager::IsSnapshotManagerNeeded()) {
210 StartMerge();
211 return;
212 }
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800213 const auto merge_delay_seconds =
214 std::clamp<int>(android::base::GetIntProperty(kMergeDelaySecondsProp, 0),
215 0,
216 kMaxMergeDelaySeconds);
217 if (merge_delay_seconds != 0) {
218 LOG(INFO) << "Merge is ready to start, but " << kMergeDelaySecondsProp
219 << " is set, delaying merge by " << merge_delay_seconds
220 << " seconds";
221 }
222 if (!scheduled_task_.PostTask(
223 FROM_HERE,
224 [this]() { StartMerge(); },
225 base::TimeDelta::FromSeconds(merge_delay_seconds))) {
226 LOG(ERROR) << "Unable to schedule " << __FUNCTION__;
227 processor_->ActionComplete(this, ErrorCode::kError);
228 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800229}
230
231void CleanupPreviousUpdateAction::CheckSlotMarkedSuccessfulOrSchedule() {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700232 AcknowledgeTaskExecuted();
Yifan Hongdad0af82020-02-19 17:19:49 -0800233 TEST_AND_RETURN(running_);
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700234 if (!kIsRecovery &&
235 !boot_control_->IsSlotMarkedSuccessful(boot_control_->GetCurrentSlot())) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800236 ScheduleWaitMarkBootSuccessful();
Kelvin Zhang65e8b6c2021-04-02 13:19:40 -0400237 return;
Yifan Hongdad0af82020-02-19 17:19:49 -0800238 }
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800239 CheckForMergeDelay();
240}
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700241
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800242void CleanupPreviousUpdateAction::StartMerge() {
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700243 if (metadata_device_ == nullptr) {
244 metadata_device_ = snapshot_->EnsureMetadataMounted();
245 }
246
247 if (metadata_device_ == nullptr) {
248 LOG(ERROR) << "Failed to mount /metadata.";
Yifan Hong4d7c5eb2020-04-03 11:31:50 -0700249 // If metadata is erased but not formatted, it is possible to not mount
250 // it in recovery. It is safe to skip CleanupPreviousUpdateAction.
251 processor_->ActionComplete(
252 this, kIsRecovery ? ErrorCode::kSuccess : ErrorCode::kError);
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700253 return;
254 }
255
Yifan Hong24031712020-03-19 19:25:38 -0700256 if (kIsRecovery) {
257 auto snapshots_created =
258 snapshot_->RecoveryCreateSnapshotDevices(metadata_device_);
259 switch (snapshots_created) {
260 case android::snapshot::CreateResult::CREATED: {
261 // If previous update has not finished merging, snapshots exists and are
262 // created here so that ProcessUpdateState can proceed.
263 LOG(INFO) << "Snapshot devices are created";
264 break;
265 }
266 case android::snapshot::CreateResult::NOT_CREATED: {
267 // If there is no previous update, no snapshot devices are created and
268 // ProcessUpdateState will return immediately. Hence, NOT_CREATED is not
269 // considered an error.
270 LOG(INFO) << "Snapshot devices are not created";
271 break;
272 }
273 case android::snapshot::CreateResult::ERROR:
274 default: {
275 LOG(ERROR)
276 << "Failed to create snapshot devices (CreateResult = "
277 << static_cast<
278 std::underlying_type_t<android::snapshot::CreateResult>>(
279 snapshots_created);
280 processor_->ActionComplete(this, ErrorCode::kError);
281 return;
282 }
283 }
284 }
285
Yifan Hongd976cc52020-02-25 14:51:42 -0800286 if (!merge_stats_->Start()) {
287 // Not an error because CleanupPreviousUpdateAction may be paused and
288 // resumed while kernel continues merging snapshots in the background.
289 LOG(WARNING) << "SnapshotMergeStats::Start failed.";
290 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800291 LOG(INFO) << "Waiting for any previous merge request to complete. "
292 << "This can take up to several minutes.";
293 WaitForMergeOrSchedule();
294}
295
296void CleanupPreviousUpdateAction::ScheduleWaitForMerge() {
297 TEST_AND_RETURN(running_);
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800298 if (!scheduled_task_.PostTask(
299 FROM_HERE,
300 base::Bind(&CleanupPreviousUpdateAction::WaitForMergeOrSchedule,
301 base::Unretained(this)),
302 kWaitForMergeInterval)) {
303 CheckTaskScheduled("WaitForMerge");
304 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800305}
306
307void CleanupPreviousUpdateAction::WaitForMergeOrSchedule() {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700308 AcknowledgeTaskExecuted();
Yifan Hongdad0af82020-02-19 17:19:49 -0800309 TEST_AND_RETURN(running_);
David Anderson28e46892021-05-21 18:54:50 -0700310
David Andersone35b4382022-03-08 23:18:29 -0800311 snapshot_->SetMergeStatsFeatures(merge_stats_);
David Anderson28e46892021-05-21 18:54:50 -0700312
313 // Propagate the merge failure code to the merge stats. If we wait until
314 // after ProcessUpdateState, then a successful merge could overwrite the
315 // state of the previous failure.
316 auto failure_code = snapshot_->ReadMergeFailureCode();
317 if (failure_code != android::snapshot::MergeFailureCode::Ok) {
318 merge_stats_->set_merge_failure_code(failure_code);
319 }
320
Yifan Hongdad0af82020-02-19 17:19:49 -0800321 auto state = snapshot_->ProcessUpdateState(
322 std::bind(&CleanupPreviousUpdateAction::OnMergePercentageUpdate, this),
323 std::bind(&CleanupPreviousUpdateAction::BeforeCancel, this));
David Andersone35b4382022-03-08 23:18:29 -0800324 merge_stats_->set_state(state);
Yifan Hongdad0af82020-02-19 17:19:49 -0800325
Yifan Hongdad0af82020-02-19 17:19:49 -0800326 switch (state) {
327 case UpdateState::None: {
328 LOG(INFO) << "Can't find any snapshot to merge.";
Yifan Hong16b594a2020-03-05 21:02:36 -0800329 ErrorCode error_code = ErrorCode::kSuccess;
330 if (!snapshot_->CancelUpdate()) {
331 error_code = ErrorCode::kError;
332 LOG(INFO) << "Failed to call SnapshotManager::CancelUpdate().";
333 }
334 processor_->ActionComplete(this, error_code);
Yifan Hongdad0af82020-02-19 17:19:49 -0800335 return;
336 }
337
338 case UpdateState::Initiated: {
339 LOG(ERROR) << "Previous update has not been completed, not cleaning up";
340 processor_->ActionComplete(this, ErrorCode::kSuccess);
341 return;
342 }
343
344 case UpdateState::Unverified: {
345 InitiateMergeAndWait();
346 return;
347 }
348
349 case UpdateState::Merging: {
350 ScheduleWaitForMerge();
351 return;
352 }
353
354 case UpdateState::MergeNeedsReboot: {
355 LOG(ERROR) << "Need reboot to finish merging.";
356 processor_->ActionComplete(this, ErrorCode::kError);
357 return;
358 }
359
360 case UpdateState::MergeCompleted: {
361 LOG(INFO) << "Merge finished with state MergeCompleted.";
Daniel Zheng9e6bfc12022-09-19 22:34:52 +0000362 boot_control_->MarkSlotUnbootable(1 - boot_control_->GetCurrentSlot());
Yifan Hongdad0af82020-02-19 17:19:49 -0800363 processor_->ActionComplete(this, ErrorCode::kSuccess);
364 return;
365 }
366
367 case UpdateState::MergeFailed: {
368 LOG(ERROR) << "Merge failed. Device may be corrupted.";
David Anderson6ac3d472021-04-14 19:40:24 -0700369 merge_stats_->set_merge_failure_code(snapshot_->ReadMergeFailureCode());
Yifan Hongdad0af82020-02-19 17:19:49 -0800370 processor_->ActionComplete(this, ErrorCode::kDeviceCorrupted);
371 return;
372 }
373
374 case UpdateState::Cancelled: {
375 // DeltaPerformer::ResetUpdateProgress failed, hence snapshots are
376 // not deleted to avoid inconsistency.
377 // Nothing can be done here; just try next time.
378 ErrorCode error_code =
379 cancel_failed_ ? ErrorCode::kError : ErrorCode::kSuccess;
380 processor_->ActionComplete(this, error_code);
381 return;
382 }
383
384 default: {
385 // Protobuf has some reserved enum values, so a default case is needed.
386 LOG(FATAL) << "SnapshotManager::ProcessUpdateState returns "
387 << static_cast<int32_t>(state);
388 }
389 }
390}
391
392bool CleanupPreviousUpdateAction::OnMergePercentageUpdate() {
393 double percentage = 0.0;
394 snapshot_->GetUpdateState(&percentage);
395 if (delegate_) {
396 // libsnapshot uses [0, 100] percentage but update_engine uses [0, 1].
397 delegate_->OnCleanupProgressUpdate(percentage / 100);
398 }
399
400 // Log if percentage increments by at least 1.
401 if (last_percentage_ < static_cast<unsigned int>(percentage)) {
402 last_percentage_ = percentage;
403 LOG(INFO) << "Waiting for merge to complete: " << last_percentage_ << "%.";
404 }
405
406 // Do not continue to wait for merge. Instead, let ProcessUpdateState
407 // return Merging directly so that we can ScheduleWaitForMerge() in
408 // MessageLoop.
409 return false;
410}
411
412bool CleanupPreviousUpdateAction::BeforeCancel() {
Daniel Zhengf9784802023-06-08 08:39:48 -0700413 if (DeltaPerformer::ResetUpdateProgress(
414 prefs_,
415 false /* quick */,
416 false /* skip dynamic partitions metadata*/)) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800417 return true;
418 }
419
420 // ResetUpdateProgress might not work on stub prefs. Do additional checks.
421 LOG(WARNING) << "ProcessUpdateState returns Cancelled but cleanup failed.";
422
423 std::string val;
424 ignore_result(prefs_->GetString(kPrefsDynamicPartitionMetadataUpdated, &val));
425 if (val.empty()) {
426 LOG(INFO) << kPrefsDynamicPartitionMetadataUpdated
427 << " is empty, assuming successful cleanup";
428 return true;
429 }
430 LOG(WARNING)
431 << kPrefsDynamicPartitionMetadataUpdated << " is " << val
432 << ", not deleting snapshots even though UpdateState is Cancelled.";
433 cancel_failed_ = true;
434 return false;
435}
436
437void CleanupPreviousUpdateAction::InitiateMergeAndWait() {
438 TEST_AND_RETURN(running_);
439 LOG(INFO) << "Attempting to initiate merge.";
Howard Chen224aed92020-04-17 11:22:13 +0800440 // suspend the VAB merge when running a DSU
441 if (GetBoolProperty("ro.gsid.image_running", false)) {
442 LOG(WARNING) << "Suspend the VAB merge when running a DSU.";
443 processor_->ActionComplete(this, ErrorCode::kError);
444 return;
445 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800446
David Anderson8bda8212021-03-03 18:33:38 -0800447 snapshot_->UpdateCowStats(merge_stats_);
448
David Anderson0c37f622021-03-11 18:40:25 -0800449 auto merge_start_time = std::chrono::duration_cast<std::chrono::milliseconds>(
450 android::base::boot_clock::now().time_since_epoch());
451 merge_stats_->set_boot_complete_to_merge_start_time_ms(
452 merge_start_time.count() - merge_stats_->boot_complete_time_ms());
453
David Anderson46574072021-06-29 19:55:49 -0700454 auto source_build_fingerprint = snapshot_->ReadSourceBuildFingerprint();
455 merge_stats_->set_source_build_fingerprint(source_build_fingerprint);
456
457 if (!merge_stats_->WriteState()) {
458 LOG(ERROR) << "Failed to write merge stats; record may be unreliable if "
459 "merge is interrupted.";
460 }
461
David Anderson8bda8212021-03-03 18:33:38 -0800462 if (snapshot_->InitiateMerge()) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800463 WaitForMergeOrSchedule();
464 return;
465 }
466
467 LOG(WARNING) << "InitiateMerge failed.";
468 auto state = snapshot_->GetUpdateState();
David Andersone35b4382022-03-08 23:18:29 -0800469 merge_stats_->set_state(state);
Yifan Hongdad0af82020-02-19 17:19:49 -0800470 if (state == UpdateState::Unverified) {
471 // We are stuck at unverified state. This can happen if the update has
472 // been applied, but it has not even been attempted yet (in libsnapshot,
473 // rollback indicator does not exist); for example, if update_engine
474 // restarts before the device reboots, then this state may be reached.
475 // Nothing should be done here.
476 LOG(WARNING) << "InitiateMerge leaves the device at "
477 << "UpdateState::Unverified. (Did update_engine "
478 << "restarted?)";
479 processor_->ActionComplete(this, ErrorCode::kSuccess);
480 return;
481 }
482
483 // State does seems to be advanced.
484 // It is possibly racy. For example, on a userdebug build, the user may
485 // manually initiate a merge with snapshotctl between last time
486 // update_engine checks UpdateState. Hence, just call
487 // WaitForMergeOrSchedule one more time.
488 LOG(WARNING) << "IniitateMerge failed but GetUpdateState returned "
489 << android::snapshot::UpdateState_Name(state)
490 << ", try to wait for merge again.";
491 WaitForMergeOrSchedule();
492 return;
493}
494
Yifan Hongd976cc52020-02-25 14:51:42 -0800495void CleanupPreviousUpdateAction::ReportMergeStats() {
496 auto result = merge_stats_->Finish();
497 if (result == nullptr) {
498 LOG(WARNING) << "Not reporting merge stats because "
499 "SnapshotMergeStats::Finish failed.";
500 return;
501 }
502
503#ifdef __ANDROID_RECOVERY__
504 LOG(INFO) << "Skip reporting merge stats in recovery.";
Nikita Putikhine788f952024-03-11 19:21:24 +0100505#elif defined(UE_DISABLE_STATS)
506 LOG(INFO) << "Skip reporting merge stats because metrics are disabled.";
Yifan Hongd976cc52020-02-25 14:51:42 -0800507#else
508 const auto& report = result->report();
509
510 if (report.state() == UpdateState::None ||
511 report.state() == UpdateState::Initiated ||
512 report.state() == UpdateState::Unverified) {
513 LOG(INFO) << "Not reporting merge stats because state is "
514 << android::snapshot::UpdateState_Name(report.state());
515 return;
516 }
517
518 auto passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
519 result->merge_time());
Alessio Balsini4ed05122020-05-26 22:17:03 +0100520
521 bool vab_retrofit = boot_control_->GetDynamicPartitionControl()
522 ->GetVirtualAbFeatureFlag()
523 .IsRetrofit();
Yifan Hongbab11c52021-02-03 15:05:05 -0800524 bool vab_compression_enabled = boot_control_->GetDynamicPartitionControl()
525 ->GetVirtualAbCompressionFeatureFlag()
526 .IsEnabled();
527 // The snapshot has been merged, so we can no longer call
528 // DynamicPartitionControlInterface::UpdateUsesSnapshotCompression.
529 // However, we have saved the flag in the snapshot report.
530 bool vab_compression_used = report.compression_enabled();
David Andersone35b4382022-03-08 23:18:29 -0800531 bool userspace_snapshots_enabled =
532 boot_control_->GetDynamicPartitionControl()
533 ->GetVirtualAbUserspaceSnapshotsFeatureFlag()
534 .IsEnabled();
535 bool userspace_snapshots_used = report.userspace_snapshots_used();
536 bool xor_compression_enabled = boot_control_->GetDynamicPartitionControl()
537 ->GetVirtualAbCompressionXorFeatureFlag()
538 .IsEnabled();
539 bool xor_compression_used = report.xor_compression_used();
540 bool iouring_used = report.iouring_used();
Alessio Balsini4ed05122020-05-26 22:17:03 +0100541
David Andersonbb682252021-06-29 19:59:22 -0700542 auto target_build_fingerprint =
543 android::base::GetProperty("ro.build.fingerprint", "");
544
Yifan Hongd976cc52020-02-25 14:51:42 -0800545 LOG(INFO) << "Reporting merge stats: "
546 << android::snapshot::UpdateState_Name(report.state()) << " in "
547 << passed_ms.count() << "ms (resumed " << report.resume_count()
Alessio Balsini4ed05122020-05-26 22:17:03 +0100548 << " times), using " << report.cow_file_size()
549 << " bytes of COW image.";
Vova Sharaienkod62c81b2022-09-21 05:32:43 +0000550 statsd::stats_write(statsd::SNAPSHOT_MERGE_REPORTED,
551 static_cast<int32_t>(report.state()),
552 static_cast<int64_t>(passed_ms.count()),
553 static_cast<int32_t>(report.resume_count()),
554 vab_retrofit,
555 static_cast<int64_t>(report.cow_file_size()),
556 vab_compression_enabled,
557 vab_compression_used,
558 report.total_cow_size_bytes(),
559 report.estimated_cow_size_bytes(),
560 report.boot_complete_time_ms(),
561 report.boot_complete_to_merge_start_time_ms(),
562 static_cast<int32_t>(report.merge_failure_code()),
563 report.source_build_fingerprint().c_str(),
564 target_build_fingerprint.c_str(),
565 userspace_snapshots_enabled,
566 userspace_snapshots_used,
567 xor_compression_enabled,
568 xor_compression_used,
569 iouring_used);
Yifan Hongd976cc52020-02-25 14:51:42 -0800570#endif
571}
572
Yifan Hongdad0af82020-02-19 17:19:49 -0800573} // namespace chromeos_update_engine