Merge "fastboot: Fix IPv6 connect and -s host parsing"
diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp
index 895c111..4d60ddb 100644
--- a/debuggerd/debuggerd_test.cpp
+++ b/debuggerd/debuggerd_test.cpp
@@ -1680,6 +1680,24 @@
   if (params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
   p[params.access_offset] = 42;
   if (!params.free_before_access) free(static_cast<void*>(const_cast<char*>(p)));
+
+  bool recoverable = std::get<1>(GetParam());
+  ASSERT_TRUE(recoverable);  // Non-recoverable should have crashed.
+
+  // As we're in recoverable mode, trigger another 2x use-after-frees (ensuring
+  // we end with at least one in a different slot), make sure the process still
+  // doesn't crash.
+  p = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
+  char* volatile p2 = reinterpret_cast<char* volatile>(malloc(params.alloc_size));
+  free(static_cast<void*>(const_cast<char*>(p)));
+  free(static_cast<void*>(const_cast<char*>(p2)));
+  *p = 42;
+  *p2 = 42;
+
+  // Under clang coverage (which is a default TEST_MAPPING presubmit target), the
+  // recoverable+seccomp tests fail because the minijail prevents some atexit syscalls that clang
+  // coverage does. Thus, skip the atexit handlers.
+  _exit(0);
 }
 
 TEST_F(CrasherTest, fdsan_warning_abort_message) {
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 602ba01..5dac3f5 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1123,7 +1123,9 @@
     unique_fd fd(TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_BINARY)));
 
     if (fd == -1) {
-        return false;
+        auto path = find_item_given_name(fname);
+        fd = unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_BINARY)));
+        if (fd == -1) return false;
     }
 
     struct stat s;
@@ -2167,10 +2169,6 @@
     android::base::InitLogging(argv, FastbootLogger, FastbootAborter);
 
     bool wants_wipe = false;
-    bool wants_reboot = false;
-    bool wants_reboot_bootloader = false;
-    bool wants_reboot_recovery = false;
-    bool wants_reboot_fastboot = false;
     bool skip_reboot = false;
     bool wants_set_active = false;
     bool skip_secondary = false;
@@ -2359,7 +2357,7 @@
             }
         }
     }
-
+    std::unique_ptr<Task> reboot_task = nullptr;
     std::vector<std::string> args(argv, argv + argc);
     while (!args.empty()) {
         std::string command = next_arg(&args);
@@ -2411,30 +2409,19 @@
             fb->Download("signature", data);
             fb->RawCommand("signature", "installing signature");
         } else if (command == FB_CMD_REBOOT) {
-            wants_reboot = true;
-
             if (args.size() == 1) {
-                std::string what = next_arg(&args);
-                if (what == "bootloader") {
-                    wants_reboot = false;
-                    wants_reboot_bootloader = true;
-                } else if (what == "recovery") {
-                    wants_reboot = false;
-                    wants_reboot_recovery = true;
-                } else if (what == "fastboot") {
-                    wants_reboot = false;
-                    wants_reboot_fastboot = true;
-                } else {
-                    syntax_error("unknown reboot target %s", what.c_str());
-                }
+                std::string reboot_target = next_arg(&args);
+                reboot_task = std::make_unique<RebootTask>(fb, reboot_target);
+            } else {
+                reboot_task = std::make_unique<RebootTask>(fb);
             }
             if (!args.empty()) syntax_error("junk after reboot command");
         } else if (command == FB_CMD_REBOOT_BOOTLOADER) {
-            wants_reboot_bootloader = true;
+            reboot_task = std::make_unique<RebootTask>(fb, "bootloader");
         } else if (command == FB_CMD_REBOOT_RECOVERY) {
-            wants_reboot_recovery = true;
+            reboot_task = std::make_unique<RebootTask>(fb, "recovery");
         } else if (command == FB_CMD_REBOOT_FASTBOOT) {
-            wants_reboot_fastboot = true;
+            reboot_task = std::make_unique<RebootTask>(fb, "fastboot");
         } else if (command == FB_CMD_CONTINUE) {
             fb->Continue();
         } else if (command == FB_CMD_BOOT) {
@@ -2478,7 +2465,7 @@
             } else {
                 do_flashall(slot_override, skip_secondary, wants_wipe, force_flash);
             }
