Remove the ability to generate an image in image_space.cc
In mainline, on-device signing will create image space upon APEX update.
Bug: 160683548
Test: m test-art-host-gtest && art/test.py --host -r
Change-Id: I6498336512040c922a545d6362acec3326220f77
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index af63f68..a91a6ec 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -50,7 +50,6 @@
#include "gc/accounting/space_bitmap-inl.h"
#include "gc/task_processor.h"
#include "image-inl.h"
-#include "image_space_fs.h"
#include "intern_table-inl.h"
#include "mirror/class-inl.h"
#include "mirror/executable-inl.h"
@@ -116,92 +115,6 @@
return ChooseRelocationOffsetDelta(ART_BASE_ADDRESS_MIN_DELTA, ART_BASE_ADDRESS_MAX_DELTA);
}
-static bool GenerateImage(const std::string& image_filename,
- InstructionSet image_isa,
- std::string* error_msg) {
- Runtime* runtime = Runtime::Current();
- const std::vector<std::string>& boot_class_path = runtime->GetBootClassPath();
- if (boot_class_path.empty()) {
- *error_msg = "Failed to generate image because no boot class path specified";
- return false;
- }
- // We should clean up so we are more likely to have room for the image.
- if (Runtime::Current()->IsZygote()) {
- LOG(INFO) << "Pruning dalvik-cache since we are generating an image and will need to recompile";
- PruneDalvikCache(image_isa);
- }
-
- std::vector<std::string> arg_vector;
-
- std::string dex2oat(Runtime::Current()->GetCompilerExecutable());
- arg_vector.push_back(dex2oat);
-
- char* dex2oat_bcp = getenv("DEX2OATBOOTCLASSPATH");
- std::vector<std::string> dex2oat_bcp_vector;
- if (dex2oat_bcp != nullptr) {
- arg_vector.push_back("--runtime-arg");
- arg_vector.push_back(StringPrintf("-Xbootclasspath:%s", dex2oat_bcp));
- Split(dex2oat_bcp, ':', &dex2oat_bcp_vector);
- }
-
- std::string image_option_string("--image=");
- image_option_string += image_filename;
- arg_vector.push_back(image_option_string);
-
- if (!dex2oat_bcp_vector.empty()) {
- for (size_t i = 0u; i < dex2oat_bcp_vector.size(); i++) {
- arg_vector.push_back(std::string("--dex-file=") + dex2oat_bcp_vector[i]);
- arg_vector.push_back(std::string("--dex-location=") + dex2oat_bcp_vector[i]);
- }
- } else {
- const std::vector<std::string>& boot_class_path_locations =
- runtime->GetBootClassPathLocations();
- DCHECK_EQ(boot_class_path.size(), boot_class_path_locations.size());
- for (size_t i = 0u; i < boot_class_path.size(); i++) {
- arg_vector.push_back(std::string("--dex-file=") + boot_class_path[i]);
- arg_vector.push_back(std::string("--dex-location=") + boot_class_path_locations[i]);
- }
- }
-
- std::string oat_file_option_string("--oat-file=");
- oat_file_option_string += ImageHeader::GetOatLocationFromImageLocation(image_filename);
- arg_vector.push_back(oat_file_option_string);
-
- // Note: we do not generate a fully debuggable boot image so we do not pass the
- // compiler flag --debuggable here.
-
- Runtime::Current()->AddCurrentRuntimeFeaturesAsDex2OatArguments(&arg_vector);
- CHECK_EQ(image_isa, kRuntimeISA)
- << "We should always be generating an image for the current isa.";
-
- int32_t base_offset = ChooseRelocationOffsetDelta();
- LOG(INFO) << "Using an offset of 0x" << std::hex << base_offset << " from default "
- << "art base address of 0x" << std::hex << ART_BASE_ADDRESS;
- arg_vector.push_back(StringPrintf("--base=0x%x", ART_BASE_ADDRESS + base_offset));
-
- if (!kIsTargetBuild) {
- arg_vector.push_back("--host");
- }
-
- // Check if there is a boot profile, and pass it to dex2oat.
- if (OS::FileExists("/system/etc/boot-image.prof")) {
- arg_vector.push_back("--profile-file=/system/etc/boot-image.prof");
- } else {
- // We will compile the boot image with compiler filter "speed" unless overridden below.
- LOG(WARNING) << "Missing boot-image.prof file, /system/etc/boot-image.prof not found: "
- << strerror(errno);
- }
-
- const std::vector<std::string>& compiler_options = Runtime::Current()->GetImageCompilerOptions();
- for (size_t i = 0; i < compiler_options.size(); ++i) {
- arg_vector.push_back(compiler_options[i].c_str());
- }
-
- std::string command_line(Join(arg_vector, ' '));
- LOG(INFO) << "GenerateImage: " << command_line;
- return Exec(arg_vector, error_msg);
-}
-
static bool FindImageFilenameImpl(const char* image_location,
const InstructionSet image_isa,
bool* has_system,
@@ -307,36 +220,6 @@
return hdr;
}
-static bool CanWriteToDalvikCache(const InstructionSet isa) {
- const std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(isa));
- if (access(dalvik_cache.c_str(), O_RDWR) == 0) {
- return true;
- } else if (errno != EACCES) {
- PLOG(WARNING) << "CanWriteToDalvikCache returned error other than EACCES";
- }
- return false;
-}
-
-static bool ImageCreationAllowed(bool is_global_cache,
- const InstructionSet isa,
- bool is_zygote,
- std::string* error_msg) {
- // Anyone can write into a "local" cache.
- if (!is_global_cache) {
- return true;
- }
-
- // Only the zygote running as root is allowed to create the global boot image.
- // If the zygote is running as non-root (and cannot write to the dalvik-cache),
- // then image creation is not allowed..
- if (is_zygote) {
- return CanWriteToDalvikCache(isa);
- }
-
- *error_msg = "Only the zygote can create the global boot image.";
- return false;
-}
-
void ImageSpace::VerifyImageAllocations() {
uint8_t* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
while (current < End()) {
@@ -3517,41 +3400,6 @@
return image_header != nullptr;
}
-static constexpr uint64_t kLowSpaceValue = 50 * MB;
-static constexpr uint64_t kTmpFsSentinelValue = 384 * MB;
-
-// Read the free space of the cache partition and make a decision whether to keep the generated
-// image. This is to try to mitigate situations where the system might run out of space later.
-static bool CheckSpace(const std::string& cache_filename, std::string* error_msg) {
- // Using statvfs vs statvfs64 because of b/18207376, and it is enough for all practical purposes.
- struct statvfs buf;
-
- int res = TEMP_FAILURE_RETRY(statvfs(cache_filename.c_str(), &buf));
- if (res != 0) {
- // Could not stat. Conservatively tell the system to delete the image.
- *error_msg = "Could not stat the filesystem, assuming low-memory situation.";
- return false;
- }
-
- uint64_t fs_overall_size = buf.f_bsize * static_cast<uint64_t>(buf.f_blocks);
- // Zygote is privileged, but other things are not. Use bavail.
- uint64_t fs_free_size = buf.f_bsize * static_cast<uint64_t>(buf.f_bavail);
-
- // Take the overall size as an indicator for a tmpfs, which is being used for the decryption
- // environment. We do not want to fail quickening the boot image there, as it is beneficial
- // for time-to-UI.
- if (fs_overall_size > kTmpFsSentinelValue) {
- if (fs_free_size < kLowSpaceValue) {
- *error_msg = StringPrintf("Low-memory situation: only %4.2f megabytes available, need at "
- "least %" PRIu64 ".",
- static_cast<double>(fs_free_size) / MB,
- kLowSpaceValue / MB);
- return false;
- }
- }
- return true;
-}
-
bool ImageSpace::LoadBootImage(
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
@@ -3583,36 +3431,8 @@
relocate,
executable,
is_zygote);
-
- // Step 0: Extra zygote work.
-
loader.FindImageFiles();
- // Step 0.a: If we're the zygote, check for free space, and prune the cache preemptively,
- // if necessary. While the runtime may be fine (it is pretty tolerant to
- // out-of-disk-space situations), other parts of the platform are not.
- //
- // The advantage of doing this proactively is that the later steps are simplified,
- // i.e., we do not need to code retries.
- bool low_space = false;
- if (loader.IsZygote() && loader.DalvikCacheExists()) {
- // Extra checks for the zygote. These only apply when loading the first image, explained below.
- const std::string& dalvik_cache = loader.GetDalvikCache();
- DCHECK(!dalvik_cache.empty());
- std::string local_error_msg;
- bool check_space = CheckSpace(dalvik_cache, &local_error_msg);
- if (!check_space) {
- LOG(WARNING) << local_error_msg << " Preemptively pruning the dalvik cache.";
- PruneDalvikCache(image_isa);
-
- // Re-evaluate the image.
- loader.FindImageFiles();
-
- // Disable compilation/patching - we do not want to fill up the space again.
- low_space = true;
- }
- }
-
// Collect all the errors.
std::vector<std::string> error_msgs;
@@ -3660,39 +3480,6 @@
}
}
- // Step 3: We do not have an existing image in /system,
- // so generate an image into the dalvik cache.
- if (!loader.HasSystem() && loader.DalvikCacheExists()) {
- std::string local_error_msg;
- if (low_space || !Runtime::Current()->IsImageDex2OatEnabled()) {
- local_error_msg = "Image compilation disabled.";
- } else if (ImageCreationAllowed(loader.IsGlobalCache(),
- image_isa,
- is_zygote,
- &local_error_msg)) {
- bool compilation_success =
- GenerateImage(loader.GetCacheFilename(), image_isa, &local_error_msg);
- if (compilation_success) {
- if (loader.LoadFromDalvikCache(/*validate_oat_file=*/ false,
- extra_reservation_size,
- boot_image_spaces,
- extra_reservation,
- &local_error_msg)) {
- return true;
- }
- }
- }
- error_msgs.push_back(StringPrintf("Cannot compile image to %s: %s",
- loader.GetCacheFilename().c_str(),
- local_error_msg.c_str()));
- }
-
- // We failed. Prune the cache the free up space, create a compound error message
- // and return false.
- if (loader.DalvikCacheExists()) {
- PruneDalvikCache(image_isa);
- }
-
std::ostringstream oss;
bool first = true;
for (const auto& msg : error_msgs) {
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
deleted file mode 100644
index c491893..0000000
--- a/runtime/gc/space/image_space_fs.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-#ifndef ART_RUNTIME_GC_SPACE_IMAGE_SPACE_FS_H_
-#define ART_RUNTIME_GC_SPACE_IMAGE_SPACE_FS_H_
-
-#include <dirent.h>
-#include <dlfcn.h>
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-
-#include "base/file_utils.h"
-#include "base/logging.h" // For VLOG.
-#include "base/macros.h"
-#include "base/os.h"
-#include "base/unix_file/fd_file.h"
-#include "base/utils.h"
-#include "runtime.h"
-#include "runtime_globals.h"
-
-namespace art {
-namespace gc {
-namespace space {
-
-// This file contains helper code for ImageSpace. It has most of the file-system
-// related code, including handling A/B OTA.
-
-namespace impl {
-
-// Delete the directory and its (regular or link) contents. If the recurse flag is true, delete
-// sub-directories recursively.
-static void DeleteDirectoryContents(const std::string& dir, bool recurse) {
- if (!OS::DirectoryExists(dir.c_str())) {
- return;
- }
- DIR* c_dir = opendir(dir.c_str());
- if (c_dir == nullptr) {
- PLOG(WARNING) << "Unable to open " << dir << " to delete it's contents";
- return;
- }
-
- for (struct dirent* de = readdir(c_dir); de != nullptr; de = readdir(c_dir)) {
- const char* name = de->d_name;
- if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) {
- continue;
- }
- // We only want to delete regular files and symbolic links.
- std::string file = android::base::StringPrintf("%s/%s", dir.c_str(), name);
- if (de->d_type != DT_REG && de->d_type != DT_LNK) {
- if (de->d_type == DT_DIR) {
- if (recurse) {
- DeleteDirectoryContents(file, recurse);
- // Try to rmdir the directory.
- if (rmdir(file.c_str()) != 0) {
- PLOG(ERROR) << "Unable to rmdir " << file;
- }
- }
- } else {
- LOG(WARNING) << "Unexpected file type of " << std::hex << de->d_type << " encountered.";
- }
- } else {
- // Try to unlink the file.
- if (unlink(file.c_str()) != 0) {
- PLOG(ERROR) << "Unable to unlink " << file;
- }
- }
- }
- CHECK_EQ(0, closedir(c_dir)) << "Unable to close directory.";
-}
-
-} // namespace impl
-
-
-// We are relocating or generating the core image. We should get rid of everything. It is all
-// out-of-date. We also don't really care if this fails since it is just a convenience.
-// Adapted from prune_dex_cache(const char* subdir) in frameworks/native/cmds/installd/commands.c
-// Note this should only be used during first boot.
-static void PruneDalvikCache(InstructionSet isa) {
- CHECK_NE(isa, InstructionSet::kNone);
- // Prune the base /data/dalvik-cache.
- // Note: GetDalvikCache may return the empty string if the directory doesn't
- // exist. It is safe to pass "" to DeleteDirectoryContents, so this is okay.
- impl::DeleteDirectoryContents(GetDalvikCache("."), false);
- // Prune /data/dalvik-cache/<isa>.
- impl::DeleteDirectoryContents(GetDalvikCache(GetInstructionSetString(isa)), false);
-
- // Be defensive. There should be a runtime created here, but this may be called in a test.
- if (Runtime::Current() != nullptr) {
- Runtime::Current()->SetPrunedDalvikCache(true);
- }
-}
-
-} // namespace space
-} // namespace gc
-} // namespace art
-
-#endif // ART_RUNTIME_GC_SPACE_IMAGE_SPACE_FS_H_
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index efd82d9..02b959c 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -35,8 +35,6 @@
class ImageSpaceTest : public CommonRuntimeTest {
protected:
void SetUpRuntimeOptions(RuntimeOptions* options) override {
- // Disable implicit dex2oat invocations when loading image spaces.
- options->emplace_back("-Xnoimage-dex2oat", nullptr);
// Disable relocation.
options->emplace_back("-Xnorelocate", nullptr);
}
@@ -371,7 +369,7 @@
}
}
-template <bool kImage, bool kRelocate, bool kImageDex2oat>
+template <bool kImage, bool kRelocate>
class ImageSpaceLoadingTest : public CommonRuntimeTest {
protected:
void SetUpRuntimeOptions(RuntimeOptions* options) override {
@@ -383,7 +381,6 @@
options->emplace_back(android::base::StringPrintf("-Ximage:%s", image_location.c_str()),
nullptr);
options->emplace_back(kRelocate ? "-Xrelocate" : "-Xnorelocate", nullptr);
- options->emplace_back(kImageDex2oat ? "-Ximage-dex2oat" : "-Xnoimage-dex2oat", nullptr);
// We want to test the relocation behavior of ImageSpace. As such, don't pretend we're a
// compiler.
@@ -414,22 +411,17 @@
UniqueCPtr<const char[]> old_dex2oat_bcp_;
};
-using ImageSpaceDex2oatTest = ImageSpaceLoadingTest<false, true, true>;
-TEST_F(ImageSpaceDex2oatTest, Test) {
- EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
-}
-
-using ImageSpaceNoDex2oatTest = ImageSpaceLoadingTest<true, true, false>;
+using ImageSpaceNoDex2oatTest = ImageSpaceLoadingTest<true, true>;
TEST_F(ImageSpaceNoDex2oatTest, Test) {
EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
}
-using ImageSpaceNoRelocateNoDex2oatTest = ImageSpaceLoadingTest<true, false, false>;
+using ImageSpaceNoRelocateNoDex2oatTest = ImageSpaceLoadingTest<true, false>;
TEST_F(ImageSpaceNoRelocateNoDex2oatTest, Test) {
EXPECT_FALSE(Runtime::Current()->GetHeap()->GetBootImageSpaces().empty());
}
-class NoAccessAndroidDataTest : public ImageSpaceLoadingTest<false, true, true> {
+class NoAccessAndroidDataTest : public ImageSpaceLoadingTest<false, true> {
protected:
NoAccessAndroidDataTest() : quiet_(LogSeverity::FATAL) {}
@@ -450,11 +442,11 @@
CHECK_NE(fd, -1) << strerror(errno);
result = close(fd);
CHECK_EQ(result, 0) << strerror(errno);
- ImageSpaceLoadingTest<false, true, true>::SetUpRuntimeOptions(options);
+ ImageSpaceLoadingTest<false, true>::SetUpRuntimeOptions(options);
}
void TearDown() override {
- ImageSpaceLoadingTest<false, true, true>::TearDown();
+ ImageSpaceLoadingTest<false, true>::TearDown();
int result = unlink(bad_dalvik_cache_.c_str());
CHECK_EQ(result, 0) << strerror(errno);
result = rmdir(bad_android_data_.c_str());