Merge tag 'android-14.0.0_r50' into leaf-3.2

Android 14.0.0 Release 50 (AP2A.240605.024)

* tag 'android-14.0.0_r50' of https://android.googlesource.com/platform/bootable/recovery:
  misctrl: use libbase combined logging
  misctrl: read message, incl 16kb flag
  intro misctrl
  Reland "Only format /data in recovery if user specified a new fstype"
  Add kcmdline bootloader message
  Revert "Only format /data in recovery if user specified a new fstype"
  Only format /data in recovery if user specified a new fstype
  Fix the problem of incremental OTA upgrade failure (recovery part)
  Add recovery flag to reformat /data

Change-Id: I86ccd1ec79f307a99ca5d1b5879831a1c523e723
diff --git a/bootloader_message/Android.bp b/bootloader_message/Android.bp
index 92c4428..24b562f 100644
--- a/bootloader_message/Android.bp
+++ b/bootloader_message/Android.bp
@@ -40,6 +40,17 @@
     export_include_dirs: ["include"],
 }
 
+cc_binary {
+    name: "misctrl",
+    shared_libs: [
+        "libbase",
+        "libbootloader_message",
+        "liblog",
+    ],
+    init_rc: ["misctrl.rc"],
+    srcs: ["misctrl_main.cpp"],
+}
+
 cc_library {
     name: "libbootloader_message",
     defaults: [
diff --git a/bootloader_message/bootloader_message.cpp b/bootloader_message/bootloader_message.cpp
index 18ff886..d80d9d1 100644
--- a/bootloader_message/bootloader_message.cpp
+++ b/bootloader_message/bootloader_message.cpp
@@ -26,6 +26,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/hex.h>
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
@@ -319,6 +320,43 @@
                                        offsetof(misc_system_space_layout, memtag_message), err);
 }
 
+bool ReadMiscKcmdlineMessage(misc_kcmdline_message* message, std::string* err) {
+  return ReadMiscPartitionSystemSpace(message, sizeof(*message),
+                                      offsetof(misc_system_space_layout, kcmdline_message), err);
+}
+
+bool WriteMiscKcmdlineMessage(const misc_kcmdline_message& message, std::string* err) {
+  return WriteMiscPartitionSystemSpace(&message, sizeof(message),
+                                       offsetof(misc_system_space_layout, kcmdline_message), err);
+}
+
+bool ReadMiscControlMessage(misc_control_message* message, std::string* err) {
+  return ReadMiscPartitionSystemSpace(message, sizeof(*message),
+                                      offsetof(misc_system_space_layout, control_message), err);
+}
+
+bool WriteMiscControlMessage(const misc_control_message& message, std::string* err) {
+  return WriteMiscPartitionSystemSpace(&message, sizeof(message),
+                                       offsetof(misc_system_space_layout, control_message), err);
+}
+
+bool CheckReservedSystemSpaceEmpty(bool* empty, std::string* err) {
+  constexpr size_t kReservedSize = SYSTEM_SPACE_SIZE_IN_MISC - sizeof(misc_system_space_layout);
+
+  uint8_t space[kReservedSize];
+  if (!ReadMiscPartitionSystemSpace(&space, kReservedSize, sizeof(misc_system_space_layout), err)) {
+    return false;
+  }
+
+  *empty = space[0] == 0 && 0 == memcmp(space, space + 1, kReservedSize - 1);
+
+  if (!*empty) {
+    *err = android::base::HexString(space, kReservedSize);
+  }
+
+  return true;
+}
+
 extern "C" bool write_reboot_bootloader(void) {
   std::string err;
   return write_reboot_bootloader(&err);
diff --git a/bootloader_message/include/bootloader_message/bootloader_message.h b/bootloader_message/include/bootloader_message/bootloader_message.h
index c8a8437..4b2b8a1 100644
--- a/bootloader_message/include/bootloader_message/bootloader_message.h
+++ b/bootloader_message/include/bootloader_message/bootloader_message.h
@@ -100,6 +100,21 @@
   uint8_t reserved[55];
 } __attribute__((packed));
 
