Merge "Allow linking to libicuuc.so and libicui18n.so from executable in /data" into qt-dev
diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp
index 0fc4512..806ed8c 100644
--- a/adb/daemon/usb.cpp
+++ b/adb/daemon/usb.cpp
@@ -58,10 +58,12 @@
 static std::optional<bool> gFfsAioSupported;
 
 // Not all USB controllers support operations larger than 16k, so don't go above that.
-static constexpr size_t kUsbReadQueueDepth = 32;
+// Also, each submitted operation does an allocation in the kernel of that size, so we want to
+// minimize our queue depth while still maintaining a deep enough queue to keep the USB stack fed.
+static constexpr size_t kUsbReadQueueDepth = 8;
 static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE;
 
-static constexpr size_t kUsbWriteQueueDepth = 32;
+static constexpr size_t kUsbWriteQueueDepth = 8;
 static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE;
 
 static const char* to_string(enum usb_functionfs_event_type type) {
@@ -117,7 +119,7 @@
 
 struct IoBlock {
     bool pending = false;
-    struct iocb control;
+    struct iocb control = {};
     std::shared_ptr<Block> payload;
 
     TransferId id() const { return TransferId::from_value(control.aio_data); }
@@ -314,11 +316,13 @@
                         if (bound) {
                             LOG(WARNING) << "received FUNCTIONFS_BIND while already bound?";
                             running = false;
+                            break;
                         }
 
                         if (enabled) {
                             LOG(WARNING) << "received FUNCTIONFS_BIND while already enabled?";
                             running = false;
+                            break;
                         }
 
                         bound = true;
@@ -328,11 +332,13 @@
                         if (!bound) {
                             LOG(WARNING) << "received FUNCTIONFS_ENABLE while not bound?";
                             running = false;
+                            break;
                         }
 
                         if (enabled) {
                             LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?";
                             running = false;
+                            break;
                         }
 
                         enabled = true;
@@ -364,6 +370,33 @@
                         bound = false;
                         running = false;
                         break;
+
+                    case FUNCTIONFS_SETUP: {
+                        LOG(INFO) << "received FUNCTIONFS_SETUP control transfer: bRequestType = "
+                                  << static_cast<int>(event.u.setup.bRequestType)
+                                  << ", bRequest = " << static_cast<int>(event.u.setup.bRequest)
+                                  << ", wValue = " << static_cast<int>(event.u.setup.wValue)
+                                  << ", wIndex = " << static_cast<int>(event.u.setup.wIndex)
+                                  << ", wLength = " << static_cast<int>(event.u.setup.wLength);
+
+                        if ((event.u.setup.bRequestType & USB_DIR_IN)) {
+                            LOG(WARNING) << "received a device-to-host control transfer, ignoring";
+                        } else {
+                            std::string buf;
+                            buf.resize(event.u.setup.wLength + 1);
+
+                            ssize_t rc = adb_read(control_fd_.get(), buf.data(), buf.size());
+                            if (rc != event.u.setup.wLength) {
+                                LOG(ERROR)
+                                        << "read " << rc
+                                        << " bytes when trying to read control request, expected "
+                                        << event.u.setup.wLength;
+                            }
+
+                            LOG(INFO) << "control request contents: " << buf;
+                            break;
+                        }
+                    }
                 }
             }
 
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index f8f7eb3..c8caa67 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -1177,6 +1177,10 @@
     if (!is_userspace_fastboot()) {
         die("Failed to boot into userspace fastboot; one or more components might be unbootable.");
     }
