Prune image cache if the boot marker is still in place.
We place a marker in each isa cache dir and have the framework
delete it for us.
This seems like a convenient place to do it given all the other
dalvik-cache related code that hooks in here, and also because
this is the first point where we try to access the cache.
TODO: Add a timeout to the (higher level) zygote code to correctly
kill the surviving zygote if one of them never comes up.
bug: 18280671
(cherry picked from commit c38276177aeeda4326a54f1121790c154df04300)
(partial cherry-pick of 9433ec60b325b708b9fa87e699ab4a6565741494)
Change-Id: I5dbea21b4bf9ca4106a13225946d3f35f8060a43
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index b232128..071997f 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -74,17 +74,17 @@
// 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 RealPruneDexCache(const std::string& cache_dir_path);
+static void RealPruneDalvikCache(const std::string& cache_dir_path);
-static void PruneDexCache(InstructionSet isa) {
+static void PruneDalvikCache(InstructionSet isa) {
CHECK_NE(isa, kNone);
// Prune the base /data/dalvik-cache.
- RealPruneDexCache(GetDalvikCacheOrDie(".", false));
+ RealPruneDalvikCache(GetDalvikCacheOrDie(".", false));
// Prune /data/dalvik-cache/<isa>.
- RealPruneDexCache(GetDalvikCacheOrDie(GetInstructionSetString(isa), false));
+ RealPruneDalvikCache(GetDalvikCacheOrDie(GetInstructionSetString(isa), false));
}
-static void RealPruneDexCache(const std::string& cache_dir_path) {
+static void RealPruneDalvikCache(const std::string& cache_dir_path) {
if (!OS::DirectoryExists(cache_dir_path.c_str())) {
return;
}
@@ -118,6 +118,28 @@
CHECK_EQ(0, TEMP_FAILURE_RETRY(closedir(cache_dir))) << "Unable to close directory.";
}
+// We write out an empty file to the zygote's ISA specific cache dir at the start of
+// every zygote boot and delete it when the boot completes. If we find a file already
+// present, it usually means the boot didn't complete. We wipe the entire dalvik
+// cache if that's the case.
+static void MarkZygoteStart(const InstructionSet isa) {
+ const std::string isa_subdir = GetDalvikCacheOrDie(GetInstructionSetString(isa), false);
+ const std::string boot_marker = isa_subdir + "/.booting";
+
+ if (OS::FileExists(boot_marker.c_str())) {
+ LOG(WARNING) << "Incomplete boot detected. Pruning dalvik cache";
+ RealPruneDalvikCache(isa_subdir);
+ }
+
+ VLOG(startup) << "Creating boot start marker: " << boot_marker;
+ std::unique_ptr<File> f(OS::CreateEmptyFile(boot_marker.c_str()));
+ if (f.get() != nullptr) {
+ if (f->FlushCloseOrErase() != 0) {
+ PLOG(WARNING) << "Failed to write boot marker.";
+ }
+ }
+}
+
static bool GenerateImage(const std::string& image_filename, InstructionSet image_isa,
std::string* error_msg) {
const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
@@ -130,7 +152,7 @@
// 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";
- PruneDexCache(image_isa);
+ PruneDalvikCache(image_isa);
}
std::vector<std::string> arg_vector;
@@ -232,7 +254,7 @@
// 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 relocating an image and will need to recompile";
- PruneDexCache(isa);
+ PruneDalvikCache(isa);
}
std::string patchoat(Runtime::Current()->GetPatchoatExecutable());
@@ -427,6 +449,10 @@
&has_system, &cache_filename, &dalvik_cache_exists,
&has_cache, &is_global_cache);
+ if (Runtime::Current()->IsZygote()) {
+ MarkZygoteStart(image_isa);
+ }
+
ImageSpace* space;
bool relocate = Runtime::Current()->ShouldRelocate();
bool can_compile = Runtime::Current()->IsImageDex2OatEnabled();
@@ -475,7 +501,7 @@
// Since ImageCreationAllowed was true above, we are the zygote
// and therefore the only process expected to generate these for
// the device.
- PruneDexCache(image_isa);
+ PruneDalvikCache(image_isa);
return nullptr;
}
}
@@ -530,7 +556,7 @@
"but image failed to load: %s",
image_location, cache_filename.c_str(), system_filename.c_str(),
error_msg->c_str());
- PruneDexCache(image_isa);
+ PruneDalvikCache(image_isa);
return nullptr;
} else if (is_system) {
// If the /system file exists, it should be up-to-date, don't try to generate it.
@@ -558,13 +584,13 @@
// Since ImageCreationAllowed was true above, we are the zygote
// and therefore the only process expected to generate these for
// the device.
- PruneDexCache(image_isa);
+ PruneDalvikCache(image_isa);
return nullptr;
} else {
// Check whether there is enough space left over after we have generated the image.
if (!CheckSpace(cache_filename, error_msg)) {
// No. Delete the generated image and try to run out of the dex files.
- PruneDexCache(image_isa);
+ PruneDalvikCache(image_isa);
return nullptr;
}