Merge "Remove common.h"
am: 899f7b5105

Change-Id: Ic5b9e24cb87ef292f5d8e53de485e44e455f3185
diff --git a/common.h b/common.h
deleted file mode 100644
index 128a69d..0000000
--- a/common.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2007 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.
- */
-
-#pragma once
-
-#include <string>
-
-// The current stage, e.g. "1/2".
-extern std::string stage;
-
-// The reason argument provided in "--reason=".
-extern const char* reason;
diff --git a/otautil/include/otautil/boot_state.h b/otautil/include/otautil/boot_state.h
new file mode 100644
index 0000000..6c877ba
--- /dev/null
+++ b/otautil/include/otautil/boot_state.h
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <string_view>
+
+class BootState {
+ public:
+  BootState(std::string_view reason, std::string_view stage) : reason_(reason), stage_(stage) {}
+
+  std::string reason() const {
+    return reason_;
+  }
+  std::string stage() const {
+    return stage_;
+  }
+
+ private:
+  std::string reason_;  // The reason argument provided in "--reason=".
+  std::string stage_;   // The current stage, e.g. "1/2".
+};
diff --git a/recovery.cpp b/recovery.cpp
index b989b24..4862dfc 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -46,7 +46,6 @@
 #include <ziparchive/zip_archive.h>
 
 #include "bootloader_message/bootloader_message.h"
-#include "common.h"
 #include "fsck_unshare_blocks.h"
 #include "install/adb_install.h"
 #include "install/fuse_install.h"
@@ -54,6 +53,7 @@
 #include "install/package.h"
 #include "install/wipe_data.h"
 #include "install/wipe_device.h"
+#include "otautil/boot_state.h"
 #include "otautil/error_code.h"
 #include "otautil/logging.h"
 #include "otautil/paths.h"
@@ -70,8 +70,6 @@
 static constexpr const char* CACHE_ROOT = "/cache";
 
 static bool save_current_log = false;
