Merge changes from topics "runtime-apex-otapreopt_chroot-tear-down", "runtime-apex-installd-support", "runtime-apex-otapreopt_chroot-support"
* changes:
Implement a tear-down phase in otapreopt_chroot.
Revert^2 "Have installd use ART binaries from the Android Runtime APEX."
Revert^2 "Have `otapreopt_chroot` mount APEX packages in the chroot dir."
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index f574752..dd69bd0 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -137,10 +137,23 @@
],
clang: true,
- srcs: ["otapreopt_chroot.cpp"],
+ srcs: [
+ "otapreopt_chroot.cpp",
+ "otapreopt_utils.cpp",
+ ],
shared_libs: [
"libbase",
"liblog",
+ "libprotobuf-cpp-full",
+ "libselinux",
+ "libziparchive",
+ ],
+ static_libs: [
+ "libapex",
+ "libapexd",
+ "lib_apex_manifest_proto",
+ "libavb",
+ "libdm",
],
}
@@ -188,6 +201,7 @@
"dexopt.cpp",
"globals.cpp",
"otapreopt.cpp",
+ "otapreopt_utils.cpp",
"utils.cpp",
"view_compiler.cpp",
],
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 10110a8..748bf15 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -332,8 +332,8 @@
MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
// If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
- const char* dex2oat_bin = "/system/bin/dex2oat";
- constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+ const char* dex2oat_bin = "/apex/com.android.runtime/bin/dex2oat";
+ constexpr const char* kDex2oatDebugPath = "/apex/com.android.runtime/bin/dex2oatd";
// Do not use dex2oatd for release candidates (give dex2oat more soak time).
bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
if (is_debug_runtime() ||
@@ -642,7 +642,9 @@
bool copy_and_update,
bool store_aggregation_counters) {
const char* profman_bin =
- is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+ is_debug_runtime()
+ ? "/apex/com.android.runtime/bin/profmand"
+ : "/apex/com.android.runtime/bin/profman";
if (copy_and_update) {
CHECK_EQ(1u, profile_fds.size());
@@ -1458,9 +1460,9 @@
const char* class_loader_context) {
CHECK_GE(zip_fd, 0);
const char* dexoptanalyzer_bin =
- is_debug_runtime()
- ? "/system/bin/dexoptanalyzerd"
- : "/system/bin/dexoptanalyzer";
+ is_debug_runtime()
+ ? "/apex/com.android.runtime/bin/dexoptanalyzerd"
+ : "/apex/com.android.runtime/bin/dexoptanalyzer";
std::string dex_file_arg = "--dex-file=" + dex_file;
std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index b2e7047..05c8538 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -26,7 +26,6 @@
#include <sys/capability.h>
#include <sys/prctl.h>
#include <sys/stat.h>
-#include <sys/wait.h>
#include <android-base/logging.h>
#include <android-base/macros.h>
@@ -58,7 +57,6 @@
#define REPLY_MAX 256 /* largest reply allowed */
using android::base::EndsWith;
-using android::base::Join;
using android::base::Split;
using android::base::StartsWith;
using android::base::StringPrintf;
@@ -440,7 +438,7 @@
const char* isa) const {
// This needs to be kept in sync with ART, see art/runtime/gc/space/image_space.cc.
std::vector<std::string> cmd;
- cmd.push_back("/system/bin/dex2oat");
+ cmd.push_back("/apex/com.android.runtime/bin/dex2oat");
cmd.push_back(StringPrintf("--image=%s", art_path.c_str()));
for (const std::string& boot_part : Split(boot_cp, ":")) {
cmd.push_back(StringPrintf("--dex-file=%s", boot_part.c_str()));
@@ -619,61 +617,6 @@
// Helpers, mostly taken from ART //
////////////////////////////////////
- // Wrapper on fork/execv to run a command in a subprocess.
- static bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
- const std::string command_line = Join(arg_vector, ' ');
-
- CHECK_GE(arg_vector.size(), 1U) << command_line;
-
- // Convert the args to char pointers.
- const char* program = arg_vector[0].c_str();
- std::vector<char*> args;
- for (size_t i = 0; i < arg_vector.size(); ++i) {
- const std::string& arg = arg_vector[i];
- char* arg_str = const_cast<char*>(arg.c_str());
- CHECK(arg_str != nullptr) << i;
- args.push_back(arg_str);
- }
- args.push_back(nullptr);
-
- // Fork and exec.
- pid_t pid = fork();
- if (pid == 0) {
- // No allocation allowed between fork and exec.
-
- // Change process groups, so we don't get reaped by ProcessManager.
- setpgid(0, 0);
-
- execv(program, &args[0]);
-
- PLOG(ERROR) << "Failed to execv(" << command_line << ")";
- // _exit to avoid atexit handlers in child.
- _exit(1);
- } else {
- if (pid == -1) {
- *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
- command_line.c_str(), strerror(errno));
- return false;
- }
-
- // wait for subprocess to finish
- int status;
- pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
- if (got_pid != pid) {
- *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
- "wanted %d, got %d: %s",
- command_line.c_str(), pid, got_pid, strerror(errno));
- return false;
- }
- if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
- *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
- command_line.c_str());
- return false;
- }
- }
- return true;
- }
-
// Choose a random relocation offset. Taken from art/runtime/gc/image_space.cc.
static int32_t ChooseRelocationOffsetDelta(int32_t min_delta, int32_t max_delta) {
constexpr size_t kPageSize = PAGE_SIZE;
diff --git a/cmds/installd/otapreopt_chroot.cpp b/cmds/installd/otapreopt_chroot.cpp
index e90cf3b..9965d58 100644
--- a/cmds/installd/otapreopt_chroot.cpp
+++ b/cmds/installd/otapreopt_chroot.cpp
@@ -17,6 +17,7 @@
#include <fcntl.h>
#include <linux/unistd.h>
#include <sys/mount.h>
+#include <sys/stat.h>
#include <sys/wait.h>
#include <sstream>
@@ -24,6 +25,9 @@
#include <android-base/logging.h>
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
+#include <selinux/android.h>
+
+#include <apexd.h>
#include "installd_constants.h"
#include "otapreopt_utils.h"
@@ -138,6 +142,33 @@
UNUSED(product_result);
}
+ // 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:
+ //
+ // mount tmpfs tmpfs /apex nodev noexec nosuid
+ // chmod 0755 /apex
+ // chown root root /apex
+ // restorecon /apex
+ //
+ if (mount("tmpfs", kPostinstallApexDir, "tmpfs", MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr)
+ != 0) {
+ PLOG(ERROR) << "Failed to mount tmpfs in " << kPostinstallApexDir;
+ exit(209);
+ }
+ if (chmod(kPostinstallApexDir, 0755) != 0) {
+ PLOG(ERROR) << "Failed to chmod " << kPostinstallApexDir << " to 0755";
+ exit(210);
+ }
+ if (chown(kPostinstallApexDir, 0, 0) != 0) {
+ PLOG(ERROR) << "Failed to chown " << kPostinstallApexDir << " to root:root";
+ exit(211);
+ }
+ if (selinux_android_restorecon(kPostinstallApexDir, 0) < 0) {
+ PLOG(ERROR) << "Failed to restorecon " << kPostinstallApexDir;
+ exit(212);
+ }
+
// Chdir into /postinstall.
if (chdir("/postinstall") != 0) {
PLOG(ERROR) << "Unable to chdir into /postinstall.";
@@ -155,22 +186,52 @@
exit(205);
}
+ // Try to mount APEX packages in "/apex" in the chroot dir. We need at least
+ // the Android Runtime APEX, as it is required by otapreopt to run dex2oat.
+ // The logic here is (partially) copied and adapted from
+ // system/apex/apexd/apexd_main.cpp.
+ //
+ // Only scan the APEX directory under /system (within the chroot dir).
+ // Note that this leaves around the loop devices created and used by
+ // libapexd's code, but this is fine, as we expect to reboot soon after.
+ apex::scanPackagesDirAndActivate(apex::kApexPackageSystemDir);
+ // Collect activated packages.
+ std::vector<apex::ApexFile> active_packages = apex::getActivePackages();
+
// Now go on and run otapreopt.
- // Incoming: cmd + status-fd + target-slot + cmd... + null | Incoming | = argc + 1
- // Outgoing: cmd + target-slot + cmd... + null | Outgoing | = argc
- const char** argv = new const char*[argc];
-
- argv[0] = "/system/bin/otapreopt";
+ // Incoming: cmd + status-fd + target-slot + cmd... | Incoming | = argc
+ // Outgoing: cmd + target-slot + cmd... | Outgoing | = argc - 1
+ std::vector<std::string> cmd;
+ cmd.reserve(argc);
+ cmd.push_back("/system/bin/otapreopt");
// The first parameter is the status file descriptor, skip.
- for (size_t i = 2; i <= static_cast<size_t>(argc); ++i) {
- argv[i - 1] = arg[i];
+ for (size_t i = 2; i < static_cast<size_t>(argc); ++i) {
+ cmd.push_back(arg[i]);
}
- execv(argv[0], static_cast<char * const *>(const_cast<char**>(argv)));
- PLOG(ERROR) << "execv(OTAPREOPT) failed.";
- exit(99);
+ // Fork and execute otapreopt in its own process.
+ std::string error_msg;
+ bool exec_result = Exec(cmd, &error_msg);
+ if (!exec_result) {
+ LOG(ERROR) << "Running otapreopt failed: " << error_msg;
+ }
+
+ // Tear down the work down by the apexd logic above (i.e. deactivate packages).
+ for (const apex::ApexFile& apex_file : active_packages) {
+ const std::string& package_path = apex_file.GetPath();
+ apex::Status status = apex::deactivatePackage(package_path);
+ if (!status.Ok()) {
+ LOG(ERROR) << "Failed to deactivate " << package_path << ": " << status.ErrorMessage();
+ }
+ }
+
+ if (!exec_result) {
+ exit(213);
+ }
+
+ return 0;
}
} // namespace installd
diff --git a/cmds/installd/otapreopt_utils.cpp b/cmds/installd/otapreopt_utils.cpp
new file mode 100644
index 0000000..124f726
--- /dev/null
+++ b/cmds/installd/otapreopt_utils.cpp
@@ -0,0 +1,88 @@
+/*
+ ** Copyright 2019, 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 "otapreopt_utils.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+using android::base::Join;
+using android::base::StringPrintf;
+
+namespace android {
+namespace installd {
+
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg) {
+ const std::string command_line = Join(arg_vector, ' ');
+
+ CHECK_GE(arg_vector.size(), 1U) << command_line;
+
+ // Convert the args to char pointers.
+ const char* program = arg_vector[0].c_str();
+ std::vector<char*> args;
+ for (size_t i = 0; i < arg_vector.size(); ++i) {
+ const std::string& arg = arg_vector[i];
+ char* arg_str = const_cast<char*>(arg.c_str());
+ CHECK(arg_str != nullptr) << i;
+ args.push_back(arg_str);
+ }
+ args.push_back(nullptr);
+
+ // Fork and exec.
+ pid_t pid = fork();
+ if (pid == 0) {
+ // No allocation allowed between fork and exec.
+
+ // Change process groups, so we don't get reaped by ProcessManager.
+ setpgid(0, 0);
+
+ execv(program, &args[0]);
+
+ PLOG(ERROR) << "Failed to execv(" << command_line << ")";
+ // _exit to avoid atexit handlers in child.
+ _exit(1);
+ } else {
+ if (pid == -1) {
+ *error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
+ command_line.c_str(), strerror(errno));
+ return false;
+ }
+
+ // wait for subprocess to finish
+ int status;
+ pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+ if (got_pid != pid) {
+ *error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
+ "wanted %d, got %d: %s",
+ command_line.c_str(), pid, got_pid, strerror(errno));
+ return false;
+ }
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ *error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
+ command_line.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace installd
+} // namespace android
diff --git a/cmds/installd/otapreopt_utils.h b/cmds/installd/otapreopt_utils.h
index 436e554..03a6d87 100644
--- a/cmds/installd/otapreopt_utils.h
+++ b/cmds/installd/otapreopt_utils.h
@@ -18,6 +18,8 @@
#define OTAPREOPT_UTILS_H_
#include <regex>
+#include <string>
+#include <vector>
namespace android {
namespace installd {
@@ -28,6 +30,9 @@
return std::regex_match(input, slot_suffix_match, slot_suffix_regex);
}
+// Wrapper on fork/execv to run a command in a subprocess.
+bool Exec(const std::vector<std::string>& arg_vector, std::string* error_msg);
+
} // namespace installd
} // namespace android