init: set ro.boot.avb_version in recovery mode

Previously we set ro.boot.avb_version during the first stage mount in normal mode:
  - https://android-review.googlesource.com/#/c/371774/

As the first stage mount is not performed in recovery mode, we need to set the
property separately in recovery mode.

Bug: 37414003

Test: first stage mount /vendor with vboot 2.0 (avb) on bullhead in normal mode
Test: first stage mount /system with without verity on bullhead in normal mode
Test: checks ro.boot.avb_version is 1.0 on bullhead in recovery mode

Test: first mount /vendor with with vboot 1.0 on sailfish in normal mode
Test: checks ro.boot.avb_version doesn't exist on sailfish in recovery mode

Change-Id: I262e75b8b557c4de7609b4049ccb01793644245e
diff --git a/init/init.cpp b/init/init.cpp
index cec4475..1b4bdf3 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -978,6 +978,8 @@
             panic();
         }
 
+        SetInitAvbVersionInRecovery();
+
         // Set up SELinux, loading the SELinux policy.
         selinux_initialize(true);
 
diff --git a/init/init_first_stage.cpp b/init/init_first_stage.cpp
index 0c252e3..0bacd9c 100644
--- a/init/init_first_stage.cpp
+++ b/init/init_first_stage.cpp
@@ -33,6 +33,8 @@
 #include "fs_mgr_avb.h"
 #include "util.h"
 
+// Class Declarations
+// ------------------
 class FirstStageMount {
   public:
     FirstStageMount();
@@ -42,6 +44,7 @@
     // based on device tree configurations.
     static std::unique_ptr<FirstStageMount> Create();
     bool DoFirstStageMount();  // Mounts fstab entries read from device tree.
+    bool InitDevices();
 
   protected:
     void InitRequiredDevices(std::set<std::string>* devices_partition_names);
@@ -74,6 +77,8 @@
     FirstStageMountVBootV2();
     ~FirstStageMountVBootV2() override = default;
 
+    const std::string& by_name_prefix() const { return device_tree_by_name_prefix_; }
+
   protected:
     bool GetRequiredDevices(std::set<std::string>* out_devices_partition_names,
                             bool* out_need_dm_verity) override;
@@ -85,6 +90,18 @@
     FsManagerAvbUniquePtr avb_handle_;
 };
 
+// Static Functions
+// ----------------
+static inline bool IsDtVbmetaCompatible() {
+    return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
+}
+
+static bool inline IsRecoveryMode() {
+    return access("/sbin/recovery", F_OK) == 0;
+}
+
+// Class Definitions
+// -----------------
 FirstStageMount::FirstStageMount() : device_tree_fstab_(fs_mgr_read_fstab_dt(), fs_mgr_free_fstab) {
     if (!device_tree_fstab_) {
         LOG(ERROR) << "Failed to read fstab from device tree";
@@ -100,7 +117,7 @@
 }
 
 std::unique_ptr<FirstStageMount> FirstStageMount::Create() {
-    if (is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta")) {
+    if (IsDtVbmetaCompatible()) {
         return std::make_unique<FirstStageMountVBootV2>();
     } else {
         return std::make_unique<FirstStageMountVBootV1>();
@@ -111,6 +128,14 @@
     // Nothing to mount.
     if (mount_fstab_recs_.empty()) return true;
 
+    if (!InitDevices()) return false;
+
+    if (!MountPartitions()) return false;
+
+    return true;
+}
+
+bool FirstStageMount::InitDevices() {
     bool need_dm_verity;
     std::set<std::string> devices_partition_names;
 
@@ -134,8 +159,6 @@
         success = true;
     }
 
-    if (MountPartitions()) success = true;
-
     device_close();
     return success;
 }
@@ -361,7 +384,7 @@
 // Mounts /system, /vendor, and/or /odm if they are present in the fstab provided by device tree.
 bool DoFirstStageMount() {
     // Skips first stage mount if we're in recovery mode.
-    if (access("/sbin/recovery", F_OK) == 0) {
+    if (IsRecoveryMode()) {
         LOG(INFO) << "First stage mount skipped (recovery mode)";
         return true;
     }
@@ -379,3 +402,33 @@
     }
     return handle->DoFirstStageMount();
 }
+
+void SetInitAvbVersionInRecovery() {
+    if (!IsRecoveryMode()) {
+        LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
+        return;
+    }
+
+    if (!IsDtVbmetaCompatible()) {
+        LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not vbmeta compatible)";
+        return;
+    }
+
+    // Initializes required devices for the subsequent FsManagerAvbHandle::Open()
+    // to verify AVB metadata on all partitions in the verified chain.
+    // We only set INIT_AVB_VERSION when the AVB verification succeeds, i.e., the
+    // Open() function returns a valid handle.
+    // We don't need to mount partitions here in recovery mode.
+    FirstStageMountVBootV2 avb_first_mount;
+    if (!avb_first_mount.InitDevices()) {
+        LOG(ERROR) << "Failed to init devices for INIT_AVB_VERSION";
+        return;
+    }
+
+    FsManagerAvbUniquePtr avb_handle = FsManagerAvbHandle::Open(avb_first_mount.by_name_prefix());
+    if (!avb_handle) {
+        PLOG(ERROR) << "Failed to open FsManagerAvbHandle for INIT_AVB_VERSION";
+        return;
+    }
+    setenv("INIT_AVB_VERSION", avb_handle->avb_version().c_str(), 1);
+}
diff --git a/init/init_first_stage.h b/init/init_first_stage.h
index 0477f13..170a24c 100644
--- a/init/init_first_stage.h
+++ b/init/init_first_stage.h
@@ -18,5 +18,6 @@
 #define _INIT_FIRST_STAGE_H
 
 bool DoFirstStageMount();
+void SetInitAvbVersionInRecovery();
 
 #endif