-std::string stage;
-const char* reason = nullptr;
 
 /*
  * The recovery tool communicates with the main system through /cache files.
@@ -208,7 +206,8 @@
     }
 
     if (ask_to_wipe_data(device)) {
-      bool convert_fbe = reason && strcmp(reason, "convert_fbe") == 0;
+      CHECK(device->GetReason().has_value());
+      bool convert_fbe = device->GetReason().value() == "convert_fbe";
       if (WipeData(device, convert_fbe)) {
         return INSTALL_SUCCESS;
       } else {
@@ -635,12 +634,10 @@
           fsck_unshare_blocks = true;
         } else if (option == "install_with_fuse") {
           install_with_fuse = true;
-        } else if (option == "locale" || option == "fastboot") {
+        } else if (option == "locale" || option == "fastboot" || option == "reason") {
           // Handled in recovery_main.cpp
         } else if (option == "prompt_and_wipe_data") {
           should_prompt_and_wipe_data = true;
-        } else if (option == "reason") {
-          reason = optarg;
         } else if (option == "rescue") {
           rescue = true;
         } else if (option == "retry_count") {
@@ -674,8 +671,8 @@
   }
   optind = 1;
 
-  printf("stage is [%s]\n", stage.c_str());
-  printf("reason is [%s]\n", reason);
+  printf("stage is [%s]\n", device->GetStage().value_or("").c_str());
+  printf("reason is [%s]\n", device->GetReason().value_or("").c_str());
 
   auto ui = device->GetUI();
 
@@ -684,7 +681,8 @@
   ui->SetSystemUpdateText(security_update);
 
   int st_cur, st_max;
-  if (!stage.empty() && sscanf(stage.c_str(), "%d/%d", &st_cur, &st_max) == 2) {
+  if (!device->GetStage().has_value() &&
+      sscanf(device->GetStage().value().c_str(), "%d/%d", &st_cur, &st_max) == 2) {
     ui->SetStage(st_cur, st_max);
   }
 
@@ -790,7 +788,8 @@
     }
   } else if (should_wipe_data) {
     save_current_log = true;
-    bool convert_fbe = reason && strcmp(reason, "convert_fbe") == 0;
+    CHECK(device->GetReason().has_value());
+    bool convert_fbe = device->GetReason().value() == "convert_fbe";
     if (!WipeData(device, convert_fbe)) {
       status = INSTALL_ERROR;
     }
diff --git a/recovery_main.cpp b/recovery_main.cpp
index f0d75ee..28197bf 100644
--- a/recovery_main.cpp
+++ b/recovery_main.cpp
@@ -48,9 +48,9 @@
 #include <selinux/label.h>
 #include <selinux/selinux.h>
 
-#include "common.h"
 #include "fastboot/fastboot.h"
 #include "install/wipe_data.h"
+#include "otautil/boot_state.h"
 #include "otautil/logging.h"
 #include "otautil/paths.h"
 #include "otautil/roots.h"
@@ -80,11 +80,12 @@
   }
 }
 
+// Parses the command line argument from various sources; and reads the stage field from BCB.
 // command line args come from, in decreasing precedence:
 //   - the actual command line
 //   - the bootloader control block (one per line, after "recovery")
 //   - the contents of COMMAND_FILE (one per line)
-static std::vector<std::string> get_args(const int argc, char** const argv) {
+static std::vector<std::string> get_args(const int argc, char** const argv, std::string* stage) {
   CHECK_GT(argc, 0);
 
   bootloader_message boot = {};
@@ -94,7 +95,9 @@
     // If fails, leave a zeroed bootloader_message.
     boot = {};
   }
-  stage = std::string(boot.stage);
+  if (stage) {
+    *stage = std::string(boot.stage);
+  }
 
   std::string boot_command;
   if (boot.command[0] != 0) {
@@ -331,12 +334,14 @@
 
   load_volume_table();
 
-  std::vector<std::string> args = get_args(argc, argv);
+  std::string stage;
+  std::vector<std::string> args = get_args(argc, argv, &stage);
   auto args_to_parse = StringVectorToNullTerminatedArray(args);
 
   static constexpr struct option OPTIONS[] = {
     { "fastboot", no_argument, nullptr, 0 },
     { "locale", required_argument, nullptr, 0 },
+    { "reason", required_argument, nullptr, 0 },
     { "show_text", no_argument, nullptr, 't' },
     { nullptr, 0, nullptr, 0 },
   };
@@ -344,6 +349,7 @@
   bool show_text = false;
   bool fastboot = false;
   std::string locale;
+  std::string reason;
 
   int arg;
   int option_index;
@@ -357,6 +363,8 @@
         std::string option = OPTIONS[option_index].name;
         if (option == "locale") {
           locale = optarg;
+        } else if (option == "reason") {
+          reason = optarg;
         } else if (option == "fastboot" &&
                    android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
           fastboot = true;
@@ -412,6 +420,9 @@
       device->ResetUI(new StubRecoveryUI());
     }
   }
+
+  BootState boot_state(reason, stage);  // recovery_main owns the state of boot.
+  device->SetBootState(&boot_state);
   ui = device->GetUI();
 
   if (!HasCache()) {
diff --git a/recovery_ui/device.cpp b/recovery_ui/device.cpp
index e7ae1a3..d46df92 100644
--- a/recovery_ui/device.cpp
+++ b/recovery_ui/device.cpp
@@ -23,6 +23,7 @@
 
 #include <android-base/logging.h>
 
+#include "otautil/boot_state.h"
 #include "recovery_ui/ui.h"
 
 static std::vector<std::pair<std::string, Device::BuiltinAction>> g_menu_actions{
@@ -95,3 +96,15 @@
       return ui_->HasThreeButtons() ? kNoAction : kHighlightDown;
   }
 }
+
+void Device::SetBootState(const BootState* state) {
+  boot_state_ = state;
+}
+
+std::optional<std::string> Device::GetReason() const {
+  return boot_state_ ? std::make_optional(boot_state_->reason()) : std::nullopt;
+}
+
+std::optional<std::string> Device::GetStage() const {
+  return boot_state_ ? std::make_optional(boot_state_->stage()) : std::nullopt;
+}
diff --git a/recovery_ui/include/recovery_ui/device.h b/recovery_ui/include/recovery_ui/device.h
index 9a4edf2..f4f9936 100644
--- a/recovery_ui/include/recovery_ui/device.h
+++ b/recovery_ui/include/recovery_ui/device.h
@@ -20,12 +20,15 @@
 #include <stddef.h>
 
 #include <memory>
+#include <optional>
 #include <string>
 #include <vector>
 
 // Forward declaration to avoid including "ui.h".
 class RecoveryUI;
 
+class BootState;
+
 class Device {
  public:
   static constexpr const int kNoAction = -1;
@@ -126,9 +129,16 @@
     return true;
   }
 
+  void SetBootState(const BootState* state);
+  // The getters for reason and stage may return std::nullopt until StartRecovery() is called. It's
+  // the caller's responsibility to perform the check and handle the exception.
+  std::optional<std::string> GetReason() const;
+  std::optional<std::string> GetStage() const;
+
  private:
   // The RecoveryUI object that should be used to display the user interface for this device.
   std::unique_ptr<RecoveryUI> ui_;
+  const BootState* boot_state_{ nullptr };
 };
 
 // Disable name mangling, as this function will be loaded via dlsym(3).