Merge "BatteryMonitor: support battery health INCONSISTENT from health status"
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 39d7fff..4cd6193 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -2759,3 +2759,48 @@
   ASSERT_BACKTRACE_FRAME(result, "raise_debugger_signal");
   ASSERT_NOT_MATCH(result, kLogMessage);
 }
+
+// Disable this test since there is a high liklihood that this would
+// be flaky since it requires 500 messages being in the log.
+TEST_F(CrasherTest, DISABLED_max_log_messages) {
+  StartProcess([]() {
+    for (size_t i = 0; i < 600; i++) {
+      LOG(INFO) << "Message number " << i;
+    }
+    abort();
+  });
+
+  unique_fd output_fd;
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  int intercept_result;
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_NOT_MATCH(result, "Message number 99");
+  ASSERT_MATCH(result, "Message number 100");
+  ASSERT_MATCH(result, "Message number 599");
+}
+
+TEST_F(CrasherTest, log_with_newline) {
+  StartProcess([]() {
+    LOG(INFO) << "This line has a newline.\nThis is on the next line.";
+    abort();
+  });
+
+  unique_fd output_fd;
+  StartIntercept(&output_fd);
+  FinishCrasher();
+  AssertDeath(SIGABRT);
+  int intercept_result;
+  FinishIntercept(&intercept_result);
+  ASSERT_EQ(1, intercept_result) << "tombstoned reported failure";
+
+  std::string result;
+  ConsumeFd(std::move(output_fd), &result);
+  ASSERT_MATCH(result, ":\\s*This line has a newline.");
+  ASSERT_MATCH(result, ":\\s*This is on the next line.");
+}
diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp
index acd814e..7b2e068 100644
--- a/debuggerd/libdebuggerd/tombstone_proto.cpp
+++ b/debuggerd/libdebuggerd/tombstone_proto.cpp
@@ -70,6 +70,9 @@
 
 using android::base::StringPrintf;
 
+// The maximum number of messages to save in the protobuf per file.
+static constexpr size_t kMaxLogMessages = 500;
+
 // Use the demangler from libc++.
 extern "C" char* __cxa_demangle(const char*, char*, size_t*, int* status);
 
@@ -491,8 +494,8 @@
 }
 
 static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) {
-  logger_list* logger_list =
-      android_logger_list_open(android_name_to_log_id(logger), ANDROID_LOG_NONBLOCK, 0, pid);
+  logger_list* logger_list = android_logger_list_open(android_name_to_log_id(logger),
+                                                      ANDROID_LOG_NONBLOCK, kMaxLogMessages, pid);
 
   LogBuffer buffer;
 
diff --git a/debuggerd/seccomp_policy/crash_dump.riscv64.policy b/debuggerd/seccomp_policy/crash_dump.riscv64.policy
index 21887ab..281e231 100644
--- a/debuggerd/seccomp_policy/crash_dump.riscv64.policy
+++ b/debuggerd/seccomp_policy/crash_dump.riscv64.policy
@@ -19,12 +19,13 @@
 faccessat: 1
 recvmsg: 1
 recvfrom: 1
+sysinfo: 1
 process_vm_readv: 1
 tgkill: 1
 rt_sigprocmask: 1
 rt_sigaction: 1
 rt_tgsigqueueinfo: 1
-prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41 || arg0 == PR_PAC_RESET_KEYS
+prctl: arg0 == PR_GET_NO_NEW_PRIVS || arg0 == 0x53564d41
 madvise: 1
 mprotect: arg2 in 0x1|0x2
 munmap: 1
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index f09616a..f5fd3a1 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1487,13 +1487,20 @@
     return partition;
 }
 