-            wants_reboot = true;
+            reboot_task = std::make_unique<RebootTask>(fb);
         } else if (command == "update") {
             bool slot_all = (slot_override == "all");
             if (slot_all) {
@@ -2490,7 +2477,7 @@
                 filename = next_arg(&args);
             }
             do_update(filename.c_str(), slot_override, skip_secondary || slot_all, force_flash);
-            wants_reboot = true;
+            reboot_task = std::make_unique<RebootTask>(fb);
         } else if (command == FB_CMD_SET_ACTIVE) {
             std::string slot = verify_slot(next_arg(&args), false);
             fb->SetActive(slot);
@@ -2562,7 +2549,6 @@
             syntax_error("unknown command %s", command.c_str());
         }
     }
-
     if (wants_wipe) {
         if (force_flash) {
             CancelSnapshotIfNeeded();
@@ -2581,19 +2567,9 @@
     if (wants_set_active) {
         fb->SetActive(next_active);
     }
-    if (wants_reboot && !skip_reboot) {
-        fb->Reboot();
-        fb->WaitForDisconnect();
-    } else if (wants_reboot_bootloader) {
-        fb->RebootTo("bootloader");
-        fb->WaitForDisconnect();
-    } else if (wants_reboot_recovery) {
-        fb->RebootTo("recovery");
-        fb->WaitForDisconnect();
-    } else if (wants_reboot_fastboot) {
-        reboot_to_userspace_fastboot();
+    if (reboot_task && !skip_reboot) {
+        reboot_task->Run();
     }
-
     fprintf(stderr, "Finished. Total time: %.3fs\n", (now() - start));
 
     auto* old_transport = fb->set_transport(nullptr);
diff --git a/fastboot/task.cpp b/fastboot/task.cpp
index 3f33c76..94dd5c3 100644
--- a/fastboot/task.cpp
+++ b/fastboot/task.cpp
@@ -14,6 +14,8 @@
 // limitations under the License.
 //
 #include "task.h"
+#include "fastboot.h"
+#include "util.h"
 
 #include "fastboot.h"
 #include "util.h"
@@ -44,3 +46,27 @@
     };
     do_for_partitions(pname_, slot_, flash, true);
 }
+
+RebootTask::RebootTask(fastboot::FastBootDriver* _fb) : fb_(_fb){};
+RebootTask::RebootTask(fastboot::FastBootDriver* _fb, std::string _reboot_target)
+    : reboot_target_(std::move(_reboot_target)), fb_(_fb){};
+
+void RebootTask::Run() {
+    if ((reboot_target_ == "userspace" || reboot_target_ == "fastboot")) {
+        if (!is_userspace_fastboot()) {
+            reboot_to_userspace_fastboot();
+            fb_->WaitForDisconnect();
+        }
+    } else if (reboot_target_ == "recovery") {
+        fb_->RebootTo("recovery");
+        fb_->WaitForDisconnect();
+    } else if (reboot_target_ == "bootloader") {
+        fb_->RebootTo("bootloader");
+        fb_->WaitForDisconnect();
+    } else if (reboot_target_ == "") {
+        fb_->Reboot();
+        fb_->WaitForDisconnect();
+    } else {
+        syntax_error("unknown reboot target %s", reboot_target_.c_str());
+    }
+}
diff --git a/fastboot/task.h b/fastboot/task.h
index 216e658..582fa2f 100644
--- a/fastboot/task.h
+++ b/fastboot/task.h
@@ -18,9 +18,7 @@
 #include <sstream>
 #include <string>
 
-#include "fastboot.h"
 #include "fastboot_driver.h"
-#include "util.h"
 
 class Task {
   public:
@@ -46,3 +44,15 @@
     const std::string slot_;
     bool force_flash_ = false;
 };
+
+class RebootTask : public Task {
+  public:
+    RebootTask(fastboot::FastBootDriver* _fb);
+    RebootTask(fastboot::FastBootDriver* _fb, const std::string _reboot_target);
+    void Run() override;
+    ~RebootTask() {}
+
+  private:
+    const std::string reboot_target_ = "";
+    fastboot::FastBootDriver* fb_;
+};
\ No newline at end of file
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index b3763ae..fa04c43 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -108,6 +108,12 @@
 
     // Estimated COW size from OTA manifest.
     uint64 estimated_cow_size = 12;
+
+    // Enable multi-threaded compression
+    bool enable_threading = 13;
+
+    // Enable batching for COW writes
+    bool batched_writes = 14;
 }
 
 // Next: 8
