Make otapreopt_chroot setup linker

Without the linker setup we are unable to run dex2oat. This change
mounts a tmpfs for the chroot and uses linkerconfig to fill it in
after the chroot has occurred.

Test: Manual OTA on cuttlefish
Bug: 181182967
Change-Id: Ied4e6f6e367db89720e98f29d4ae22f19c9cb968
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index fb07840..46c3fd7 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -185,6 +185,13 @@
     // want it for product APKs. Same notes as vendor above.
     TryExtraMount("product", arg[2], "/postinstall/product");
 
+    constexpr const char* kPostInstallLinkerconfig = "/postinstall/linkerconfig";
+    // Try to mount /postinstall/linkerconfig. we will set it up after performing the chroot
+    if (mount("tmpfs", kPostInstallLinkerconfig, "tmpfs", 0, nullptr) != 0) {
+        PLOG(ERROR) << "Failed to mount a tmpfs for " << kPostInstallLinkerconfig;
+        exit(215);
+    }
+
     // Setup APEX mount point and its security context.
     static constexpr const char* kPostinstallApexDir = "/postinstall/apex";
     // The following logic is similar to the one in system/core/rootdir/init.rc:
@@ -246,14 +253,33 @@
 
     // Check that an ART APEX has been activated; clean up and exit
     // early otherwise.
-    if (std::none_of(active_packages.begin(),
-                     active_packages.end(),
-                     [](const apex::ApexFile& package){
-                         return package.GetManifest().name() == "com.android.art";
-                     })) {
-        LOG(FATAL_WITHOUT_ABORT) << "No activated com.android.art APEX package.";
-        DeactivateApexPackages(active_packages);
-        exit(217);
+    static constexpr const std::string_view kRequiredApexs[] = {
+      "com.android.art",
+      "com.android.runtime",
+    };
+    for (std::string_view apex : kRequiredApexs) {
+        if (std::none_of(active_packages.begin(), active_packages.end(),
+                         [&](const apex::ApexFile& package) {
+                             return package.GetManifest().name() == apex;
+                         })) {
+            LOG(FATAL_WITHOUT_ABORT) << "No activated " << apex << " APEX package.";
+            DeactivateApexPackages(active_packages);
+            exit(217);
+        }
+    }
+
+    // Setup /linkerconfig. Doing it after the chroot means it doesn't need its own category
+    if (selinux_android_restorecon("/linkerconfig", 0) < 0) {
+        PLOG(ERROR) << "Failed to restorecon /linkerconfig";
+        exit(219);
+    }
+    std::vector<std::string> linkerconfig_cmd{"/apex/com.android.runtime/bin/linkerconfig",
+                                              "--target", "/linkerconfig"};
+    std::string linkerconfig_error_msg;
+    bool linkerconfig_exec_result = Exec(linkerconfig_cmd, &linkerconfig_error_msg);
+    if (!linkerconfig_exec_result) {
+        LOG(ERROR) << "Running linkerconfig failed: " << linkerconfig_error_msg;
+        exit(218);
     }
 
     // Now go on and run otapreopt.