Merge "boot_reason: Add reasons for boot_reason_test.sh"
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index af0c89e..589b99a 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -58,7 +58,7 @@
 };
 
 // Maps BootEvent used inside bootstat into statsd atom defined in
-// frameworks/base/cmds/statsd/src/atoms.proto.
+// frameworks/proto_logging/stats/atoms.proto.
 const std::unordered_map<std::string_view, AtomInfo> kBootEventToAtomInfo = {
     // ELAPSED_TIME
     {"ro.boottime.init",
@@ -468,6 +468,13 @@
     {"watchdog,apc,bl31,crashed", 220},
     {"watchdog,apc,pbl,crashed", 221},
     {"reboot,memory_protect,hyp", 222},
+    {"reboot,tsd,pmic,main", 223},
+    {"reboot,tsd,pmic,sub", 224},
+    {"reboot,ocp,pmic,main", 225},
+    {"reboot,ocp,pmic,sub", 226},
+    {"reboot,sys_ldo_ok,pmic,main", 227},
+    {"reboot,sys_ldo_ok,pmic,sub", 228},
+    {"reboot,smpl_timeout,pmic,main", 229},
 };
 
 // Converts a string value representing the reason the system booted to an
diff --git a/fs_mgr/tests/vts_fs_test.cpp b/fs_mgr/tests/vts_fs_test.cpp
index 3f12103..ae8e459 100644
--- a/fs_mgr/tests/vts_fs_test.cpp
+++ b/fs_mgr/tests/vts_fs_test.cpp
@@ -28,8 +28,8 @@
 }
 
 TEST(fs, ErofsSupported) {
-    // U and higher for this test.
-    if (GetVsrLevel() <= __ANDROID_API_T__) {
+    // T-launch GKI kernels and higher must support EROFS.
+    if (GetVsrLevel() < __ANDROID_API_T__) {
         GTEST_SKIP();
     }
 
diff --git a/init/init.cpp b/init/init.cpp
index 4955bc5..0658942 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -442,6 +442,19 @@
     return {};
 }
 
+static void DoUnloadApex(const std::string& apex_name) {
+    std::string prop_name = "init.apex." + apex_name;
+    // TODO(b/232114573) remove services and actions read from the apex
+    // TODO(b/232799709) kill services from the apex
+    SetProperty(prop_name, "unloaded");
+}
+
+static void DoLoadApex(const std::string& apex_name) {
+    std::string prop_name = "init.apex." + apex_name;
+    // TODO(b/232799709) read .rc files from the apex
+    SetProperty(prop_name, "loaded");
+}
+
 enum class ControlTarget {
     SERVICE,    // function gets called for the named service
     INTERFACE,  // action gets called for every service that holds this interface
@@ -465,6 +478,20 @@
     return control_message_functions;
 }
 
+static bool HandleApexControlMessage(std::string_view action, const std::string& name,
+                                     std::string_view message) {
+    if (action == "load") {
+        DoLoadApex(name);
+        return true;
+    } else if (action == "unload") {
+        DoUnloadApex(name);
+        return true;
+    } else {
+        LOG(ERROR) << "Unknown control msg '" << message << "'";
+        return false;
+    }
+}
+
 static bool HandleControlMessage(std::string_view message, const std::string& name,
                                  pid_t from_pid) {
     std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid);
@@ -476,8 +503,12 @@
         process_cmdline = "unknown process";
     }
 
-    Service* service = nullptr;
     auto action = message;