+struct misc_kcmdline_message {
+  uint8_t version;
+  uint32_t magic;
+  uint64_t kcmdline_flags;
+  uint8_t reserved[51];
+} __attribute__((packed));
+
+// holds generic platform info, managed by misctrl
+struct misc_control_message {
+  uint8_t version;
+  uint32_t magic;
+  uint64_t misctrl_flags;
+  uint8_t reserved[51];
+} __attribute__((packed));
+
 #define MISC_VIRTUAL_AB_MESSAGE_VERSION 2
 #define MISC_VIRTUAL_AB_MAGIC_HEADER 0x56740AB0
 
@@ -116,11 +131,23 @@
 // See system/extras/mtectrl in AOSP for more information.
 #define MISC_MEMTAG_MODE_FORCED 0x20
 
+#define MISC_KCMDLINE_MESSAGE_VERSION 1
+#define MISC_KCMDLINE_MAGIC_HEADER 0x6ab5110c
+#define MISC_KCMDLINE_BINDER_RUST 0x1
+
+#define MISC_CONTROL_MESSAGE_VERSION 1
+#define MISC_CONTROL_MAGIC_HEADER 0x736d6f72
+#define MISC_CONTROL_16KB_BEFORE 0x1
+
 #if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
 static_assert(sizeof(struct misc_virtual_ab_message) == 64,
               "struct misc_virtual_ab_message has wrong size");
 static_assert(sizeof(struct misc_memtag_message) == 64,
               "struct misc_memtag_message has wrong size");
+static_assert(sizeof(struct misc_kcmdline_message) == 64,
+              "struct misc_kcmdline_message has wrong size");
+static_assert(sizeof(struct misc_control_message) == 64,
+              "struct misc_control_message has wrong size");
 #endif
 
 // This struct is not meant to be used directly, rather, it is to make
@@ -128,8 +155,15 @@
 struct misc_system_space_layout {
   misc_virtual_ab_message virtual_ab_message;
   misc_memtag_message memtag_message;
+  misc_kcmdline_message kcmdline_message;
+  misc_control_message control_message;
 } __attribute__((packed));
 
+#if (__STDC_VERSION__ >= 201112L) || defined(__cplusplus)
+static_assert(sizeof(struct misc_system_space_layout) % 64 == 0,
+              "prefer to extend by 64 byte chunks, for consistency");
+#endif
+
 #ifdef __cplusplus
 
 #include <string>
@@ -198,6 +232,18 @@
 // Read or write the memtag message from system space in /misc.
 bool ReadMiscMemtagMessage(misc_memtag_message* message, std::string* err);
 bool WriteMiscMemtagMessage(const misc_memtag_message& message, std::string* err);
+
+// Read or write the kcmdline message from system space in /misc.
+bool ReadMiscKcmdlineMessage(misc_kcmdline_message* message, std::string* err);
+bool WriteMiscKcmdlineMessage(const misc_kcmdline_message& message, std::string* err);
+
+// Read or write the kcmdline message from system space in /misc.
+bool ReadMiscControlMessage(misc_control_message* message, std::string* err);
+bool WriteMiscControlMessage(const misc_control_message& message, std::string* err);
+
+// Check reserved system space.
+bool CheckReservedSystemSpaceEmpty(bool* empty, std::string* err);
+
 #else
 
 #include <stdbool.h>
