ART: Allow to change boot image pickup order
Allow to change the pickup order of boot image files between
system-first and data-first.
Bug: 126307038
Test: m test-art-host
Test: Boot device with image in /data/dalvik-cache
Change-Id: Id80cfc06aeb023559e1a3706833e57ba4880f43b
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index 9c0ac8f..0624525 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -120,7 +120,11 @@
EXPECT_EQ(filter, odex_file->GetCompilerFilter());
std::string boot_image_checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
- Runtime::Current()->GetBootClassPath(), image_location, kRuntimeISA, &error_msg);
+ Runtime::Current()->GetBootClassPath(),
+ image_location,
+ kRuntimeISA,
+ gc::space::ImageSpaceLoadingOrder::kSystemFirst,
+ &error_msg);
ASSERT_FALSE(boot_image_checksums.empty()) << error_msg;
const OatHeader& oat_header = odex_file->GetOatHeader();
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5c171e6..6f72740 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -205,7 +205,8 @@
bool use_generational_cc,
uint64_t min_interval_homogeneous_space_compaction_by_oom,
bool dump_region_info_before_gc,
- bool dump_region_info_after_gc)
+ bool dump_region_info_after_gc,
+ space::ImageSpaceLoadingOrder image_space_loading_order)
: non_moving_space_(nullptr),
rosalloc_space_(nullptr),
dlmalloc_space_(nullptr),
@@ -370,6 +371,7 @@
boot_class_path_locations,
image_file_name,
image_instruction_set,
+ image_space_loading_order,
heap_reservation_size,
&boot_image_spaces,
&heap_reservation)) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 18dfbf5..898a51c 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -35,6 +35,7 @@
#include "gc/collector/iteration.h"
#include "gc/collector_type.h"
#include "gc/gc_cause.h"
+#include "gc/space/image_space_loading_order.h"
#include "gc/space/large_object_space.h"
#include "handle.h"
#include "obj_ptr.h"
@@ -215,7 +216,8 @@
bool use_generational_cc,
uint64_t min_interval_homogeneous_space_compaction_by_oom,
bool dump_region_info_before_gc,
- bool dump_region_info_after_gc);
+ bool dump_region_info_after_gc,
+ space::ImageSpaceLoadingOrder image_space_loading_order);
~Heap();
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 4a2dbf5..173e879 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -259,6 +259,7 @@
std::unique_ptr<ImageHeader> ImageSpace::ReadImageHeader(const char* image_location,
const InstructionSet image_isa,
+ ImageSpaceLoadingOrder order,
std::string* error_msg) {
std::string system_filename;
bool has_system = false;
@@ -274,10 +275,20 @@
&dalvik_cache_exists,
&has_cache,
&is_global_cache)) {
- if (has_system) {
- return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
- } else if (has_cache) {
- return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
+ if (order == ImageSpaceLoadingOrder::kSystemFirst) {
+ if (has_system) {
+ return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
+ }
+ if (has_cache) {
+ return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
+ }
+ } else {
+ if (has_cache) {
+ return ReadSpecificImageHeader(cache_filename.c_str(), error_msg);
+ }
+ if (has_system) {
+ return ReadSpecificImageHeader(system_filename.c_str(), error_msg);
+ }
}
}
@@ -1447,7 +1458,8 @@
return cache_filename_;
}
- bool LoadFromSystem(size_t extra_reservation_size,
+ bool LoadFromSystem(bool validate_oat_file,
+ size_t extra_reservation_size,
/*out*/std::vector<std::unique_ptr<space::ImageSpace>>* boot_image_spaces,
/*out*/MemMap* extra_reservation,
/*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1455,7 +1467,7 @@
std::string filename = GetSystemImageFilename(image_location_.c_str(), image_isa_);
if (!LoadFromFile(filename,
- /*validate_oat_file=*/ false,
+ validate_oat_file,
extra_reservation_size,
&logger,
boot_image_spaces,
@@ -2020,6 +2032,7 @@
const std::vector<std::string>& boot_class_path_locations,
const std::string& image_location,
const InstructionSet image_isa,
+ ImageSpaceLoadingOrder order,
size_t extra_reservation_size,
/*out*/std::vector<std::unique_ptr<space::ImageSpace>>* boot_image_spaces,
/*out*/MemMap* extra_reservation) {
@@ -2076,30 +2089,41 @@
// Collect all the errors.
std::vector<std::string> error_msgs;
- // Step 1: Check if we have an existing image in /system.
+ auto try_load_from = [&](auto has_fn, auto load_fn, bool validate_oat_file) {
+ if ((loader.*has_fn)()) {
+ std::string local_error_msg;
+ if ((loader.*load_fn)(validate_oat_file,
+ extra_reservation_size,
+ boot_image_spaces,
+ extra_reservation,
+ &local_error_msg)) {
+ return true;
+ }
+ error_msgs.push_back(local_error_msg);
+ }
+ return false;
+ };
- if (loader.HasSystem()) {
- std::string local_error_msg;
- if (loader.LoadFromSystem(extra_reservation_size,
- boot_image_spaces,
- extra_reservation,
- &local_error_msg)) {
+ auto try_load_from_system = [&]() {
+ return try_load_from(&BootImageLoader::HasSystem, &BootImageLoader::LoadFromSystem, false);
+ };
+ auto try_load_from_cache = [&]() {
+ return try_load_from(&BootImageLoader::HasCache, &BootImageLoader::LoadFromDalvikCache, true);
+ };
+
+ auto invoke_sequentially = [](auto first, auto second) {
+ return first() || second();
+ };
+
+ // Step 1+2: Check system and cache images in the asked-for order.
+ if (order == ImageSpaceLoadingOrder::kSystemFirst) {
+ if (invoke_sequentially(try_load_from_system, try_load_from_cache)) {
return true;
}
- error_msgs.push_back(local_error_msg);
- }
-
- // Step 2: Check if we have an existing image in the dalvik cache.
- if (loader.HasCache()) {
- std::string local_error_msg;
- if (loader.LoadFromDalvikCache(/*validate_oat_file=*/ true,
- extra_reservation_size,
- boot_image_spaces,
- extra_reservation,
- &local_error_msg)) {
+ } else {
+ if (invoke_sequentially(try_load_from_cache, try_load_from_system)) {
return true;
}
- error_msgs.push_back(local_error_msg);
}
// Step 3: We do not have an existing image in /system,
@@ -2259,6 +2283,7 @@
std::string ImageSpace::GetBootClassPathChecksums(const std::vector<std::string>& boot_class_path,
const std::string& image_location,
InstructionSet image_isa,
+ ImageSpaceLoadingOrder order,
/*out*/std::string* error_msg) {
std::string system_filename;
bool has_system = false;
@@ -2281,7 +2306,9 @@
}
DCHECK(has_system || has_cache);
- const std::string& filename = has_system ? system_filename : cache_filename;
+ const std::string& filename = (order == ImageSpaceLoadingOrder::kSystemFirst)
+ ? (has_system ? system_filename : cache_filename)
+ : (has_cache ? cache_filename : system_filename);
std::unique_ptr<ImageHeader> header = ReadSpecificImageHeader(filename.c_str(), error_msg);
if (header == nullptr) {
return std::string();
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index bb19097..1c61f06 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -19,6 +19,7 @@
#include "gc/accounting/space_bitmap.h"
#include "image.h"
+#include "image_space_loading_order.h"
#include "space.h"
namespace art {
@@ -48,6 +49,7 @@
const std::vector<std::string>& boot_class_path_locations,
const std::string& image_location,
const InstructionSet image_isa,
+ ImageSpaceLoadingOrder order,
size_t extra_reservation_size,
/*out*/std::vector<std::unique_ptr<space::ImageSpace>>* boot_image_spaces,
/*out*/MemMap* extra_reservation) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -63,6 +65,7 @@
// reason in error_msg.
static std::unique_ptr<ImageHeader> ReadImageHeader(const char* image_location,
InstructionSet image_isa,
+ ImageSpaceLoadingOrder order,
std::string* error_msg);
// Give access to the OatFile.
@@ -132,6 +135,7 @@
static std::string GetBootClassPathChecksums(const std::vector<std::string>& boot_class_path,
const std::string& image_location,
InstructionSet image_isa,
+ ImageSpaceLoadingOrder order,
/*out*/std::string* error_msg);
// Returns the checksums for the boot image and extra boot class path dex files,
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
index 262c6e0..0eab35f 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -20,7 +20,8 @@
#include <dirent.h>
#include <dlfcn.h>
-#include "android-base/stringprintf.h"
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include "base/file_utils.h"
#include "base/logging.h" // For VLOG.
diff --git a/runtime/gc/space/image_space_loading_order.h b/runtime/gc/space/image_space_loading_order.h
new file mode 100644
index 0000000..d8b0be4
--- /dev/null
+++ b/runtime/gc/space/image_space_loading_order.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#ifndef ART_RUNTIME_GC_SPACE_IMAGE_SPACE_LOADING_ORDER_H_
+#define ART_RUNTIME_GC_SPACE_IMAGE_SPACE_LOADING_ORDER_H_
+
+namespace art {
+namespace gc {
+namespace space {
+
+enum class ImageSpaceLoadingOrder : char {
+ kSystemFirst,
+ kDataFirst,
+};
+
+} // namespace space
+} // namespace gc
+} // namespace art
+
+#endif // ART_RUNTIME_GC_SPACE_IMAGE_SPACE_LOADING_ORDER_H_
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 8115b6b..530dbd6 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -653,8 +653,9 @@
return JNI_FALSE;
}
std::string error_msg;
+ Runtime* runtime = Runtime::Current();
std::unique_ptr<ImageHeader> image_header(gc::space::ImageSpace::ReadImageHeader(
- Runtime::Current()->GetImageLocation().c_str(), isa, &error_msg));
+ runtime->GetImageLocation().c_str(), isa, runtime->GetImageSpaceLoadingOrder(), &error_msg));
return image_header.get() != nullptr;
}
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f1708b4..ca09339 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -584,7 +584,11 @@
std::unique_ptr<ImageInfo> info(new ImageInfo());
info->location = runtime->GetImageLocation();
info->boot_class_path_checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
- runtime->GetBootClassPath(), info->location, isa, error_msg);
+ runtime->GetBootClassPath(),
+ info->location,
+ isa,
+ runtime->GetImageSpaceLoadingOrder(),
+ error_msg);
if (info->boot_class_path_checksums.empty()) {
return nullptr;
}
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 6423f3b..cf0d478 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -89,6 +89,11 @@
.Define("-Ximage:_")
.WithType<std::string>()
.IntoKey(M::Image)
+ .Define("-Ximage-load-order:_")
+ .WithType<gc::space::ImageSpaceLoadingOrder>()
+ .WithValueMap({{"system", gc::space::ImageSpaceLoadingOrder::kSystemFirst},
+ {"data", gc::space::ImageSpaceLoadingOrder::kDataFirst}})
+ .IntoKey(M::ImageSpaceLoadingOrder)
.Define("-Xcheck:jni")
.IntoKey(M::CheckJni)
.Define("-Xjniopts:forcecopy")
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 095d66e..39ce4ce 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -24,6 +24,7 @@
#include "arch/instruction_set.h"
#include "gc/collector_type.h"
+#include "gc/space/image_space_loading_order.h"
#include "gc/space/large_object_space.h"
// #include "jit/profile_saver_options.h"
#include "runtime_globals.h"
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5539205..0d32e0b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1270,6 +1270,8 @@
// Generational CC collection is currently only compatible with Baker read barriers.
bool use_generational_cc = kUseBakerReadBarrier && xgc_option.generational_cc;
+ image_space_loading_order_ = runtime_options.GetOrDefault(Opt::ImageSpaceLoadingOrder);
+
heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
runtime_options.GetOrDefault(Opt::HeapMinFree),
@@ -1307,7 +1309,8 @@
use_generational_cc,
runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs),
runtime_options.Exists(Opt::DumpRegionInfoBeforeGC),
- runtime_options.Exists(Opt::DumpRegionInfoAfterGC));
+ runtime_options.Exists(Opt::DumpRegionInfoAfterGC),
+ image_space_loading_order_);
if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 6a9e1e9..449a5a4 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -34,6 +34,7 @@
#include "deoptimization_kind.h"
#include "dex/dex_file_types.h"
#include "experimental_flags.h"
+#include "gc/space/image_space_loading_order.h"
#include "gc_root.h"
#include "instrumentation.h"
#include "jdwp_provider.h"
@@ -847,6 +848,10 @@
// Return true if startup is already completed.
bool GetStartupCompleted() const;
+ gc::space::ImageSpaceLoadingOrder GetImageSpaceLoadingOrder() const {
+ return image_space_loading_order_;
+ }
+
private:
static void InitPlatformSignalHandlers();
@@ -1175,6 +1180,9 @@
// If startup has completed, must happen at most once.
std::atomic<bool> startup_completed_ = false;
+ gc::space::ImageSpaceLoadingOrder image_space_loading_order_ =
+ gc::space::ImageSpaceLoadingOrder::kSystemFirst;
+
// Note: See comments on GetFaultMessage.
friend std::string GetFaultMessageForAbortLogging();
friend class ScopedThreadPoolUsage;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 9b4aa0f..41f0634 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -155,4 +155,8 @@
RUNTIME_OPTIONS_KEY (Unit, OnlyUseSystemOatFiles)
RUNTIME_OPTIONS_KEY (unsigned int, VerifierLoggingThreshold, 100)
+RUNTIME_OPTIONS_KEY (gc::space::ImageSpaceLoadingOrder, \
+ ImageSpaceLoadingOrder, \
+ gc::space::ImageSpaceLoadingOrder::kSystemFirst)
+
#undef RUNTIME_OPTIONS_KEY
diff --git a/runtime/runtime_options.h b/runtime/runtime_options.h
index 39b44e7..4f46d89 100644
--- a/runtime/runtime_options.h
+++ b/runtime/runtime_options.h
@@ -26,6 +26,7 @@
#include "base/variant_map.h"
#include "cmdline_types.h" // TODO: don't need to include this file here
#include "gc/collector_type.h"
+#include "gc/space/image_space_loading_order.h"
#include "gc/space/large_object_space.h"
#include "jdwp/jdwp.h"
#include "jit/jit.h"