-void do_flash(const char* pname, const char* fname, const bool apply_vbmeta) {
+void do_flash(const char* pname, const char* fname, const bool apply_vbmeta,
+              const FlashingPlan* fp) {
     verbose("Do flash %s %s", pname, fname);
     struct fastboot_buffer buf;
 
-    if (!load_buf(fname, &buf)) {
+    if (fp->source) {
+        unique_fd fd = fp->source->OpenFile(fname);
+        if (fd < 0 || !load_buf_fd(std::move(fd), &buf)) {
+            die("could not load '%s': %s", fname, strerror(errno));
+        }
+    } else if (!load_buf(fname, &buf)) {
         die("cannot load '%s': %s", fname, strerror(errno));
     }
+
     if (is_logical(pname)) {
         fb->ResizePartition(pname, std::to_string(buf.image_size));
     }
@@ -1592,7 +1599,7 @@
     if (img_name.empty()) {
         img_name = partition + ".img";
     }
-    return std::make_unique<FlashTask>(slot, partition, img_name, apply_vbmeta);
+    return std::make_unique<FlashTask>(slot, partition, img_name, apply_vbmeta, fp);
 }
 
 std::unique_ptr<RebootTask> ParseRebootCommand(const FlashingPlan* fp,
@@ -1666,7 +1673,7 @@
 }
 
 static bool IsIgnore(const std::vector<std::string>& command) {
-    if (command[0][0] == '#') {
+    if (command.size() == 0 || command[0][0] == '#') {
         return true;
     }
     return false;
@@ -1748,16 +1755,6 @@
     return tasks;
 }
 
-std::vector<std::unique_ptr<Task>> ParseFastbootInfo(const FlashingPlan* fp, std::ifstream& fs) {
-    std::string text;
-    std::vector<std::string> file;
-    // Get os_partitions that need to be resized
-    while (std::getline(fs, text)) {
-        file.emplace_back(text);
-    }
-    return ParseFastbootInfo(fp, file);
-}
-
 FlashAllTool::FlashAllTool(FlashingPlan* fp) : fp_(fp) {}
 
 void FlashAllTool::Flash() {
@@ -1777,16 +1774,17 @@
 
     CancelSnapshotIfNeeded();
 
-    std::string path = find_item_given_name("fastboot-info.txt");
-    std::ifstream stream(path);
-    if (!stream || stream.eof()) {
+    std::vector<char> contents;
+    if (!fp_->source->ReadFile("fastboot-info.txt", &contents)) {
         LOG(VERBOSE) << "Flashing from hardcoded images. fastboot-info.txt is empty or does not "
                         "exist";
         HardcodedFlash();
         return;
     }
 
-    std::vector<std::unique_ptr<Task>> tasks = ParseFastbootInfo(fp_, stream);
+    std::vector<std::unique_ptr<Task>> tasks =
+            ParseFastbootInfo(fp_, Split({contents.data(), contents.size()}, "\n"));
+
     if (tasks.empty()) {
         LOG(FATAL) << "Invalid fastboot-info.txt file.";
     }
@@ -2115,7 +2113,7 @@
 }
 
 static bool wipe_super(const android::fs_mgr::LpMetadata& metadata, const std::string& slot,
-                       std::string* message) {
+                       std::string* message, const FlashingPlan* fp) {
     auto super_device = GetMetadataSuperBlockDevice(metadata);
     auto block_size = metadata.geometry.logical_block_size;
     auto super_bdev_name = android::fs_mgr::GetBlockDevicePartitionName(*super_device);
@@ -2155,7 +2153,7 @@
 
         auto image_path = temp_dir.path + "/"s + image_name;
         auto flash = [&](const std::string& partition_name) {
-            do_flash(partition_name.c_str(), image_path.c_str(), false);
+            do_flash(partition_name.c_str(), image_path.c_str(), false, fp);
         };
         do_for_partitions(partition, slot, flash, force_slot);
 
@@ -2164,7 +2162,8 @@
     return true;
 }
 
-static void do_wipe_super(const std::string& image, const std::string& slot_override) {
+static void do_wipe_super(const std::string& image, const std::string& slot_override,
+                          const FlashingPlan* fp) {
     if (access(image.c_str(), R_OK) != 0) {
         die("Could not read image: %s", image.c_str());
     }
@@ -2179,7 +2178,7 @@
     }
 
     std::string message;
-    if (!wipe_super(*metadata.get(), slot, &message)) {
+    if (!wipe_super(*metadata.get(), slot, &message, fp)) {
         die(message);
     }
 }
@@ -2476,7 +2475,7 @@
             }
             if (fname.empty()) die("cannot determine image filename for '%s'", pname.c_str());
 
-            FlashTask task(fp->slot_override, pname, fname, is_vbmeta_partition(pname));
+            FlashTask task(fp->slot_override, pname, fname, is_vbmeta_partition(pname), fp.get());
             task.Run();
         } else if (command == "flash:raw") {
             std::string partition = next_arg(&args);
@@ -2571,7 +2570,7 @@
             } else {
                 image = next_arg(&args);
             }
-            do_wipe_super(image, fp->slot_override);
+            do_wipe_super(image, fp->slot_override, fp.get());
         } else if (command == "snapshot-update") {
             std::string arg;
             if (!args.empty()) {
diff --git a/fastboot/fastboot.h b/fastboot/fastboot.h
index 80b77a0..0a1f1eb 100644
--- a/fastboot/fastboot.h
+++ b/fastboot/fastboot.h
@@ -124,7 +124,8 @@
 
 bool should_flash_in_userspace(const std::string& partition_name);
 bool is_userspace_fastboot();
-void do_flash(const char* pname, const char* fname, const bool apply_vbmeta);
+void do_flash(const char* pname, const char* fname, const bool apply_vbmeta,
+              const FlashingPlan* fp);
 void do_for_partitions(const std::string& part, const std::string& slot,
                        const std::function<void(const std::string&)>& func, bool force_slot);
 std::string find_item(const std::string& item);
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index e98effb..cb12060 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -27,8 +27,8 @@
 
 using namespace std::string_literals;
 FlashTask::FlashTask(const std::string& slot, const std::string& pname, const std::string& fname,
-                     const bool apply_vbmeta)
-    : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta) {}
+                     const bool apply_vbmeta, const FlashingPlan* fp)
+    : pname_(pname), fname_(fname), slot_(slot), apply_vbmeta_(apply_vbmeta), fp_(fp) {}
 
 void FlashTask::Run() {
     auto flash = [&](const std::string& partition) {
@@ -41,7 +41,7 @@
                 "And try again. If you are intentionally trying to "
                 "overwrite a fixed partition, use --force.");
         }
-        do_flash(partition.c_str(), fname_.c_str(), apply_vbmeta_);
+        do_flash(partition.c_str(), fname_.c_str(), apply_vbmeta_, fp_);
     };
     do_for_partitions(pname_, slot_, flash, true);
 }
