Otapreopt: Adapt for actual A/B

Add postinstall script for update_engine hook.

Add otapreopt_chroot as a gateway between installd and otapreopt.
Installd will fork and run otapreopt_chroot, which has the permission
to set up a chroot in /postinstall and run otapreopt from the B
partition.

Bug: 25612095
Change-Id: I4264598da00053ced87c849c738ddc0bc5437304
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
new file mode 100644
index 0000000..f7f69a9
--- /dev/null
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -0,0 +1,99 @@
+/*
+ ** Copyright 2016, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <linux/unistd.h>
+#include <sys/mount.h>
+#include <sys/wait.h>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+
+#ifndef LOG_TAG
+#define LOG_TAG "otapreopt"
+#endif
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+static int otapreopt_chroot(const int argc, char **arg) {
+    // We need to run the otapreopt tool from the postinstall partition. As such, set up a
+    // mount namespace and change root.
+
+    // Create our own mount namespace.
+    if (unshare(CLONE_NEWNS) != 0) {
+        PLOG(ERROR) << "Failed to unshare() for otapreopt.";
+        exit(200);
+    }
+
+    // Make postinstall private, so that our changes don't propagate.
+    if (mount("", "/postinstall", nullptr, MS_PRIVATE, nullptr) != 0) {
+        PLOG(ERROR) << "Failed to mount private.";
+        exit(201);
+    }
+
+    // Bind mount necessary directories.
+    constexpr const char* kBindMounts[] = {
+            "/data", "/dev", "/proc", "/sys"
+    };
+    for (size_t i = 0; i < arraysize(kBindMounts); ++i) {
+        std::string trg = StringPrintf("/postinstall%s", kBindMounts[i]);
+        if (mount(kBindMounts[i], trg.c_str(), nullptr, MS_BIND, nullptr) != 0) {
+            PLOG(ERROR) << "Failed to bind-mount " << kBindMounts[i];
+            exit(202);
+        }
+    }
+
+    // Chdir into /postinstall.
+    if (chdir("/postinstall") != 0) {
+        PLOG(ERROR) << "Unable to chdir into /postinstall.";
+        exit(203);
+    }
+
+    // Make /postinstall the root in our mount namespace.
+    if (chroot(".")  != 0) {
+        PLOG(ERROR) << "Failed to chroot";
+        exit(204);
+    }
+
+    if (chdir("/") != 0) {
+        PLOG(ERROR) << "Unable to chdir into /.";
+        exit(205);
+    }
+
+    // Now go on and run otapreopt.
+
+    const char* argv[1 + 9 + 1];
+    CHECK_EQ(argc, 10);
+    argv[0] = "/system/bin/otapreopt";
+    for (size_t i = 1; i <= 9; ++i) {
+        argv[i] = arg[i];
+    }
+    argv[10] = nullptr;
+
+    execv(argv[0], (char * const *)argv);
+    PLOG(ERROR) << "execv(OTAPREOPT) failed.";
+    exit(99);
+}
+
+}  // namespace installd
+}  // namespace android
+
+int main(const int argc, char *argv[]) {
+    return android::installd::otapreopt_chroot(argc, argv);
+}