diff --git a/fs_mgr/libsnapshot/partition_cow_creator.h b/fs_mgr/libsnapshot/partition_cow_creator.h
index 949e6c5..bd5c8cb 100644
--- a/fs_mgr/libsnapshot/partition_cow_creator.h
+++ b/fs_mgr/libsnapshot/partition_cow_creator.h
@@ -60,6 +60,12 @@
     bool using_snapuserd = false;
     std::string compression_algorithm;
 
+    // True if multi-threaded compression should be enabled
+    bool enable_threading;
+
+    // True if COW writes should be batched in memory
+    bool batched_writes;
+
     struct Return {
         SnapshotStatus snapshot_status;
         std::vector<Interval> cow_partition_usable_regions;
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 961db02..15f025c 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -400,6 +400,12 @@
     status->set_metadata_sectors(0);
     status->set_using_snapuserd(cow_creator->using_snapuserd);
     status->set_compression_algorithm(cow_creator->compression_algorithm);
+    if (cow_creator->enable_threading) {
+        status->set_enable_threading(cow_creator->enable_threading);
+    }
+    if (cow_creator->batched_writes) {
+        status->set_batched_writes(cow_creator->batched_writes);
+    }
 
     if (!WriteSnapshotStatus(lock, *status)) {
         PLOG(ERROR) << "Could not write snapshot status: " << status->name();
@@ -3248,6 +3254,12 @@
             .using_snapuserd = using_snapuserd,
             .compression_algorithm = compression_algorithm,
     };
+    if (dap_metadata.vabc_feature_set().has_threaded()) {
+        cow_creator.enable_threading = dap_metadata.vabc_feature_set().threaded();
+    }
+    if (dap_metadata.vabc_feature_set().has_batch_writes()) {
+        cow_creator.batched_writes = dap_metadata.vabc_feature_set().batch_writes();
+    }
 
     auto ret = CreateUpdateSnapshotsInternal(lock.get(), manifest, &cow_creator, &created_devices,
                                              &all_snapshot_status);
@@ -3635,6 +3647,8 @@
     CowOptions cow_options;
     cow_options.compression = status.compression_algorithm();
     cow_options.max_blocks = {status.device_size() / cow_options.block_size};
+    cow_options.batch_write = status.batched_writes();
+    cow_options.num_compress_threads = status.enable_threading() ? 2 : 0;
     // Disable scratch space for vts tests
     if (device()->IsTestDevice()) {
         cow_options.scratch_space = false;
diff --git a/fs_mgr/libsnapshot/update_engine/update_metadata.proto b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
index 69d72e1..cc12d1d 100644
--- a/fs_mgr/libsnapshot/update_engine/update_metadata.proto
+++ b/fs_mgr/libsnapshot/update_engine/update_metadata.proto
@@ -71,11 +71,18 @@
     repeated string partition_names = 3;
 }
 
+message VABCFeatureSet {
+  optional bool threaded = 1;
+  optional bool batch_writes = 2;
+}
+
 message DynamicPartitionMetadata {
     repeated DynamicPartitionGroup groups = 1;
     optional bool vabc_enabled = 3;
     optional string vabc_compression_param = 4;
     optional uint32 cow_version = 5;
+    // A collection of knobs to tune Virtual AB Compression
+    optional VABCFeatureSet vabc_feature_set = 6;
 }
 
 message DeltaArchiveManifest {
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index b180a58..66e1e63 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -392,12 +392,13 @@
         mHealthInfo->batteryFullChargeDesignCapacityUah =
                 getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
 
-    if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
-        mHealthInfo->batteryStateOfHealth = getIntField(mHealthdConfig->batteryStateOfHealthPath);
-
     if (!mHealthdConfig->batteryHealthStatusPath.isEmpty())
         mBatteryHealthStatus = getIntField(mHealthdConfig->batteryHealthStatusPath);
 
+    if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
+        mHealthInfo->batteryHealthData->batteryStateOfHealth =
+                getIntField(mHealthdConfig->batteryStateOfHealthPath);
+
     if (!mHealthdConfig->batteryManufacturingDatePath.isEmpty())
         mHealthInfo->batteryHealthData->batteryManufacturingDateSeconds =
                 getIntField(mHealthdConfig->batteryManufacturingDatePath);
@@ -591,6 +592,10 @@
         if (!mHealthdConfig->batteryFirstUsageDatePath.isEmpty())
             return getIntField(mHealthdConfig->batteryFirstUsageDatePath);
     }
+    if (id == BATTERY_PROP_STATE_OF_HEALTH) {
+        if (!mHealthdConfig->batteryStateOfHealthPath.isEmpty())
+            return getIntField(mHealthdConfig->batteryStateOfHealthPath);
+    }
     return 0;
 }
 
