update_engine: Pospone setgoodkernel after update check

Currently, if an update is forced, we first run setgoodkernel and then continue
with the update check. However, this delays the update check screen in the
OOBE. This patch adds a new Action, UpdateBootFlagsAction which is configured to
run AFTER an update check and response. However, now if the update check failed
due for example the response was invalid, then setgoodkernel will not
happen. But we already have a mechanism in SystemState where setgoodkernel is
always called (currently) 45 seconds after the boot. So there would no worries.

BUG=chromium:807976
TEST=unittests
TEST=powerwashed the device, and the check for update passed faster on OOBE.

Change-Id: I5845d7a4c1393aec568b6279dfbb7d3dfa31cdd8
Reviewed-on: https://chromium-review.googlesource.com/1011244
Commit-Ready: Amin Hassani <ahassani@chromium.org>
Tested-by: Amin Hassani <ahassani@chromium.org>
Reviewed-by: Sen Jiang <senj@chromium.org>
diff --git a/update_boot_flags_action.cc b/update_boot_flags_action.cc
new file mode 100644
index 0000000..97ef7f2
--- /dev/null
+++ b/update_boot_flags_action.cc
@@ -0,0 +1,68 @@
+//
+// 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_boot_flags_action.h"
+
+#include <base/bind.h>
+#include <base/logging.h>
+
+#include "update_engine/common/boot_control.h"
+
+namespace chromeos_update_engine {
+
+bool UpdateBootFlagsAction::updated_boot_flags_ = false;
+bool UpdateBootFlagsAction::is_running_ = false;
+
+void UpdateBootFlagsAction::PerformAction() {
+  if (is_running_) {
+    LOG(INFO) << "Update boot flags running, nothing to do.";
+    processor_->ActionComplete(this, ErrorCode::kSuccess);
+    return;
+  }
+  if (updated_boot_flags_) {
+    LOG(INFO) << "Already updated boot flags. Skipping.";
+    processor_->ActionComplete(this, ErrorCode::kSuccess);
+    return;
+  }
+
+  // This is purely best effort. Failures should be logged by Subprocess. Run
+  // the script asynchronously to avoid blocking the event loop regardless of
+  // the script runtime.
+  is_running_ = true;
+  LOG(INFO) << "Marking booted slot as good.";
+  if (!boot_control_->MarkBootSuccessfulAsync(
+          base::Bind(&UpdateBootFlagsAction::CompleteUpdateBootFlags,
+                     base::Unretained(this)))) {
+    CompleteUpdateBootFlags(false);
+  }
+}
+
+void UpdateBootFlagsAction::CompleteUpdateBootFlags(bool successful) {
+  is_running_ = false;
+  if (!successful) {
+    // We ignore the failure for now because if the updating boot flags is flaky
+    // or has a bug in a specific release, then blocking the update can cause
+    // devices to stay behind even though we could have updated the system and
+    // fixed the issue regardless of this failure.
+    //
+    // TODO(ahassani): Add new error code metric for kUpdateBootFlagsFailed.
+    LOG(ERROR) << "Updating boot flags failed, but ignoring its failure.";
+  }
+  updated_boot_flags_ = true;
+  processor_->ActionComplete(this, ErrorCode::kSuccess);
+}
+
+}  // namespace chromeos_update_engine