blob: b070ecddcc6dbc8062a0e37b8e8a8fd58f5547ba [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>
Yifan Hongd976cc52020-02-25 14:51:42 -080019#include <chrono> // NOLINT(build/c++11) -- for merge times
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>
27
Yifan Hongd976cc52020-02-25 14:51:42 -080028#ifndef __ANDROID_RECOVERY__
Vova Sharaienkod62c81b2022-09-21 05:32:43 +000029#include <statslog_ue.h>
Yifan Hongd976cc52020-02-25 14:51:42 -080030#endif
31
Yifan Hongdad0af82020-02-19 17:19:49 -080032#include "update_engine/common/utils.h"
33#include "update_engine/payload_consumer/delta_performer.h"
34
Howard Chen224aed92020-04-17 11:22:13 +080035using android::base::GetBoolProperty;
Yifan Hongf9cb4492020-04-15 13:00:20 -070036using android::snapshot::ISnapshotManager;
Yifan Hongd976cc52020-02-25 14:51:42 -080037using android::snapshot::SnapshotMergeStats;
Yifan Hongdad0af82020-02-19 17:19:49 -080038using android::snapshot::UpdateState;
39using brillo::MessageLoop;
40
41constexpr char kBootCompletedProp[] = "sys.boot_completed";
Kelvin Zhang8bcb2212023-11-16 10:45:29 -080042constexpr auto&& kMergeDelaySecondsProp = "ro.virtual_ab.merge_delay_seconds";
43constexpr size_t kMaxMergeDelaySeconds = 600;
Yifan Hongdad0af82020-02-19 17:19:49 -080044// Interval to check sys.boot_completed.
45constexpr auto kCheckBootCompletedInterval = base::TimeDelta::FromSeconds(2);
46// Interval to check IBootControl::isSlotMarkedSuccessful
47constexpr auto kCheckSlotMarkedSuccessfulInterval =
48 base::TimeDelta::FromSeconds(2);
49// Interval to call SnapshotManager::ProcessUpdateState
50constexpr auto kWaitForMergeInterval = base::TimeDelta::FromSeconds(2);
51
Yifan Hong5cd63fa2020-03-16 12:31:16 -070052#ifdef __ANDROID_RECOVERY__
53static constexpr bool kIsRecovery = true;
54#else
55static constexpr bool kIsRecovery = false;
56#endif
57
Yifan Hongdad0af82020-02-19 17:19:49 -080058namespace chromeos_update_engine {
59
60CleanupPreviousUpdateAction::CleanupPreviousUpdateAction(
61 PrefsInterface* prefs,
62 BootControlInterface* boot_control,
Yifan Hongf9cb4492020-04-15 13:00:20 -070063 android::snapshot::ISnapshotManager* snapshot,
Yifan Hongdad0af82020-02-19 17:19:49 -080064 CleanupPreviousUpdateActionDelegateInterface* delegate)
65 : prefs_(prefs),
66 boot_control_(boot_control),
67 snapshot_(snapshot),
68 delegate_(delegate),
69 running_(false),
70 cancel_failed_(false),
Yifan Hongd976cc52020-02-25 14:51:42 -080071 last_percentage_(0),
Yifan Hongf9cb4492020-04-15 13:00:20 -070072 merge_stats_(nullptr) {}
Yifan Hongdad0af82020-02-19 17:19:49 -080073
Yifan Hongd1d52a02020-09-25 15:09:07 -070074CleanupPreviousUpdateAction::~CleanupPreviousUpdateAction() {
75 StopActionInternal();
76}
77
Yifan Hongdad0af82020-02-19 17:19:49 -080078void CleanupPreviousUpdateAction::PerformAction() {
Yifan Hongd506dee2020-09-25 15:08:19 -070079 StartActionInternal();
Yifan Hongdad0af82020-02-19 17:19:49 -080080}
81
82void CleanupPreviousUpdateAction::TerminateProcessing() {
Yifan Hongd506dee2020-09-25 15:08:19 -070083 StopActionInternal();
Yifan Hongdad0af82020-02-19 17:19:49 -080084}
85
86void CleanupPreviousUpdateAction::ResumeAction() {
Yifan Hongdad0af82020-02-19 17:19:49 -080087 StartActionInternal();
88}
89
90void CleanupPreviousUpdateAction::SuspendAction() {
Yifan Hongd506dee2020-09-25 15:08:19 -070091 StopActionInternal();
Yifan Hongdad0af82020-02-19 17:19:49 -080092}
93
94void CleanupPreviousUpdateAction::ActionCompleted(ErrorCode error_code) {
Yifan Hongd506dee2020-09-25 15:08:19 -070095 StopActionInternal();
Yifan Hongd976cc52020-02-25 14:51:42 -080096 ReportMergeStats();
Yifan Hong5cd63fa2020-03-16 12:31:16 -070097 metadata_device_ = nullptr;
Yifan Hongdad0af82020-02-19 17:19:49 -080098}
99
100std::string CleanupPreviousUpdateAction::Type() const {
101 return StaticType();
102}
103
104std::string CleanupPreviousUpdateAction::StaticType() {
105 return "CleanupPreviousUpdateAction";
106}
107
Yifan Hongd1d52a02020-09-25 15:09:07 -0700108// This function is called at the beginning of all delayed functions. By
109// resetting |scheduled_task_|, the delayed function acknowledges that the task
110// has already been executed, therefore there's no need to cancel it in the
111// future. This avoids StopActionInternal() from resetting task IDs in an
112// unexpected way because task IDs could be reused.
113void CleanupPreviousUpdateAction::AcknowledgeTaskExecuted() {
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800114 if (scheduled_task_.IsScheduled()) {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700115 LOG(INFO) << "Executing task " << scheduled_task_;
116 }
Yifan Hongd1d52a02020-09-25 15:09:07 -0700117}
118
119// Check that scheduled_task_ is a valid task ID. Otherwise, terminate the
120// action.
121void CleanupPreviousUpdateAction::CheckTaskScheduled(std::string_view name) {
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800122 if (!scheduled_task_.IsScheduled()) {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700123 LOG(ERROR) << "Unable to schedule " << name;
124 processor_->ActionComplete(this, ErrorCode::kError);
125 } else {
126 LOG(INFO) << "CleanupPreviousUpdateAction scheduled task ID "
127 << scheduled_task_ << " for " << name;
128 }
129}
130
Yifan Hongd506dee2020-09-25 15:08:19 -0700131void CleanupPreviousUpdateAction::StopActionInternal() {
132 LOG(INFO) << "Stopping/suspending/completing CleanupPreviousUpdateAction";
133 running_ = false;
Yifan Hongd1d52a02020-09-25 15:09:07 -0700134
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800135 if (scheduled_task_.IsScheduled()) {
136 if (scheduled_task_.Cancel()) {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700137 LOG(INFO) << "CleanupPreviousUpdateAction cancelled pending task ID "
138 << scheduled_task_;
139 } else {
140 LOG(ERROR) << "CleanupPreviousUpdateAction unable to cancel task ID "
141 << scheduled_task_;
142 }
143 }
Yifan Hongd506dee2020-09-25 15:08:19 -0700144}
145
Yifan Hongdad0af82020-02-19 17:19:49 -0800146void CleanupPreviousUpdateAction::StartActionInternal() {
Yifan Hongd506dee2020-09-25 15:08:19 -0700147 CHECK(prefs_);
148 CHECK(boot_control_);
149
150 LOG(INFO) << "Starting/resuming CleanupPreviousUpdateAction";
151 running_ = true;
Yifan Hongdad0af82020-02-19 17:19:49 -0800152 // Do nothing on non-VAB device.
153 if (!boot_control_->GetDynamicPartitionControl()
154 ->GetVirtualAbFeatureFlag()
155 .IsEnabled()) {
156 processor_->ActionComplete(this, ErrorCode::kSuccess);
157 return;
158 }
Yifan Hongf9cb4492020-04-15 13:00:20 -0700159 // SnapshotManager must be available on VAB devices.
160 CHECK(snapshot_ != nullptr);
161 merge_stats_ = snapshot_->GetSnapshotMergeStatsInstance();
162 CHECK(merge_stats_ != nullptr);
Yifan Hongdad0af82020-02-19 17:19:49 -0800163 WaitBootCompletedOrSchedule();
164}
165
166void CleanupPreviousUpdateAction::ScheduleWaitBootCompleted() {
167 TEST_AND_RETURN(running_);
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800168 if (!scheduled_task_.PostTask(
169 FROM_HERE,
170 base::Bind(&CleanupPreviousUpdateAction::WaitBootCompletedOrSchedule,
171 base::Unretained(this)),
172 kCheckBootCompletedInterval)) {
173 CheckTaskScheduled("WaitBootCompleted");
174 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800175}
176
177void CleanupPreviousUpdateAction::WaitBootCompletedOrSchedule() {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700178 AcknowledgeTaskExecuted();
Yifan Hongdad0af82020-02-19 17:19:49 -0800179 TEST_AND_RETURN(running_);
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700180 if (!kIsRecovery &&
181 !android::base::GetBoolProperty(kBootCompletedProp, false)) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800182 // repeat
183 ScheduleWaitBootCompleted();
184 return;
185 }
186
David Anderson0c37f622021-03-11 18:40:25 -0800187 auto boot_time = std::chrono::duration_cast<std::chrono::milliseconds>(
188 android::base::boot_clock::now().time_since_epoch());
189 merge_stats_->set_boot_complete_time_ms(boot_time.count());
190
Yifan Hongdad0af82020-02-19 17:19:49 -0800191 LOG(INFO) << "Boot completed, waiting on markBootSuccessful()";
192 CheckSlotMarkedSuccessfulOrSchedule();
193}
194
195void CleanupPreviousUpdateAction::ScheduleWaitMarkBootSuccessful() {
196 TEST_AND_RETURN(running_);
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800197 if (!scheduled_task_.PostTask(
198 FROM_HERE,
199 base::Bind(
200 &CleanupPreviousUpdateAction::CheckSlotMarkedSuccessfulOrSchedule,
201 base::Unretained(this)),
202 kCheckSlotMarkedSuccessfulInterval)) {
203 CheckTaskScheduled("WaitMarkBootSuccessful");
204 }
205}
206
207void CleanupPreviousUpdateAction::CheckForMergeDelay() {
208 const auto merge_delay_seconds =
209 std::clamp<int>(android::base::GetIntProperty(kMergeDelaySecondsProp, 0),
210 0,
211 kMaxMergeDelaySeconds);
212 if (merge_delay_seconds != 0) {
213 LOG(INFO) << "Merge is ready to start, but " << kMergeDelaySecondsProp
214 << " is set, delaying merge by " << merge_delay_seconds
215 << " seconds";
216 }
217 if (!scheduled_task_.PostTask(
218 FROM_HERE,
219 [this]() { StartMerge(); },
220 base::TimeDelta::FromSeconds(merge_delay_seconds))) {
221 LOG(ERROR) << "Unable to schedule " << __FUNCTION__;
222 processor_->ActionComplete(this, ErrorCode::kError);
223 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800224}
225
226void CleanupPreviousUpdateAction::CheckSlotMarkedSuccessfulOrSchedule() {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700227 AcknowledgeTaskExecuted();
Yifan Hongdad0af82020-02-19 17:19:49 -0800228 TEST_AND_RETURN(running_);
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700229 if (!kIsRecovery &&
230 !boot_control_->IsSlotMarkedSuccessful(boot_control_->GetCurrentSlot())) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800231 ScheduleWaitMarkBootSuccessful();
Kelvin Zhang65e8b6c2021-04-02 13:19:40 -0400232 return;
Yifan Hongdad0af82020-02-19 17:19:49 -0800233 }
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800234 CheckForMergeDelay();
235}
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700236
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800237void CleanupPreviousUpdateAction::StartMerge() {
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700238 if (metadata_device_ == nullptr) {
239 metadata_device_ = snapshot_->EnsureMetadataMounted();
240 }
241
242 if (metadata_device_ == nullptr) {
243 LOG(ERROR) << "Failed to mount /metadata.";
Yifan Hong4d7c5eb2020-04-03 11:31:50 -0700244 // If metadata is erased but not formatted, it is possible to not mount
245 // it in recovery. It is safe to skip CleanupPreviousUpdateAction.
246 processor_->ActionComplete(
247 this, kIsRecovery ? ErrorCode::kSuccess : ErrorCode::kError);
Yifan Hong5cd63fa2020-03-16 12:31:16 -0700248 return;
249 }
250
Yifan Hong24031712020-03-19 19:25:38 -0700251 if (kIsRecovery) {
252 auto snapshots_created =
253 snapshot_->RecoveryCreateSnapshotDevices(metadata_device_);
254 switch (snapshots_created) {
255 case android::snapshot::CreateResult::CREATED: {
256 // If previous update has not finished merging, snapshots exists and are
257 // created here so that ProcessUpdateState can proceed.
258 LOG(INFO) << "Snapshot devices are created";
259 break;
260 }
261 case android::snapshot::CreateResult::NOT_CREATED: {
262 // If there is no previous update, no snapshot devices are created and
263 // ProcessUpdateState will return immediately. Hence, NOT_CREATED is not
264 // considered an error.
265 LOG(INFO) << "Snapshot devices are not created";
266 break;
267 }
268 case android::snapshot::CreateResult::ERROR:
269 default: {
270 LOG(ERROR)
271 << "Failed to create snapshot devices (CreateResult = "
272 << static_cast<
273 std::underlying_type_t<android::snapshot::CreateResult>>(
274 snapshots_created);
275 processor_->ActionComplete(this, ErrorCode::kError);
276 return;
277 }
278 }
279 }
280
Yifan Hongd976cc52020-02-25 14:51:42 -0800281 if (!merge_stats_->Start()) {
282 // Not an error because CleanupPreviousUpdateAction may be paused and
283 // resumed while kernel continues merging snapshots in the background.
284 LOG(WARNING) << "SnapshotMergeStats::Start failed.";
285 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800286 LOG(INFO) << "Waiting for any previous merge request to complete. "
287 << "This can take up to several minutes.";
288 WaitForMergeOrSchedule();
289}
290
291void CleanupPreviousUpdateAction::ScheduleWaitForMerge() {
292 TEST_AND_RETURN(running_);
Kelvin Zhang8bcb2212023-11-16 10:45:29 -0800293 if (!scheduled_task_.PostTask(
294 FROM_HERE,
295 base::Bind(&CleanupPreviousUpdateAction::WaitForMergeOrSchedule,
296 base::Unretained(this)),
297 kWaitForMergeInterval)) {
298 CheckTaskScheduled("WaitForMerge");
299 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800300}
301
302void CleanupPreviousUpdateAction::WaitForMergeOrSchedule() {
Yifan Hongd1d52a02020-09-25 15:09:07 -0700303 AcknowledgeTaskExecuted();
Yifan Hongdad0af82020-02-19 17:19:49 -0800304 TEST_AND_RETURN(running_);
David Anderson28e46892021-05-21 18:54:50 -0700305
David Andersone35b4382022-03-08 23:18:29 -0800306 snapshot_->SetMergeStatsFeatures(merge_stats_);
David Anderson28e46892021-05-21 18:54:50 -0700307
308 // Propagate the merge failure code to the merge stats. If we wait until
309 // after ProcessUpdateState, then a successful merge could overwrite the
310 // state of the previous failure.
311 auto failure_code = snapshot_->ReadMergeFailureCode();
312 if (failure_code != android::snapshot::MergeFailureCode::Ok) {
313 merge_stats_->set_merge_failure_code(failure_code);
314 }
315
Yifan Hongdad0af82020-02-19 17:19:49 -0800316 auto state = snapshot_->ProcessUpdateState(
317 std::bind(&CleanupPreviousUpdateAction::OnMergePercentageUpdate, this),
318 std::bind(&CleanupPreviousUpdateAction::BeforeCancel, this));
David Andersone35b4382022-03-08 23:18:29 -0800319 merge_stats_->set_state(state);
Yifan Hongdad0af82020-02-19 17:19:49 -0800320
Yifan Hongdad0af82020-02-19 17:19:49 -0800321 switch (state) {
322 case UpdateState::None: {
323 LOG(INFO) << "Can't find any snapshot to merge.";
Yifan Hong16b594a2020-03-05 21:02:36 -0800324 ErrorCode error_code = ErrorCode::kSuccess;
325 if (!snapshot_->CancelUpdate()) {
326 error_code = ErrorCode::kError;
327 LOG(INFO) << "Failed to call SnapshotManager::CancelUpdate().";
328 }
329 processor_->ActionComplete(this, error_code);
Yifan Hongdad0af82020-02-19 17:19:49 -0800330 return;
331 }
332
333 case UpdateState::Initiated: {
334 LOG(ERROR) << "Previous update has not been completed, not cleaning up";
335 processor_->ActionComplete(this, ErrorCode::kSuccess);
336 return;
337 }
338
339 case UpdateState::Unverified: {
340 InitiateMergeAndWait();
341 return;
342 }
343
344 case UpdateState::Merging: {
345 ScheduleWaitForMerge();
346 return;
347 }
348
349 case UpdateState::MergeNeedsReboot: {
350 LOG(ERROR) << "Need reboot to finish merging.";
351 processor_->ActionComplete(this, ErrorCode::kError);
352 return;
353 }
354
355 case UpdateState::MergeCompleted: {
356 LOG(INFO) << "Merge finished with state MergeCompleted.";
Daniel Zheng9e6bfc12022-09-19 22:34:52 +0000357 boot_control_->MarkSlotUnbootable(1 - boot_control_->GetCurrentSlot());
Yifan Hongdad0af82020-02-19 17:19:49 -0800358 processor_->ActionComplete(this, ErrorCode::kSuccess);
359 return;
360 }
361
362 case UpdateState::MergeFailed: {
363 LOG(ERROR) << "Merge failed. Device may be corrupted.";
David Anderson6ac3d472021-04-14 19:40:24 -0700364 merge_stats_->set_merge_failure_code(snapshot_->ReadMergeFailureCode());
Yifan Hongdad0af82020-02-19 17:19:49 -0800365 processor_->ActionComplete(this, ErrorCode::kDeviceCorrupted);
366 return;
367 }
368
369 case UpdateState::Cancelled: {
370 // DeltaPerformer::ResetUpdateProgress failed, hence snapshots are
371 // not deleted to avoid inconsistency.
372 // Nothing can be done here; just try next time.
373 ErrorCode error_code =
374 cancel_failed_ ? ErrorCode::kError : ErrorCode::kSuccess;
375 processor_->ActionComplete(this, error_code);
376 return;
377 }
378
379 default: {
380 // Protobuf has some reserved enum values, so a default case is needed.
381 LOG(FATAL) << "SnapshotManager::ProcessUpdateState returns "
382 << static_cast<int32_t>(state);
383 }
384 }
385}
386
387bool CleanupPreviousUpdateAction::OnMergePercentageUpdate() {
388 double percentage = 0.0;
389 snapshot_->GetUpdateState(&percentage);
390 if (delegate_) {
391 // libsnapshot uses [0, 100] percentage but update_engine uses [0, 1].
392 delegate_->OnCleanupProgressUpdate(percentage / 100);
393 }
394
395 // Log if percentage increments by at least 1.
396 if (last_percentage_ < static_cast<unsigned int>(percentage)) {
397 last_percentage_ = percentage;
398 LOG(INFO) << "Waiting for merge to complete: " << last_percentage_ << "%.";
399 }
400
401 // Do not continue to wait for merge. Instead, let ProcessUpdateState
402 // return Merging directly so that we can ScheduleWaitForMerge() in
403 // MessageLoop.
404 return false;
405}
406
407bool CleanupPreviousUpdateAction::BeforeCancel() {
Daniel Zhengf9784802023-06-08 08:39:48 -0700408 if (DeltaPerformer::ResetUpdateProgress(
409 prefs_,
410 false /* quick */,
411 false /* skip dynamic partitions metadata*/)) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800412 return true;
413 }
414
415 // ResetUpdateProgress might not work on stub prefs. Do additional checks.
416 LOG(WARNING) << "ProcessUpdateState returns Cancelled but cleanup failed.";
417
418 std::string val;
419 ignore_result(prefs_->GetString(kPrefsDynamicPartitionMetadataUpdated, &val));
420 if (val.empty()) {
421 LOG(INFO) << kPrefsDynamicPartitionMetadataUpdated
422 << " is empty, assuming successful cleanup";
423 return true;
424 }
425 LOG(WARNING)
426 << kPrefsDynamicPartitionMetadataUpdated << " is " << val
427 << ", not deleting snapshots even though UpdateState is Cancelled.";
428 cancel_failed_ = true;
429 return false;
430}
431
432void CleanupPreviousUpdateAction::InitiateMergeAndWait() {
433 TEST_AND_RETURN(running_);
434 LOG(INFO) << "Attempting to initiate merge.";
Howard Chen224aed92020-04-17 11:22:13 +0800435 // suspend the VAB merge when running a DSU
436 if (GetBoolProperty("ro.gsid.image_running", false)) {
437 LOG(WARNING) << "Suspend the VAB merge when running a DSU.";
438 processor_->ActionComplete(this, ErrorCode::kError);
439 return;
440 }
Yifan Hongdad0af82020-02-19 17:19:49 -0800441
David Anderson8bda8212021-03-03 18:33:38 -0800442 snapshot_->UpdateCowStats(merge_stats_);
443
David Anderson0c37f622021-03-11 18:40:25 -0800444 auto merge_start_time = std::chrono::duration_cast<std::chrono::milliseconds>(
445 android::base::boot_clock::now().time_since_epoch());
446 merge_stats_->set_boot_complete_to_merge_start_time_ms(
447 merge_start_time.count() - merge_stats_->boot_complete_time_ms());
448
David Anderson46574072021-06-29 19:55:49 -0700449 auto source_build_fingerprint = snapshot_->ReadSourceBuildFingerprint();
450 merge_stats_->set_source_build_fingerprint(source_build_fingerprint);
451
452 if (!merge_stats_->WriteState()) {
453 LOG(ERROR) << "Failed to write merge stats; record may be unreliable if "
454 "merge is interrupted.";
455 }
456
David Anderson8bda8212021-03-03 18:33:38 -0800457 if (snapshot_->InitiateMerge()) {
Yifan Hongdad0af82020-02-19 17:19:49 -0800458 WaitForMergeOrSchedule();
459 return;
460 }
461
462 LOG(WARNING) << "InitiateMerge failed.";
463 auto state = snapshot_->GetUpdateState();
David Andersone35b4382022-03-08 23:18:29 -0800464 merge_stats_->set_state(state);
Yifan Hongdad0af82020-02-19 17:19:49 -0800465 if (state == UpdateState::Unverified) {
466 // We are stuck at unverified state. This can happen if the update has
467 // been applied, but it has not even been attempted yet (in libsnapshot,
468 // rollback indicator does not exist); for example, if update_engine
469 // restarts before the device reboots, then this state may be reached.
470 // Nothing should be done here.
471 LOG(WARNING) << "InitiateMerge leaves the device at "
472 << "UpdateState::Unverified. (Did update_engine "
473 << "restarted?)";
474 processor_->ActionComplete(this, ErrorCode::kSuccess);
475 return;
476 }
477
478 // State does seems to be advanced.
479 // It is possibly racy. For example, on a userdebug build, the user may
480 // manually initiate a merge with snapshotctl between last time
481 // update_engine checks UpdateState. Hence, just call
482 // WaitForMergeOrSchedule one more time.
483 LOG(WARNING) << "IniitateMerge failed but GetUpdateState returned "
484 << android::snapshot::UpdateState_Name(state)
485 << ", try to wait for merge again.";
486 WaitForMergeOrSchedule();
487 return;
488}
489
Yifan Hongd976cc52020-02-25 14:51:42 -0800490void CleanupPreviousUpdateAction::ReportMergeStats() {
491 auto result = merge_stats_->Finish();
492 if (result == nullptr) {
493 LOG(WARNING) << "Not reporting merge stats because "
494 "SnapshotMergeStats::Finish failed.";
495 return;
496 }
497
498#ifdef __ANDROID_RECOVERY__
499 LOG(INFO) << "Skip reporting merge stats in recovery.";
500#else
501 const auto& report = result->report();
502
503 if (report.state() == UpdateState::None ||
504 report.state() == UpdateState::Initiated ||
505 report.state() == UpdateState::Unverified) {
506 LOG(INFO) << "Not reporting merge stats because state is "
507 << android::snapshot::UpdateState_Name(report.state());
508 return;
509 }
510
511 auto passed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
512 result->merge_time());
Alessio Balsini4ed05122020-05-26 22:17:03 +0100513
514 bool vab_retrofit = boot_control_->GetDynamicPartitionControl()
515 ->GetVirtualAbFeatureFlag()
516 .IsRetrofit();
Yifan Hongbab11c52021-02-03 15:05:05 -0800517 bool vab_compression_enabled = boot_control_->GetDynamicPartitionControl()
518 ->GetVirtualAbCompressionFeatureFlag()
519 .IsEnabled();
520 // The snapshot has been merged, so we can no longer call
521 // DynamicPartitionControlInterface::UpdateUsesSnapshotCompression.
522 // However, we have saved the flag in the snapshot report.
523 bool vab_compression_used = report.compression_enabled();
David Andersone35b4382022-03-08 23:18:29 -0800524 bool userspace_snapshots_enabled =
525 boot_control_->GetDynamicPartitionControl()
526 ->GetVirtualAbUserspaceSnapshotsFeatureFlag()
527 .IsEnabled();
528 bool userspace_snapshots_used = report.userspace_snapshots_used();
529 bool xor_compression_enabled = boot_control_->GetDynamicPartitionControl()
530 ->GetVirtualAbCompressionXorFeatureFlag()
531 .IsEnabled();
532 bool xor_compression_used = report.xor_compression_used();
533 bool iouring_used = report.iouring_used();
Alessio Balsini4ed05122020-05-26 22:17:03 +0100534
David Andersonbb682252021-06-29 19:59:22 -0700535 auto target_build_fingerprint =
536 android::base::GetProperty("ro.build.fingerprint", "");
537
Yifan Hongd976cc52020-02-25 14:51:42 -0800538 LOG(INFO) << "Reporting merge stats: "
539 << android::snapshot::UpdateState_Name(report.state()) << " in "
540 << passed_ms.count() << "ms (resumed " << report.resume_count()
Alessio Balsini4ed05122020-05-26 22:17:03 +0100541 << " times), using " << report.cow_file_size()
542 << " bytes of COW image.";
Vova Sharaienkod62c81b2022-09-21 05:32:43 +0000543 statsd::stats_write(statsd::SNAPSHOT_MERGE_REPORTED,
544 static_cast<int32_t>(report.state()),
545 static_cast<int64_t>(passed_ms.count()),
546 static_cast<int32_t>(report.resume_count()),
547 vab_retrofit,
548 static_cast<int64_t>(report.cow_file_size()),
549 vab_compression_enabled,
550 vab_compression_used,
551 report.total_cow_size_bytes(),
552 report.estimated_cow_size_bytes(),
553 report.boot_complete_time_ms(),
554 report.boot_complete_to_merge_start_time_ms(),
555 static_cast<int32_t>(report.merge_failure_code()),
556 report.source_build_fingerprint().c_str(),
557 target_build_fingerprint.c_str(),
558 userspace_snapshots_enabled,
559 userspace_snapshots_used,
560 xor_compression_enabled,
561 xor_compression_used,
562 iouring_used);
Yifan Hongd976cc52020-02-25 14:51:42 -0800563#endif
564}
565
Yifan Hongdad0af82020-02-19 17:19:49 -0800566} // namespace chromeos_update_engine