@@ -669,6 +674,11 @@
         ret = OK;
         break;
 
+    case BATTERY_PROP_STATE_OF_HEALTH:
+        val->valueInt64 = getBatteryHealthData(BATTERY_PROP_STATE_OF_HEALTH);
+        ret = OK;
+        break;
+
     default:
         break;
     }
diff --git a/init/action.cpp b/init/action.cpp
index 1e998ae..18f6360 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -30,7 +30,7 @@
 
 Result<void> RunBuiltinFunction(const BuiltinFunction& function,
                                 const std::vector<std::string>& args, const std::string& context) {
-    auto builtin_arguments = BuiltinArguments(context);
+    BuiltinArguments builtin_arguments{.context = context};
 
     builtin_arguments.args.resize(args.size());
     builtin_arguments.args[0] = args[0];
@@ -69,7 +69,7 @@
 }
 
 Result<void> Command::CheckCommand() const {
-    auto builtin_arguments = BuiltinArguments("host_init_verifier");
+    BuiltinArguments builtin_arguments{.context = "host_init_verifier"};
 
     builtin_arguments.args.resize(args_.size());
     builtin_arguments.args[0] = args_[0];
diff --git a/init/builtin_arguments.h b/init/builtin_arguments.h
index 1742b78..890a216 100644
--- a/init/builtin_arguments.h
+++ b/init/builtin_arguments.h
@@ -24,10 +24,6 @@
 namespace init {
 
 struct BuiltinArguments {
-    BuiltinArguments(const std::string& context) : context(context) {}
-    BuiltinArguments(std::vector<std::string> args, const std::string& context)
-        : args(std::move(args)), context(context) {}
-
     const std::string& operator[](std::size_t i) const { return args[i]; }
     auto begin() const { return args.begin(); }
     auto end() const { return args.end(); }
diff --git a/init/builtins.cpp b/init/builtins.cpp
index a89813e..bc23972 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1074,7 +1074,7 @@
 static Result<void> do_restorecon_recursive(const BuiltinArguments& args) {
     std::vector<std::string> non_const_args(args.args);
     non_const_args.insert(std::next(non_const_args.begin()), "--recursive");
-    return do_restorecon({std::move(non_const_args), args.context});
+    return do_restorecon({.args = std::move(non_const_args), .context = args.context});
 }
 
 static Result<void> do_loglevel(const BuiltinArguments& args) {
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index 481fa31..461ed22 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -85,7 +85,7 @@
 }
 
 Result<void> check_exec_reboot_on_failure(const BuiltinArguments& args) {
-    BuiltinArguments remaining_args(args.context);
+    BuiltinArguments remaining_args{.context = args.context};
 
     remaining_args.args = std::vector<std::string>(args.begin() + 1, args.end());
     remaining_args.args[0] = args[0];
diff --git a/init/init.cpp b/init/init.cpp
index f964c60..c965fe6 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -51,6 +51,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
+#include <android-base/thread_annotations.h>
 #include <fs_avb/fs_avb.h>
 #include <fs_mgr_vendor_overlay.h>
 #include <keyutils.h>
@@ -211,16 +212,16 @@
     }
 
   private:
-    void ResetWaitForPropLocked() {
+    void ResetWaitForPropLocked() EXCLUSIVE_LOCKS_REQUIRED(lock_) {
         wait_prop_name_.clear();
         wait_prop_value_.clear();
         waiting_for_prop_.reset();
     }
 
     std::mutex lock_;
-    std::unique_ptr<Timer> waiting_for_prop_{nullptr};
-    std::string wait_prop_name_;
-    std::string wait_prop_value_;
+    GUARDED_BY(lock_) std::unique_ptr<Timer> waiting_for_prop_{nullptr};
+    GUARDED_BY(lock_) std::string wait_prop_name_;
+    GUARDED_BY(lock_) std::string wait_prop_value_;
 
 } prop_waiter_state;
 
@@ -259,7 +260,7 @@
 
   private:
     std::mutex shutdown_command_lock_;
-    std::string shutdown_command_;
+    std::string shutdown_command_ GUARDED_BY(shutdown_command_lock_);
     bool do_shutdown_ = false;
 } shutdown_state;
 
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 4cc00fe..062ed39 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -897,29 +897,31 @@
             continue;
         }
 
-        auto system_entry = GetEntryForMountPoint(&fstab, "/system");
-        if (!system_entry) {
-            LOG(ERROR) << "Could not find mount entry for /system";
-            break;
-        }
-        if (!system_entry->fs_mgr_flags.logical) {
-            LOG(INFO) << "Skipping mount of " << name << ", system is not dynamic.";
-            break;
-        }
+        auto system_entries = GetEntriesForMountPoint(&fstab, "/system");
+        for (auto& system_entry : system_entries) {
+            if (!system_entry) {
+                LOG(ERROR) << "Could not find mount entry for /system";
+                break;
+            }
+            if (!system_entry->fs_mgr_flags.logical) {
+                LOG(INFO) << "Skipping mount of " << name << ", system is not dynamic.";
+                break;
+            }
 
-        auto entry = *system_entry;
-        auto partition_name = name + fs_mgr_get_slot_suffix();
-        auto replace_name = "system"s + fs_mgr_get_slot_suffix();
+            auto entry = *system_entry;
+            auto partition_name = name + fs_mgr_get_slot_suffix();
+            auto replace_name = "system"s + fs_mgr_get_slot_suffix();
 
-        entry.mount_point = "/"s + name;
-        entry.blk_device =
+            entry.mount_point = "/"s + name;
+            entry.blk_device =
                 android::base::StringReplace(entry.blk_device, replace_name, partition_name, false);
-        if (!fs_mgr_update_logical_partition(&entry)) {
-            LOG(ERROR) << "Could not update logical partition";
-            continue;
-        }
+            if (!fs_mgr_update_logical_partition(&entry)) {
+                LOG(ERROR) << "Could not update logical partition";
+                continue;
+            }
 
-        extra_fstab.emplace_back(std::move(entry));
+            extra_fstab.emplace_back(std::move(entry));
+        }
     }
 
     SkipMountingPartitions(&extra_fstab, true /* verbose */);