diff --git a/bootloader_message/misctrl.rc b/bootloader_message/misctrl.rc
new file mode 100644
index 0000000..5293bf2
--- /dev/null
+++ b/bootloader_message/misctrl.rc
@@ -0,0 +1,4 @@
+service misctrl /system/bin/misctrl
+    user root # for misc partition access
+    class core
+    oneshot
diff --git a/bootloader_message/misctrl_main.cpp b/bootloader_message/misctrl_main.cpp
new file mode 100644
index 0000000..653b62d
--- /dev/null
+++ b/bootloader_message/misctrl_main.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 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 <android-base/logging.h>
+#include <android-base/properties.h>
+#include <bootloader_message/bootloader_message.h>
+#include <log/log.h>
+
+#include <string>
+
+#include <cstdio>
+
+static int check_control_message() {
+  misc_control_message m;
+  std::string err;
+  if (!ReadMiscControlMessage(&m, &err)) {
+    LOG(ERROR) << "Could not read misctrl message: " << err.c_str();
+    return 1;
+  }
+
+  if (m.magic != MISC_CONTROL_MAGIC_HEADER || m.version != MISC_CONTROL_MESSAGE_VERSION) {
+    LOG(WARNING) << "misctrl message invalid, resetting it";
+    m = { .version = MISC_CONTROL_MESSAGE_VERSION,
+          .magic = MISC_CONTROL_MAGIC_HEADER,
+          .misctrl_flags = 0 };
+  }
+
+  int res = 0;
+
+  const size_t ps = getpagesize();
+
+  if (ps != 4096 && ps != 16384) {
+    LOG(ERROR) << "Unrecognized page size: " << ps;
+    res = 1;
+  }
+
+  if (ps == 16384) {
+    m.misctrl_flags |= MISC_CONTROL_16KB_BEFORE;
+  }
+
+  bool before_16kb = m.misctrl_flags & MISC_CONTROL_16KB_BEFORE;
+  res |= android::base::SetProperty("ro.misctrl.16kb_before", before_16kb ? "1" : "0");
+
+  if (!WriteMiscControlMessage(m, &err)) {
+    LOG(ERROR) << "Could not write misctrl message: " << err.c_str();
+    res |= 1;
+  }
+
+  return res;
+}
+
+static int check_reserved_space() {
+  bool empty;
+  std::string err;
+  bool success = CheckReservedSystemSpaceEmpty(&empty, &err);
+  if (!success) {
+    LOG(ERROR) << "Could not read reserved space: " << err.c_str();
+    return 1;
+  }
+  LOG(INFO) << "System reserved space empty? " << empty;
+
+  if (!err.empty()) {
+    LOG(ERROR) << "Reserved misc space being used: " << err;
+  }
+
+  return empty ? 0 : 1;
+}
+
+int main(int argc, char** argv) {
+  {
+    using namespace android::base;
+    (void)argc;
+    InitLogging(argv, TeeLogger(LogdLogger(), &StderrLogger));
+  }
+  int err = 0;
+  err |= check_control_message();
+  err |= check_reserved_space();
+  return err;
+}
diff --git a/install/include/install/wipe_data.h b/install/include/install/wipe_data.h
index 75b8d36..47a5a80 100644
--- a/install/include/install/wipe_data.h
+++ b/install/include/install/wipe_data.h
@@ -24,10 +24,11 @@
 struct selabel_handle;
 
 // Returns true on success.
-bool WipeCache(RecoveryUI* ui, const std::function<bool()>& confirm);
+bool WipeCache(RecoveryUI* ui, const std::function<bool()>& confirm,
+               std::string_view new_fstype = "");
 
 // Returns true on success.
-bool WipeData(Device* device, bool keep_memtag_mode = false);
+bool WipeData(Device* device, bool keep_memtag_mode = false, std::string_view new_fstype = "");
 
 // Returns true on success.
 bool WipeSystem(RecoveryUI* ui, const std::function<bool()>& confirm);
diff --git a/install/wipe_data.cpp b/install/wipe_data.cpp
index b10b0b8..b390a61 100644
--- a/install/wipe_data.cpp
+++ b/install/wipe_data.cpp
@@ -35,7 +35,6 @@
 
 #include "bootloader_message/bootloader_message.h"
 #include "install/snapshot_utils.h"
-#include "otautil/dirutil.h"
 #include "recovery_ui/ui.h"
 #include "recovery_utils/logging.h"
 #include "recovery_utils/roots.h"