+
+    // Reset target_sparse_limit after reboot to userspace fastboot. Max
+    // download sizes may differ in bootloader and fastbootd.
+    target_sparse_limit = -1;
 }
 
 class ImageSource {
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index ff918a7..a1d69d2 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -244,16 +244,29 @@
 // Testing creation/resize/delete of logical partitions
 TEST_F(LogicalPartitionCompliance, CreateResizeDeleteLP) {
     ASSERT_TRUE(UserSpaceFastboot());
+    std::string test_partition_name = "test_partition";
+    std::string slot_count;
+    // Add suffix to test_partition_name if device is slotted.
+    EXPECT_EQ(fb->GetVar("slot-count", &slot_count), SUCCESS) << "getvar slot-count failed";
+    int32_t num_slots = strtol(slot_count.c_str(), nullptr, 10);
+    if (num_slots > 0) {
+        std::string current_slot;
+        EXPECT_EQ(fb->GetVar("current-slot", &current_slot), SUCCESS)
+                << "getvar current-slot failed";
+        std::string slot_suffix = "_" + current_slot;
+        test_partition_name += slot_suffix;
+    }
+
     GTEST_LOG_(INFO) << "Testing 'fastboot create-logical-partition' command";
-    EXPECT_EQ(fb->CreatePartition("test_partition_a", "0"), SUCCESS)
+    EXPECT_EQ(fb->CreatePartition(test_partition_name, "0"), SUCCESS)
             << "create-logical-partition failed";
     GTEST_LOG_(INFO) << "Testing 'fastboot resize-logical-partition' command";
-    EXPECT_EQ(fb->ResizePartition("test_partition_a", "4096"), SUCCESS)
+    EXPECT_EQ(fb->ResizePartition(test_partition_name, "4096"), SUCCESS)
             << "resize-logical-partition failed";
     std::vector<char> buf(4096);
 
     GTEST_LOG_(INFO) << "Flashing a logical partition..";
-    EXPECT_EQ(fb->FlashPartition("test_partition_a", buf), SUCCESS)
+    EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), SUCCESS)
             << "flash logical -partition failed";
     GTEST_LOG_(INFO) << "Rebooting to bootloader mode";
     // Reboot to bootloader mode and attempt to flash the logical partitions
@@ -262,7 +275,7 @@
     ReconnectFastbootDevice();
     ASSERT_FALSE(UserSpaceFastboot());
     GTEST_LOG_(INFO) << "Attempt to flash a logical partition..";
-    EXPECT_EQ(fb->FlashPartition("test_partition", buf), DEVICE_FAIL)
+    EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), DEVICE_FAIL)
             << "flash logical partition must fail in bootloader";
     GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode";
     fb->RebootTo("fastboot");
@@ -270,7 +283,7 @@
     ReconnectFastbootDevice();
     ASSERT_TRUE(UserSpaceFastboot());
     GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command";
-    EXPECT_EQ(fb->DeletePartition("test_partition_a"), SUCCESS)
+    EXPECT_EQ(fb->DeletePartition(test_partition_name), SUCCESS)
             << "delete logical-partition failed";
 }
 
diff --git a/init/README.md b/init/README.md
index 929f0e4..1b8b848 100644
--- a/init/README.md
+++ b/init/README.md
@@ -414,7 +414,8 @@
 
 `class_start_post_data <serviceclass>`
 > Like `class_start`, but only considers services that were started
-  after /data was mounted. Only used for FDE devices.
+  after /data was mounted, and that were running at the time
+ `class_reset_post_data` was called. Only used for FDE devices.
 
 `class_stop <serviceclass>`
 > Stop and disable all services of the specified class if they are
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 34f229b..25f324c 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -104,35 +104,36 @@
     }
 }
 
-static Result<Success> class_start(const std::string& class_name, bool post_data_only) {
+static Result<Success> do_class_start(const BuiltinArguments& args) {
     // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1.
-    if (android::base::GetBoolProperty("persist.init.dont_start_class." + class_name, false))
+    if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false))
         return Success();
     // Starting a class does not start services which are explicitly disabled.
     // They must  be started individually.
     for (const auto& service : ServiceList::GetInstance()) {
-        if (service->classnames().count(class_name)) {
-            if (post_data_only && !service->is_post_data()) {
-                continue;
-            }
+        if (service->classnames().count(args[1])) {
             if (auto result = service->StartIfNotDisabled(); !result) {
                 LOG(ERROR) << "Could not start service '" << service->name()
-                           << "' as part of class '" << class_name << "': " << result.error();
+                           << "' as part of class '" << args[1] << "': " << result.error();
             }
         }
     }
     return Success();
 }
 