diff --git a/init/service.cpp b/init/service.cpp
index 87d9c3a..cce24c3 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -755,6 +755,9 @@
 
     NotifyStateChange("running");
     reboot_on_failure.Disable();
+
+    LOG(INFO) << "... started service '" << name_ << "' has pid " << pid_;
+
     return {};
 }
 
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1da69ba..384a8f0 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -406,18 +406,15 @@
                 pids.emplace(pid);
             }
         }
-        if (file_is_empty) {
-            // This happens when process is already dead
-            return 0;
-        }
-
-        // Erase all pids that will be killed when we kill the process groups.
-        for (auto it = pids.begin(); it != pids.end();) {
-            pid_t pgid = getpgid(*it);
-            if (pgids.count(pgid) == 1) {
-                it = pids.erase(it);
-            } else {
-                ++it;
+        if (!file_is_empty) {
+            // Erase all pids that will be killed when we kill the process groups.
+            for (auto it = pids.begin(); it != pids.end();) {
+                pid_t pgid = getpgid(*it);
+                if (pgids.count(pgid) == 1) {
+                    it = pids.erase(it);
+                } else {
+                    ++it;
+                }
             }
         }
     }
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2929da4..68191bb 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -925,6 +925,10 @@
     mkdir /data/system/dropbox 0700 system system
     mkdir /data/system/heapdump 0700 system system
     mkdir /data/system/users 0775 system system
+    # Mkdir and set SELinux security contexts for shutdown-checkpoints.
+    # TODO(b/270286197): remove these after couple releases.
+    mkdir /data/system/shutdown-checkpoints 0700 system system
+    restorecon_recursive /data/system/shutdown-checkpoints
 
     # Create the parent directories of the user CE and DE storage directories.
     # These parent directories must use encryption=None, since each of their
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index f767d40..09f696b 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -76,6 +76,7 @@
     KM_CLEAR_ATTESTATION_CERT_CHAIN = (0xa000 << KEYMASTER_REQ_SHIFT),
     KM_SET_WRAPPED_ATTESTATION_KEY = (0xb000 << KEYMASTER_REQ_SHIFT),
     KM_SET_ATTESTATION_IDS = (0xc000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_ATTESTATION_IDS_KM3 = (0xc001 << KEYMASTER_REQ_SHIFT),
     KM_CONFIGURE_BOOT_PATCHLEVEL = (0xd000 << KEYMASTER_REQ_SHIFT),
 };