+    if (ConsumePrefix(&action, "apex_")) {
+        return HandleApexControlMessage(action, name, message);
+    }
+
+    Service* service = nullptr;
     if (ConsumePrefix(&action, "interface_")) {
         service = ServiceList::GetInstance().FindInterface(name);
     } else {
diff --git a/init/init_test.cpp b/init/init_test.cpp
index 0dc6ff6..5651a83 100644
--- a/init/init_test.cpp
+++ b/init/init_test.cpp
@@ -35,6 +35,10 @@
 #include "util.h"
 
 using android::base::GetIntProperty;
+using android::base::GetProperty;
+using android::base::SetProperty;
+using android::base::WaitForProperty;
+using namespace std::literals;
 
 namespace android {
 namespace init {
@@ -334,6 +338,20 @@
     EXPECT_EQ(2, num_executed);
 }
 
+TEST(init, RespondToCtlApexMessages) {
+    if (getuid() != 0) {
+        GTEST_SKIP() << "Skipping test, must be run as root.";
+        return;
+    }
+
+    std::string apex_name = "com.android.apex.cts.shim";
+    SetProperty("ctl.apex_unload", apex_name);
+    EXPECT_TRUE(WaitForProperty("init.apex." + apex_name, "unloaded", 10s));
+
+    SetProperty("ctl.apex_load", apex_name);
+    EXPECT_TRUE(WaitForProperty("init.apex." + apex_name, "loaded", 10s));
+}
+
 TEST(init, RejectsCriticalAndOneshotService) {
     if (GetIntProperty("ro.product.first_api_level", 10000) < 30) {
         GTEST_SKIP() << "Test only valid for devices launching with R or later";
diff --git a/mkbootfs/mkbootfs.c b/mkbootfs/mkbootfs.c
index 58153f3..05d1940 100644
--- a/mkbootfs/mkbootfs.c
+++ b/mkbootfs/mkbootfs.c
@@ -24,8 +24,7 @@
 ** - device notes, pipes, etc are not supported (error)
 */
 
-void die(const char *why, ...)
-{
+static void die(const char* why, ...) {
     va_list ap;
 
     va_start(ap, why);
@@ -42,7 +41,7 @@
 };
 
 static struct fs_config_entry* canned_config = NULL;
-static char *target_out_path = NULL;
+static const char* target_out_path = NULL;
 
 /* Each line in the canned file should be a path plus three ints (uid,
  * gid, mode). */
@@ -273,8 +272,7 @@
     }
 }
 
-void archive(const char *start, const char *prefix)
-{
+static void archive(const char* start, const char* prefix) {
     char in[8192];
     char out[8192];
 
@@ -294,7 +292,7 @@
 
     char line[CANNED_LINE_LENGTH];
     FILE* f = fopen(filename, "r");
-    if (f == NULL) die("failed to open canned file");
+    if (f == NULL) die("failed to open canned file '%s'", filename);
 
     while (fgets(line, CANNED_LINE_LENGTH, f) != NULL) {
         if (!line[0]) break;
@@ -332,6 +330,13 @@
 
 int main(int argc, char *argv[])
 {
+    if (argc == 1) {
+        fprintf(stderr,
+                "usage: %s [-d TARGET_OUTPUT_PATH] [-f CANNED_CONFIGURATION_PATH] DIRECTORIES...\n",
+                argv[0]);
+        exit(1);
+    }
+
     argc--;
     argv++;
 
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 660f18c..a819c7a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -832,7 +832,6 @@
     mkdir /data/misc/odsign 0710 root system
     # directory used for odsign metrics
     mkdir /data/misc/odsign/metrics 0770 root system
-
     # Directory for VirtualizationService temporary image files.
     # Delete any stale files owned by the old virtualizationservice uid (b/230056726).
     chmod 0770 /data/misc/virtualizationservice
@@ -1041,8 +1040,7 @@
     exec_start update_verifier_nonencrypted
     start statsd
     start netd
-    start zygote
-    start zygote_secondary
+    trigger zygote-run
 
 on zygote-start && property:ro.crypto.state=unsupported
     wait_for_prop odsign.verification.done 1
@@ -1050,8 +1048,7 @@
     exec_start update_verifier_nonencrypted
     start statsd
     start netd
-    start zygote
-    start zygote_secondary
+    trigger zygote-run
 
 on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
     wait_for_prop odsign.verification.done 1
@@ -1059,6 +1056,15 @@
     exec_start update_verifier_nonencrypted
     start statsd
     start netd
+    trigger zygote-run
+
+on zygote-run && property:ro.zygote=zygote32
+    start zygote
+
+on zygote-run && property:ro.zygote=zygote64
+    start zygote
+
+on zygote-run && property:ro.zygote=zygote64_32
     start zygote
     start zygote_secondary
 
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index efb30d6..dfe1645 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -25,3 +25,4 @@
     socket usap_pool_secondary stream 660 root system
     onrestart restart zygote
     task_profiles ProcessCapacityHigh MaxPerformance
+    disabled