-static Result<Success> do_class_start(const BuiltinArguments& args) {
-    return class_start(args[1], false /* post_data_only */);
-}
-
 static Result<Success> do_class_start_post_data(const BuiltinArguments& args) {
     if (args.context != kInitContext) {
         return Error() << "command 'class_start_post_data' only available in init context";
     }
-    return class_start(args[1], true /* post_data_only */);
+    for (const auto& service : ServiceList::GetInstance()) {
+        if (service->classnames().count(args[1])) {
+            if (auto result = service->StartIfPostData(); !result) {
+                LOG(ERROR) << "Could not start service '" << service->name()
+                           << "' as part of class '" << args[1] << "': " << result.error();
+            }
+        }
+    }
+    return Success();
 }
 
 static Result<Success> do_class_stop(const BuiltinArguments& args) {
diff --git a/init/service.cpp b/init/service.cpp
index 2f96681..ccc37b7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -1154,10 +1154,23 @@
 
 void Service::ResetIfPostData() {
     if (post_data_) {
+        if (flags_ & SVC_RUNNING) {
+            running_at_post_data_reset_ = true;
+        }
         StopOrReset(SVC_RESET);
     }
 }
 
+Result<Success> Service::StartIfPostData() {
+    // Start the service, but only if it was started after /data was mounted,
+    // and it was still running when we reset the post-data services.
+    if (running_at_post_data_reset_) {
+        return Start();
+    }
+
+    return Success();
+}
+
 void Service::Stop() {
     StopOrReset(SVC_DISABLED);
 }
diff --git a/init/service.h b/init/service.h
index dc2b128..ae29f28 100644
--- a/init/service.h
+++ b/init/service.h
@@ -79,6 +79,7 @@
     Result<Success> ExecStart();
     Result<Success> Start();
     Result<Success> StartIfNotDisabled();
+    Result<Success> StartIfPostData();
     Result<Success> Enable();
     void Reset();
     void ResetIfPostData();
@@ -248,6 +249,8 @@
     bool pre_apexd_ = false;
 
     bool post_data_ = false;
+
+    bool running_at_post_data_reset_ = false;
 };
 
 class ServiceList {
diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp
index 6cd6b6e..92fcd1e 100644
--- a/libprocessgroup/cgroup_map.cpp
+++ b/libprocessgroup/cgroup_map.cpp
@@ -67,6 +67,13 @@
     return controller_ != nullptr;
 }
 
+bool CgroupController::IsUsable() const {
+    if (!HasValue()) return false;
+
+    uint32_t flags = ACgroupController_getFlags(controller_);
+    return (flags & CGROUPRC_CONTROLLER_FLAG_MOUNTED) != 0;
+}
+
 std::string CgroupController::GetTasksFilePath(const std::string& rel_path) const {
     std::string tasks_path = path();
 
@@ -153,6 +160,7 @@
         const ACgroupController* controller = ACgroupFile_getController(i);
         LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver "
                   << ACgroupController_getVersion(controller) << " path "
+                  << ACgroupController_getFlags(controller) << " flags "
                   << ACgroupController_getPath(controller);
     }
 }
diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h
index d765e60..9350412 100644
--- a/libprocessgroup/cgroup_map.h
+++ b/libprocessgroup/cgroup_map.h
@@ -38,6 +38,7 @@
     const char* path() const;
 
     bool HasValue() const;
+    bool IsUsable() const;
 
     std::string GetTasksFilePath(const std::string& path) const;
     std::string GetProcsFilePath(const std::string& path, uid_t uid, pid_t pid) const;
diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp
index 6848620..9d5afeb 100644
--- a/libprocessgroup/cgrouprc/Android.bp
+++ b/libprocessgroup/cgrouprc/Android.bp
@@ -42,19 +42,19 @@
         "libcgrouprc_format",
     ],
     stubs: {
-        symbol_file: "libcgrouprc.map.txt",
+        symbol_file: "libcgrouprc.llndk.txt",
         versions: ["29"],
     },
     target: {
         linux: {
-            version_script: "libcgrouprc.map.txt",
+            version_script: "libcgrouprc.llndk.txt",
         },
     },
 }
 
 llndk_library {
     name: "libcgrouprc",
-    symbol_file: "libcgrouprc.map.txt",
+    symbol_file: "libcgrouprc.llndk.txt",
     export_include_dirs: [
         "include",
     ],
diff --git a/libprocessgroup/cgrouprc/cgroup_controller.cpp b/libprocessgroup/cgrouprc/cgroup_controller.cpp
index d064d31..5a326e5 100644
--- a/libprocessgroup/cgrouprc/cgroup_controller.cpp
+++ b/libprocessgroup/cgrouprc/cgroup_controller.cpp
@@ -27,6 +27,11 @@
     return controller->version();
 }
 