@@ -44,7 +43,8 @@
 constexpr const char* DATA_ROOT = "/data";
 constexpr const char* METADATA_ROOT = "/metadata";
 
-static bool EraseVolume(const char* volume, RecoveryUI* ui) {
+static bool EraseVolume(const char* volume, RecoveryUI* ui, std::string_view new_fstype) {
+  LOG(INFO) << "Erasing volume " << volume << " with new filesystem type " << new_fstype;
   bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
 
   std::vector<saved_log_file> log_files;
@@ -103,7 +103,7 @@
     return false;
   }
 
-  int result = format_volume(volume);
+  int result = format_volume(volume, "", new_fstype);
 
   if (is_cache) {
     RestoreLogFilesAfterFormat(log_files);
@@ -112,7 +112,8 @@
   return (result == 0);
 }
 
-bool WipeCache(RecoveryUI* ui, const std::function<bool()>& confirm_func) {
+bool WipeCache(RecoveryUI* ui, const std::function<bool()>& confirm_func,
+               std::string_view new_fstype) {
   bool has_cache = volume_for_mount_point("/cache") != nullptr;
   if (!has_cache) {
     ui->Print("No /cache partition found.\n");
@@ -127,14 +128,14 @@
   ui->SetBackground(RecoveryUI::ERASING);
   ui->SetProgressType(RecoveryUI::INDETERMINATE);
 
-  bool success = EraseVolume("/cache", ui);
+  bool success = EraseVolume("/cache", ui, new_fstype);
   ui->Print("Cache wipe %s.\n", success ? "complete" : "failed");
   return success;
 }
 
-bool WipeData(Device* device, bool keep_memtag_mode) {
+bool WipeData(Device* device, bool keep_memtag_mode, std::string_view data_fstype) {
   RecoveryUI* ui = device->GetUI();
-  ui->Print("\n-- Wiping data...\n");
+  ui->Print("\n-- Wiping data %.*s...\n", static_cast<int>(data_fstype.size()), data_fstype.data());
   ui->SetBackground(RecoveryUI::ERASING);
   ui->SetProgressType(RecoveryUI::INDETERMINATE);
 
@@ -145,13 +146,13 @@
 
   bool success = device->PreWipeData();
   if (success) {
-    success &= EraseVolume(DATA_ROOT, ui);
+    success &= EraseVolume(DATA_ROOT, ui, data_fstype);
     bool has_cache = volume_for_mount_point("/cache") != nullptr;
     if (has_cache) {
-      success &= EraseVolume(CACHE_ROOT, ui);
+      success &= EraseVolume(CACHE_ROOT, ui, data_fstype);
     }
     if (volume_for_mount_point(METADATA_ROOT) != nullptr) {
-      success &= EraseVolume(METADATA_ROOT, ui);
+      success &= EraseVolume(METADATA_ROOT, ui, data_fstype);
     }
   }
   if (keep_memtag_mode) {
diff --git a/recovery.cpp b/recovery.cpp
index 129af41..5824ff5 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -16,11 +16,8 @@
 
 #include "recovery.h"
 
-#include <ctype.h>
 #include <errno.h>
 #include <getopt.h>
-#include <inttypes.h>
-#include <limits.h>
 #include <linux/input.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -54,7 +51,6 @@
 #include "install/snapshot_utils.h"
 #include "install/wipe_data.h"
 #include "install/wipe_device.h"
-#include "otautil/boot_state.h"
 #include "otautil/error_code.h"
 #include "otautil/package.h"
 #include "otautil/paths.h"
@@ -557,7 +553,8 @@
         update_in_progress = true;
         WriteUpdateInProgress();
 
-        Device::BuiltinAction reboot_action;
+        bool adb = true;
+        Device::BuiltinAction reboot_action{};
         if (chosen_action == Device::ENTER_RESCUE) {
           // Switch to graphics screen.
           ui->ShowText(false);
@@ -722,6 +719,7 @@
     { "wipe_data", no_argument, nullptr, 0 },
     { "keep_memtag_mode", no_argument, nullptr, 0 },
     { "wipe_package_size", required_argument, nullptr, 0 },
+    { "reformat_data", required_argument, nullptr, 0 },
     { nullptr, 0, nullptr, 0 },
   };
 
@@ -744,8 +742,9 @@
 
   auto args_to_parse = StringVectorToNullTerminatedArray(args);
 
-  int arg;
-  int option_index;
+  int arg = 0;
+  int option_index = 0;
+  std::string data_fstype;
   // Parse everything before the last element (which must be a nullptr). getopt_long(3) expects a
   // null-terminated char* array, but without counting null as an arg (i.e. argv[argc] should be
   // nullptr).
@@ -789,6 +788,8 @@
           should_wipe_data = true;
         } else if (option == "wipe_package_size") {
           android::base::ParseUint(optarg, &wipe_package_size);
+        } else if (option == "reformat_data") {
+          data_fstype = optarg;
         } else if (option == "keep_memtag_mode") {
           should_keep_memtag_mode = true;
         }
@@ -816,7 +817,7 @@
   // otherwise set it to "installing system update".
   ui->SetSystemUpdateText(security_update);
 
-  int st_cur, st_max;
+  int st_cur = 0, st_max = 0;
   if (!device->GetStage().has_value() &&
       sscanf(device->GetStage().value().c_str(), "%d/%d", &st_cur, &st_max) == 2) {
     ui->SetStage(st_cur, st_max);
@@ -856,7 +857,7 @@
     // to log the update attempt since update_package is non-NULL.
     save_current_log = true;
 
-    if (int required_battery_level; retry_count == 0 && !IsBatteryOk(&required_battery_level)) {
+    if (int required_battery_level = 0; retry_count == 0 && !IsBatteryOk(&required_battery_level)) {
       ui->Print("battery capacity is not enough for installing package: %d%% needed\n",
                 required_battery_level);
       // Log the error code to last_install when installation skips due to low battery.
@@ -922,7 +923,7 @@
   } else if (should_wipe_data) {
     save_current_log = true;
     CHECK(device->GetReason().has_value());
-    if (!WipeData(device, should_keep_memtag_mode)) {
+    if (!WipeData(device, should_keep_memtag_mode, data_fstype)) {
       status = INSTALL_ERROR;
     }
   } else if (should_prompt_and_wipe_data) {
@@ -937,7 +938,7 @@
     }
   } else if (should_wipe_cache) {
     save_current_log = true;
-    if (!WipeCache(ui, nullptr)) {
+    if (!WipeCache(ui, nullptr, data_fstype)) {
       status = INSTALL_ERROR;
     }
   } else if (should_wipe_ab) {
diff --git a/recovery_main.cpp b/recovery_main.cpp
index 366e921..5e27419 100644
--- a/recovery_main.cpp
+++ b/recovery_main.cpp
@@ -134,7 +134,7 @@
         // Skip empty and '\0'-filled tokens.
         if (!it->empty() && (*it)[0] != '\0') args.push_back(std::move(*it));
       }
-      LOG(INFO) << "Got " << args.size() << " arguments from boot message";
+      LOG(INFO) << "Got " << args.size() << " arguments from boot message " << android::base::Join(args, ", ");
     } else if (boot.recovery[0] != 0) {
       LOG(ERROR) << "Bad boot message: \"" << boot_recovery << "\"";
     }
diff --git a/recovery_utils/include/recovery_utils/roots.h b/recovery_utils/include/recovery_utils/roots.h
index cbc8b07..aa7b0ee 100644
--- a/recovery_utils/include/recovery_utils/roots.h
+++ b/recovery_utils/include/recovery_utils/roots.h
@@ -52,7 +52,8 @@
 // "/cache"), no paths permitted.  Attempts to unmount the volume if
 // it is mounted.
 // Copies 'directory' to root of the newly formatted volume
-int format_volume(const std::string& volume, const std::string& directory);
+int format_volume(const std::string& volume, const std::string& directory,
+                  std::string_view new_fstype);
 
 // Ensure that all and only the volumes that packages expect to find
 // mounted (/tmp and /cache) are mounted.  Returns 0 on success.
diff --git a/recovery_utils/roots.cpp b/recovery_utils/roots.cpp
index 010b98c..9ebb3e0 100644
--- a/recovery_utils/roots.cpp
+++ b/recovery_utils/roots.cpp
@@ -155,7 +155,8 @@
   return computed_size;
 }
 
-int format_volume(const std::string& volume, const std::string& directory) {
+int format_volume(const std::string& volume, const std::string& directory,
+                  std::string_view new_fstype) {
   const FstabEntry* v = android::fs_mgr::GetEntryForPath(&fstab, volume);
   if (v == nullptr) {
     LOG(ERROR) << "unknown volume \"" << volume << "\"";
@@ -201,11 +202,13 @@
   }
 
   // If the raw disk will be used as a metadata encrypted device mapper target,
-  // next boot will do encrypt_in_place the raw disk which gives a subtle duration
-  // to get any failure in the process. In order to avoid it, let's simply wipe
-  // the raw disk if we don't reserve any space, which behaves exactly same as booting
-  // after "fastboot -w".
-  if (!v->metadata_key_dir.empty() && length == 0) {
+  // next boot will do encrypt_in_place the raw disk. While fs_mgr mounts /data
+  // as RO to avoid write file operations before encrypt_inplace, this code path
+  // is not well tested so we would like to avoid it if possible. For safety,
+  // let vold do the formatting on boot for metadata encrypted devices, except
+  // when user specified a new fstype. Because init formats /data according
+  // to fstab, it's difficult to override the fstab in init.
+  if (!v->metadata_key_dir.empty() && length == 0 && new_fstype.empty()) {
     android::base::unique_fd fd(open(v->blk_device.c_str(), O_RDWR));
     if (fd == -1) {
       PLOG(ERROR) << "format_volume: failed to open " << v->blk_device;
@@ -219,7 +222,8 @@
     }
   }
 
-  if (v->fs_type == "ext4") {
+  if ((v->fs_type == "ext4" && new_fstype.empty()) || new_fstype == "ext4") {
+    LOG(INFO) << "Formatting " << v->blk_device << " as ext4";
     static constexpr int kBlockSize = 4096;
     std::vector<std::string> mke2fs_args = {
       "/system/bin/mke2fs", "-F", "-t", "ext4", "-b", std::to_string(kBlockSize),
@@ -271,6 +275,7 @@
   }
 
   // Has to be f2fs because we checked earlier.
+  LOG(INFO) << "Formatting " << v->blk_device << " as f2fs";
   static constexpr int kSectorSize = 4096;
   std::vector<std::string> make_f2fs_cmd = {
     "/system/bin/make_f2fs",
@@ -315,7 +320,7 @@
 }
 
 int format_volume(const std::string& volume) {
-  return format_volume(volume, "");
+  return format_volume(volume, "", "");
 }
 
 int setup_install_mounts() {
diff --git a/updater/Android.bp b/updater/Android.bp
index 35debaa..4fc3c49 100644
--- a/updater/Android.bp
+++ b/updater/Android.bp
@@ -44,7 +44,7 @@
         "libbrotli",
         "libbz",
         "libziparchive",
-        "libz",
+        "libz_stable",
         "libbase",
         "libcrypto_utils",
         "libcutils",
diff --git a/updater/Android.mk b/updater/Android.mk
index bb1c07d..2fd5639 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -42,7 +42,7 @@
     libbrotli \
     libbz \
     libziparchive \
-    libz \
+    libz_stable \
     libbase \
     libcrypto_static \
     libcrypto_utils \