diff --git a/fastboot/task.h b/fastboot/task.h
index d113f18..82e8ebf 100644
--- a/fastboot/task.h
+++ b/fastboot/task.h
@@ -46,7 +46,7 @@
 class FlashTask : public Task {
   public:
     FlashTask(const std::string& slot, const std::string& pname, const std::string& fname,
-              const bool apply_vbmeta);
+              const bool apply_vbmeta, const FlashingPlan* fp);
     virtual FlashTask* AsFlashTask() override { return this; }
 
     std::string GetPartition() { return pname_; }
@@ -60,6 +60,7 @@
     const std::string fname_;
     const std::string slot_;
     const bool apply_vbmeta_;
+    const FlashingPlan* fp_;
 };
 
 class RebootTask : public Task {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index ef436e5..f04fc8d 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -1083,7 +1083,7 @@
         return 0;
     }
 
-    auto ideal_size = std::min(super_info.size, uint64_t(s.f_frsize * s.f_bfree * 0.85));
+    auto ideal_size = std::min(super_info.size, uint64_t(uint64_t(s.f_frsize) * s.f_bfree * 0.85));
 
     // Align up to the filesystem block size.
     if (auto remainder = ideal_size % s.f_bsize; remainder > 0) {
diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp
index b9fa58c..3c012fe 100644
--- a/init/firmware_handler.cpp
+++ b/init/firmware_handler.cpp
@@ -33,6 +33,7 @@
 #include <android-base/chrono_utils.h>
 #include <android-base/file.h>
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/scopeguard.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
@@ -43,6 +44,7 @@
 using android::base::Timer;
 using android::base::Trim;
 using android::base::unique_fd;
+using android::base::WaitForProperty;
 using android::base::WriteFully;
 
 namespace android {
@@ -82,6 +84,33 @@
     return access("/dev/.booting", F_OK) == 0;
 }
 
+static bool IsApexActivated() {
+    static bool apex_activated = []() {
+        // Wait for com.android.runtime.apex activation
+        // Property name and value must be kept in sync with system/apexd/apex/apex_constants.h
+        // 60s is the default firmware sysfs fallback timeout. (/sys/class/firmware/timeout)
+        if (!WaitForProperty("apexd.status", "activated", 60s)) {
+            LOG(ERROR) << "Apexd activation wait timeout";
+            return false;
+        }
+        return true;
+    }();
+
+    return apex_activated;
+}
+
+static bool NeedsRerunExternalHandler() {
+    static bool first = true;
+
+    // Rerun external handler only on the first try and when apex is activated
+    if (first) {
+        first = false;
+        return IsApexActivated();
+    }
+
+    return first;
+}
+
 ExternalFirmwareHandler::ExternalFirmwareHandler(std::string devpath, uid_t uid, gid_t gid,
                                                  std::string handler_path)
     : devpath(std::move(devpath)), uid(uid), gid(gid), handler_path(std::move(handler_path)) {
@@ -210,6 +239,11 @@
 
             auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid,
                                              external_handler.gid, uevent);
+            if (!result.ok() && NeedsRerunExternalHandler()) {
+                auto res = RunExternalHandler(external_handler.handler_path, external_handler.uid,
+                                              external_handler.gid, uevent);
+                result = std::move(res);
+            }
             if (!result.ok()) {
                 LOG(ERROR) << "Using default firmware; External firmware handler failed: "
                            << result.error();