+uint32_t ACgroupController_getFlags(const ACgroupController* controller) {
+    CHECK(controller != nullptr);
+    return controller->flags();
+}
+
 const char* ACgroupController_getName(const ACgroupController* controller) {
     CHECK(controller != nullptr);
     return controller->name();
diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
index 4edd239..ffc9f0b 100644
--- a/libprocessgroup/cgrouprc/include/android/cgrouprc.h
+++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h
@@ -66,6 +66,18 @@
         __INTRODUCED_IN(29);
 
 /**
+ * Flag bitmask used in ACgroupController_getFlags
+ */
+#define CGROUPRC_CONTROLLER_FLAG_MOUNTED 0x1
+
+/**
+ * Returns the flags bitmask of the given controller.
+ * If the given controller is null, return 0.
+ */
+__attribute__((warn_unused_result)) uint32_t ACgroupController_getFlags(const ACgroupController*)
+        __INTRODUCED_IN(29);
+
+/**
  * Returns the name of the given controller.
  * If the given controller is null, return nullptr.
  */
diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.llndk.txt
similarity index 88%
rename from libprocessgroup/cgrouprc/libcgrouprc.map.txt
rename to libprocessgroup/cgrouprc/libcgrouprc.llndk.txt
index 91df392..ea3df33 100644
--- a/libprocessgroup/cgrouprc/libcgrouprc.map.txt
+++ b/libprocessgroup/cgrouprc/libcgrouprc.llndk.txt
@@ -4,6 +4,7 @@
     ACgroupFile_getControllerCount;
     ACgroupFile_getController;
     ACgroupController_getVersion;
+    ACgroupController_getFlags;
     ACgroupController_getName;
     ACgroupController_getPath;
   local:
diff --git a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
index 877eed8..202b23e 100644
--- a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
+++ b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp
@@ -20,12 +20,19 @@
 namespace cgrouprc {
 namespace format {
 
-CgroupController::CgroupController(uint32_t version, const std::string& name,
-                                   const std::string& path) {
+CgroupController::CgroupController() : version_(0), flags_(0) {
+    memset(name_, 0, sizeof(name_));
+    memset(path_, 0, sizeof(path_));
+}
+
+CgroupController::CgroupController(uint32_t version, uint32_t flags, const std::string& name,
+                                   const std::string& path)
+    : CgroupController() {
     // strlcpy isn't available on host. Although there is an implementation
     // in licutils, libcutils itself depends on libcgrouprc_format, causing
     // a circular dependency.
     version_ = version;
+    flags_ = flags;
     strncpy(name_, name.c_str(), sizeof(name_) - 1);
     name_[sizeof(name_) - 1] = '\0';
     strncpy(path_, path.c_str(), sizeof(path_) - 1);
@@ -36,6 +43,10 @@
     return version_;
 }
 
+uint32_t CgroupController::flags() const {
+    return flags_;
+}
+
 const char* CgroupController::name() const {
     return name_;
 }
@@ -44,6 +55,10 @@
     return path_;
 }
 
+void CgroupController::set_flags(uint32_t flags) {
+    flags_ = flags;
+}
+
 }  // namespace format
 }  // namespace cgrouprc
 }  // namespace android
diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
index 64c7532..40d8548 100644
--- a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
+++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h
@@ -26,18 +26,23 @@
 // Minimal controller description to be mmapped into process address space
 struct CgroupController {
   public:
-    CgroupController() {}
-    CgroupController(uint32_t version, const std::string& name, const std::string& path);
+    CgroupController();
+    CgroupController(uint32_t version, uint32_t flags, const std::string& name,
+                     const std::string& path);
 
     uint32_t version() const;
+    uint32_t flags() const;
     const char* name() const;
     const char* path() const;
 
+    void set_flags(uint32_t flags);
+
   private:
     static constexpr size_t CGROUP_NAME_BUF_SZ = 16;
     static constexpr size_t CGROUP_PATH_BUF_SZ = 32;
 
     uint32_t version_;
+    uint32_t flags_;
     char name_[CGROUP_NAME_BUF_SZ];
     char path_[CGROUP_PATH_BUF_SZ];
 };
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 1485ae9..d3ac26b 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -106,8 +106,7 @@
 }
 
 static bool isMemoryCgroupSupported() {
-    std::string cgroup_name;
-    static bool memcg_supported = CgroupMap::GetInstance().FindController("memory").HasValue();
+    static bool memcg_supported = CgroupMap::GetInstance().FindController("memory").IsUsable();
 
     return memcg_supported;
 }
diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp
index fe4f93b..15f8139 100644
--- a/libprocessgroup/sched_policy.cpp
+++ b/libprocessgroup/sched_policy.cpp
@@ -151,19 +151,19 @@
 }
 
 bool cpusets_enabled() {
-    static bool enabled = (CgroupMap::GetInstance().FindController("cpuset").HasValue());
+    static bool enabled = (CgroupMap::GetInstance().FindController("cpuset").IsUsable());
     return enabled;
 }
 
 bool schedboost_enabled() {
-    static bool enabled = (CgroupMap::GetInstance().FindController("schedtune").HasValue());
+    static bool enabled = (CgroupMap::GetInstance().FindController("schedtune").IsUsable());
     return enabled;
 }
 
 static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) {
     auto controller = CgroupMap::GetInstance().FindController(subsys);
 
-    if (!controller.HasValue()) return -1;
+    if (!controller.IsUsable()) return -1;
 
     if (!controller.GetTaskGroup(tid, &subgroup)) {
         LOG(ERROR) << "Failed to find cgroup for tid " << tid;
diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h
index 597060e..f029c4f 100644
--- a/libprocessgroup/setup/cgroup_descriptor.h
+++ b/libprocessgroup/setup/cgroup_descriptor.h
@@ -32,6 +32,8 @@
     std::string uid() const { return uid_; }
     std::string gid() const { return gid_; }
 
+    void set_mounted(bool mounted);
+
   private:
     format::CgroupController controller_;
     mode_t mode_ = 0;
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index da60948..17ea06e 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -35,6 +35,7 @@
 #include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/unique_fd.h>
+#include <android/cgrouprc.h>
 #include <json/reader.h>
 #include <json/value.h>
 #include <processgroup/format/cgroup_file.h>
@@ -267,7 +268,17 @@
 CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name,
                                    const std::string& path, mode_t mode, const std::string& uid,
                                    const std::string& gid)
-    : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {}
+    : controller_(version, 0, name, path), mode_(mode), uid_(uid), gid_(gid) {}
+
+void CgroupDescriptor::set_mounted(bool mounted) {
+    uint32_t flags = controller_.flags();
+    if (mounted) {
+        flags |= CGROUPRC_CONTROLLER_FLAG_MOUNTED;
+    } else {
+        flags &= ~CGROUPRC_CONTROLLER_FLAG_MOUNTED;
+    }
+    controller_.set_flags(flags);
+}
 
 }  // namespace cgrouprc
 }  // namespace android
@@ -296,10 +307,11 @@
     }
 
     // setup cgroups
-    for (const auto& [name, descriptor] : descriptors) {
-        if (!SetupCgroup(descriptor)) {
+    for (auto& [name, descriptor] : descriptors) {
+        if (SetupCgroup(descriptor)) {
+            descriptor.set_mounted(true);
+        } else {
             // issue a warning and proceed with the next cgroup
-            // TODO: mark the descriptor as invalid and skip it in WriteRcFile()
             LOG(WARNING) << "Failed to setup " << name << " cgroup";
         }
     }
diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt
index dc69920..2ac54e9 100644
--- a/rootdir/etc/ld.config.txt
+++ b/rootdir/etc/ld.config.txt
@@ -177,6 +177,7 @@
 namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
 
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
+namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%
@@ -625,6 +626,7 @@
 namespace.media.asan.search.paths = /apex/com.android.media/${LIB}
 
 namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors
+namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors
 
 namespace.media.links = default
 namespace.media.link.default.shared_libs  = %LLNDK_LIBRARIES%