Revert "Generate app image at runtime."
This reverts commit 1ebfebc865ef6661b16e38011ea8fbb6d8608e61.
Reason for revert: b/261576631
Change-Id: I3f2b9c97cab2e4178ec8dc7bf9447d69481b907d
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 166c342..1cba4b5 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -278,7 +278,6 @@
"runtime.cc",
"runtime_callbacks.cc",
"runtime_common.cc",
- "runtime_image.cc",
"runtime_intrinsics.cc",
"runtime_options.cc",
"scoped_thread_state_change.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ca3d399..dc2ccb4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1432,7 +1432,7 @@
}
}
-bool ClassLinker::IsBootClassLoader(ObjPtr<mirror::Object> class_loader) {
+bool ClassLinker::IsBootClassLoader(ObjPtr<mirror::ClassLoader> class_loader) {
return class_loader == nullptr ||
WellKnownClasses::java_lang_BootClassLoader == class_loader->GetClass();
}
@@ -1999,8 +1999,9 @@
hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()));
- MutableHandle<mirror::Object> special_root(hs.NewHandle(
- app_image ? header.GetImageRoot(ImageHeader::kSpecialRoots) : nullptr));
+ MutableHandle<mirror::ClassLoader> image_class_loader(hs.NewHandle(
+ app_image ? header.GetImageRoot(ImageHeader::kAppImageClassLoader)->AsClassLoader()
+ : nullptr));
DCHECK(class_roots != nullptr);
if (class_roots->GetLength() != static_cast<int32_t>(ClassRoot::kMax)) {
*error_msg = StringPrintf("Expected %d class roots but got %d",
@@ -2047,30 +2048,9 @@
if (app_image) {
ScopedAssertNoThreadSuspension sants("Checking app image");
- if (special_root == nullptr) {
- *error_msg = "Unexpected null special root in app image";
- return false;
- } else if (special_root->IsIntArray()) {
- size_t count = special_root->AsIntArray()->GetLength();
- if (oat_file->GetVdexFile()->GetNumberOfDexFiles() != count) {
- *error_msg = "Cheksums count does not match";
- return false;
- }
- static_assert(sizeof(VdexFile::VdexChecksum) == sizeof(int32_t));
- const VdexFile::VdexChecksum* art_checksums =
- reinterpret_cast<VdexFile::VdexChecksum*>(special_root->AsIntArray()->GetData());
- const VdexFile::VdexChecksum* vdex_checksums =
- oat_file->GetVdexFile()->GetDexChecksumsArray();
- if (memcmp(art_checksums, vdex_checksums, sizeof(VdexFile::VdexChecksum) * count) != 0) {
- *error_msg = "Image and vdex cheksums did not match";
- return false;
- }
- } else if (IsBootClassLoader(special_root.Get())) {
+ if (IsBootClassLoader(image_class_loader.Get())) {
*error_msg = "Unexpected BootClassLoader in app image";
return false;
- } else if (!special_root->IsClassLoader()) {
- *error_msg = "Unexpected special root in app image";
- return false;
}
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index bafbd7b..37e9979 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -723,7 +723,7 @@
REQUIRES(!Locks::classlinker_classes_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
- static bool IsBootClassLoader(ObjPtr<mirror::Object> class_loader)
+ static bool IsBootClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_);
ArtMethod* AddMethodToConflictTable(ObjPtr<mirror::Class> klass,
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index e318933..c87b31e 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -164,7 +164,7 @@
void CopyFrom(SpaceBitmap* source_bitmap);
// Starting address of our internal storage.
- Atomic<uintptr_t>* Begin() const {
+ Atomic<uintptr_t>* Begin() {
return bitmap_begin_;
}
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 48e5eb6..5667266 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -521,8 +521,7 @@
// Check the oat file checksum.
const uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
const uint32_t image_oat_checksum = image_header.GetOatChecksum();
- // Note image_oat_checksum is 0 for images generated by the runtime.
- if (image_oat_checksum != 0u && oat_checksum != image_oat_checksum) {
+ if (oat_checksum != image_oat_checksum) {
*error_msg = StringPrintf("Oat checksum 0x%x does not match the image one 0x%x in image %s",
oat_checksum,
image_oat_checksum,
diff --git a/runtime/image.cc b/runtime/image.cc
index 5030b49..b8536db 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -67,14 +67,12 @@
image_roots_(image_roots),
pointer_size_(pointer_size) {
CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize));
- if (oat_checksum != 0u) {
- CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
- CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize));
- CHECK_LT(image_roots, oat_file_begin);
- CHECK_LE(oat_file_begin, oat_data_begin);
- CHECK_LT(oat_data_begin, oat_data_end);
- CHECK_LE(oat_data_end, oat_file_end);
- }
+ CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
+ CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize));
+ CHECK_LT(image_roots, oat_file_begin);
+ CHECK_LE(oat_file_begin, oat_data_begin);
+ CHECK_LT(oat_data_begin, oat_data_end);
+ CHECK_LE(oat_data_end, oat_file_end);
CHECK(ValidPointerSize(pointer_size_)) << pointer_size_;
memcpy(magic_, kImageMagic, sizeof(kImageMagic));
memcpy(version_, kImageVersion, sizeof(kImageVersion));
@@ -131,16 +129,14 @@
if (image_begin_ >= image_begin_ + image_size_) {
return false;
}
- if (oat_checksum_ != 0u) {
- if (oat_file_begin_ > oat_file_end_) {
- return false;
- }
- if (oat_data_begin_ > oat_data_end_) {
- return false;
- }
- if (oat_file_begin_ >= oat_data_begin_) {
- return false;
- }
+ if (oat_file_begin_ > oat_file_end_) {
+ return false;
+ }
+ if (oat_data_begin_ > oat_data_end_) {
+ return false;
+ }
+ if (oat_file_begin_ >= oat_data_begin_) {
+ return false;
}
return true;
}
diff --git a/runtime/image.h b/runtime/image.h
index caf1aa5..bc0c9dd 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -230,8 +230,6 @@
// Aliases.
kAppImageClassLoader = kSpecialRoots, // The class loader used to build the app image.
kBootImageLiveObjects = kSpecialRoots, // Array of boot image objects that must be kept live.
- kAppImageDexChecksums = kSpecialRoots, // Array of dex checksums for app images generated by
- // the runtime.
};
enum BootImageLiveObjects {
@@ -504,7 +502,6 @@
uint32_t blocks_count_ = 0u;
friend class linker::ImageWriter;
- friend class RuntimeImageHelper;
};
/*
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index e9c0ddd..c64b9a3 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -50,7 +50,6 @@
#include "oat_file.h"
#include "oat_file_assistant.h"
#include "obj_ptr-inl.h"
-#include "runtime_image.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-current-inl.h"
#include "thread_list.h"
@@ -214,6 +213,12 @@
oat_file_assistant->GetOptimizationStatus(
&odex_location, &compilation_filter, &compilation_reason, &odex_status);
+ Runtime::Current()->GetAppInfo()->RegisterOdexStatus(
+ dex_location,
+ compilation_filter,
+ compilation_reason,
+ odex_status);
+
ScopedTrace odex_loading(StringPrintf(
"location=%s status=%s filter=%s reason=%s",
odex_location.c_str(),
@@ -243,95 +248,74 @@
<< " best_oat_file-location=" << oat_file->GetLocation();
if (oat_file != nullptr) {
- bool compilation_enabled =
- CompilerFilter::IsAotCompilationEnabled(oat_file->GetCompilerFilter());
// Load the dex files from the oat file.
bool added_image_space = false;
- if (should_madvise_vdex_and_odex) {
- VLOG(oat) << "Madvising oat file: " << oat_file->GetLocation();
- size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeOdex();
- Runtime::MadviseFileForRange(madvise_size_limit,
- oat_file->Size(),
- oat_file->Begin(),
- oat_file->End(),
- oat_file->GetLocation());
- }
+ if (oat_file->IsExecutable()) {
+ if (should_madvise_vdex_and_odex) {
+ VLOG(oat) << "Madvising oat file: " << oat_file->GetLocation();
+ size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeOdex();
+ Runtime::MadviseFileForRange(madvise_size_limit,
+ oat_file->Size(),
+ oat_file->Begin(),
+ oat_file->End(),
+ oat_file->GetLocation());
+ }
- ScopedTrace app_image_timing("AppImage:Loading");
+ ScopedTrace app_image_timing("AppImage:Loading");
- // We need to throw away the image space if we are debuggable but the oat-file source of the
- // image is not otherwise we might get classes with inlined methods or other such things.
- std::unique_ptr<gc::space::ImageSpace> image_space;
- if (ShouldLoadAppImage(oat_file.get())) {
- if (oat_file->IsExecutable()) {
- // App images generated by the compiler can only be used if the oat file
- // is executable.
+ // We need to throw away the image space if we are debuggable but the oat-file source of the
+ // image is not otherwise we might get classes with inlined methods or other such things.
+ std::unique_ptr<gc::space::ImageSpace> image_space;
+ if (ShouldLoadAppImage(oat_file.get())) {
image_space = oat_file_assistant->OpenImageSpace(oat_file.get());
}
- if (image_space == nullptr && !compilation_enabled) {
- std::string art_file = RuntimeImage::GetRuntimeImagePath(dex_location);
- std::string error_msg;
+ if (image_space != nullptr) {
ScopedObjectAccess soa(self);
- image_space = gc::space::ImageSpace::CreateFromAppImage(
- art_file.c_str(), oat_file.get(), &error_msg);
- if (image_space == nullptr) {
- VLOG(image) << "Could not load runtime generated app image: " << error_msg;
- }
- }
- }
- if (image_space != nullptr) {
- ScopedObjectAccess soa(self);
- StackHandleScope<1> hs(self);
- Handle<mirror::ClassLoader> h_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
- // Can not load app image without class loader.
- if (h_loader != nullptr) {
- std::string temp_error_msg;
- // Add image space has a race condition since other threads could be reading from the
- // spaces array.
- {
- ScopedThreadSuspension sts(self, ThreadState::kSuspended);
- gc::ScopedGCCriticalSection gcs(self,
- gc::kGcCauseAddRemoveAppImageSpace,
- gc::kCollectorTypeAddRemoveAppImageSpace);
- ScopedSuspendAll ssa("Add image space");
- runtime->GetHeap()->AddSpace(image_space.get());
- }
- {
- ScopedTrace image_space_timing("Adding image space");
- added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
- h_loader,
- /*out*/&dex_files,
- /*out*/&temp_error_msg);
- }
- if (added_image_space) {
- // Successfully added image space to heap, release the map so that it does not get
- // freed.
- image_space.release(); // NOLINT b/117926937
-
- // Register for tracking.
- for (const auto& dex_file : dex_files) {
- dex::tracking::RegisterDexFile(dex_file.get());
- }
-
- if (!compilation_enabled) {
- // Update the filter we are going to report to 'speed-profile'.
- // Ideally, we would also update the compiler filter of the odex
- // file, but at this point it's just too late.
- compilation_filter = CompilerFilter::NameOfFilter(CompilerFilter::kSpeedProfile);
- }
- } else {
- LOG(INFO) << "Failed to add image file: " << temp_error_msg;
- dex_files.clear();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> h_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+ // Can not load app image without class loader.
+ if (h_loader != nullptr) {
+ std::string temp_error_msg;
+ // Add image space has a race condition since other threads could be reading from the
+ // spaces array.
{
ScopedThreadSuspension sts(self, ThreadState::kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseAddRemoveAppImageSpace,
gc::kCollectorTypeAddRemoveAppImageSpace);
- ScopedSuspendAll ssa("Remove image space");
- runtime->GetHeap()->RemoveSpace(image_space.get());
+ ScopedSuspendAll ssa("Add image space");
+ runtime->GetHeap()->AddSpace(image_space.get());
}
- // Non-fatal, don't update error_msg.
+ {
+ ScopedTrace image_space_timing("Adding image space");
+ added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
+ h_loader,
+ /*out*/&dex_files,
+ /*out*/&temp_error_msg);
+ }
+ if (added_image_space) {
+ // Successfully added image space to heap, release the map so that it does not get
+ // freed.
+ image_space.release(); // NOLINT b/117926937
+
+ // Register for tracking.
+ for (const auto& dex_file : dex_files) {
+ dex::tracking::RegisterDexFile(dex_file.get());
+ }
+ } else {
+ LOG(INFO) << "Failed to add image file " << temp_error_msg;
+ dex_files.clear();
+ {
+ ScopedThreadSuspension sts(self, ThreadState::kSuspended);
+ gc::ScopedGCCriticalSection gcs(self,
+ gc::kGcCauseAddRemoveAppImageSpace,
+ gc::kCollectorTypeAddRemoveAppImageSpace);
+ ScopedSuspendAll ssa("Remove image space");
+ runtime->GetHeap()->RemoveSpace(image_space.get());
+ }
+ // Non-fatal, don't update error_msg.
+ }
}
}
}
@@ -433,12 +417,6 @@
}
}
}
-
- Runtime::Current()->GetAppInfo()->RegisterOdexStatus(
- dex_location,
- compilation_filter,
- compilation_reason,
- odex_status);
}
// If we arrive here with an empty dex files list, it means we fail to load
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d997256..e99eaec 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -165,7 +165,6 @@
#include "reflection.h"
#include "runtime_callbacks.h"
#include "runtime_common.h"
-#include "runtime_image.h"
#include "runtime_intrinsics.h"
#include "runtime_options.h"
#include "scoped_thread_state_change-inl.h"
@@ -3370,19 +3369,6 @@
void Run(Thread* self) override {
VLOG(startup) << "NotifyStartupCompletedTask running";
Runtime* const runtime = Runtime::Current();
- {
- std::string compiler_filter;
- std::string compilation_reason;
- runtime->GetAppInfo()->GetPrimaryApkOptimizationStatus(&compiler_filter, &compilation_reason);
- CompilerFilter::Filter filter;
- if (CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter) &&
- !CompilerFilter::IsAotCompilationEnabled(filter)) {
- std::string error_msg;
- if (!RuntimeImage::WriteImageToDisk(&error_msg)) {
- LOG(DEBUG) << "Could not write temporary image to disk " << error_msg;
- }
- }
- }
// Fetch the startup linear alloc before the checkpoint to play nice with
// 1002-notify-startup test which resets the startup state.
std::unique_ptr<LinearAlloc> startup_linear_alloc(runtime->ReleaseStartupLinearAlloc());
diff --git a/runtime/runtime_image.cc b/runtime/runtime_image.cc
deleted file mode 100644
index f088eb1..0000000
--- a/runtime/runtime_image.cc
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright (C) 2022 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 "runtime_image.h"
-
-#include <lz4.h>
-#include <sstream>
-#include <unistd.h>
-
-#include "android-base/stringprintf.h"
-
-#include "base/bit_utils.h"
-#include "base/file_utils.h"
-#include "base/length_prefixed_array.h"
-#include "base/unix_file/fd_file.h"
-#include "base/utils.h"
-#include "class_loader_utils.h"
-#include "class_root-inl.h"
-#include "gc/space/image_space.h"
-#include "image.h"
-#include "mirror/object-inl.h"
-#include "mirror/object-refvisitor-inl.h"
-#include "mirror/object_array-alloc-inl.h"
-#include "mirror/object_array-inl.h"
-#include "mirror/object_array.h"
-#include "scoped_thread_state_change-inl.h"
-#include "vdex_file.h"
-
-namespace art {
-
-/**
- * Helper class to generate an app image at runtime.
- */
-class RuntimeImageHelper {
- public:
- explicit RuntimeImageHelper(gc::Heap* heap) :
- boot_image_begin_(heap->GetBootImagesStartAddress()),
- boot_image_size_(heap->GetBootImagesSize()),
- image_begin_(boot_image_begin_ + boot_image_size_),
- // Note: image relocation considers the image header in the bitmap.
- object_section_size_(sizeof(ImageHeader)) {}
-
- bool Generate(std::string* error_msg) {
- if (!WriteImageRoot(error_msg)) {
- return false;
- }
-
- // Generate the sections information stored in the header.
- dchecked_vector<ImageSection> sections(ImageHeader::kSectionCount);
- CreateImageSections(sections);
-
- // Generate the bitmap section, stored page aligned after the sections data
- // and of size `object_section_size_` page aligned.
- size_t sections_end = sections[ImageHeader::kSectionMetadata].End();
- image_bitmap_ = gc::accounting::ContinuousSpaceBitmap::Create(
- "image bitmap",
- reinterpret_cast<uint8_t*>(image_begin_),
- RoundUp(object_section_size_, kPageSize));
- for (uint32_t offset : object_offsets_) {
- DCHECK(IsAligned<kObjectAlignment>(image_begin_ + sizeof(ImageHeader) + offset));
- image_bitmap_.Set(
- reinterpret_cast<mirror::Object*>(image_begin_ + sizeof(ImageHeader) + offset));
- }
- const size_t bitmap_bytes = image_bitmap_.Size();
- auto* bitmap_section = §ions[ImageHeader::kSectionImageBitmap];
- *bitmap_section = ImageSection(RoundUp(sections_end, kPageSize),
- RoundUp(bitmap_bytes, kPageSize));
-
- // Compute boot image checksum and boot image components, to be stored in
- // the header.
- gc::Heap* const heap = Runtime::Current()->GetHeap();
- uint32_t boot_image_components = 0u;
- uint32_t boot_image_checksums = 0u;
- const std::vector<gc::space::ImageSpace*>& image_spaces = heap->GetBootImageSpaces();
- for (size_t i = 0u, size = image_spaces.size(); i != size; ) {
- const ImageHeader& header = image_spaces[i]->GetImageHeader();
- boot_image_components += header.GetComponentCount();
- boot_image_checksums ^= header.GetImageChecksum();
- DCHECK_LE(header.GetImageSpaceCount(), size - i);
- i += header.GetImageSpaceCount();
- }
-
- header_ = ImageHeader(
- /* image_reservation_size= */ RoundUp(sections_end, kPageSize),
- /* component_count= */ 1,
- image_begin_,
- sections_end,
- sections.data(),
- /* image_roots= */ image_begin_ + sizeof(ImageHeader),
- /* oat_checksum= */ 0,
- /* oat_file_begin= */ 0,
- /* oat_data_begin= */ 0,
- /* oat_data_end= */ 0,
- /* oat_file_end= */ 0,
- heap->GetBootImagesStartAddress(),
- heap->GetBootImagesSize(),
- boot_image_components,
- boot_image_checksums,
- static_cast<uint32_t>(kRuntimePointerSize));
-
- // Data size includes everything except the bitmap.
- header_.data_size_ = sections_end;
-
- // Write image methods - needs to happen after creation of the header.
- WriteImageMethods();
-
- return true;
- }
-
- const std::vector<uint8_t>& GetData() const {
- return image_data_;
- }
-
- const ImageHeader& GetHeader() const {
- return header_;
- }
-
- const gc::accounting::ContinuousSpaceBitmap& GetImageBitmap() const {
- return image_bitmap_;
- }
-
- const std::string& GetDexLocation() const {
- return dex_location_;
- }
-
- private:
- bool IsInBootImage(const void* obj) const {
- return reinterpret_cast<uintptr_t>(obj) - boot_image_begin_ < boot_image_size_;
- }
-
- // Returns a pointer that can be stored in `image_data_`:
- // - The pointer itself for boot image objects,
- // - The offset in the image for all other objects.
- mirror::Object* GetOrComputeImageAddress(ObjPtr<mirror::Object> object)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (object == nullptr || IsInBootImage(object.Ptr())) {
- DCHECK(object == nullptr || Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(object));
- return object.Ptr();
- } else if (object->IsClassLoader()) {
- // DexCache and Class point to class loaders. For runtime-generated app
- // images, we don't encode the class loader. It will be set when the
- // runtime is loading the image.
- return nullptr;
- } else {
- uint32_t offset = CopyObject(object);
- return reinterpret_cast<mirror::Object*>(image_begin_ + sizeof(ImageHeader) + offset);
- }
- }
-
- void CreateImageSections(dchecked_vector<ImageSection>& sections) const {
- sections[ImageHeader::kSectionObjects] =
- ImageSection(0u, object_section_size_);
- sections[ImageHeader::kSectionArtFields] =
- ImageSection(sections[ImageHeader::kSectionObjects].End(), 0u);
- sections[ImageHeader::kSectionArtMethods] =
- ImageSection(sections[ImageHeader::kSectionArtFields].End(), 0u);
- sections[ImageHeader::kSectionImTables] =
- ImageSection(sections[ImageHeader::kSectionArtMethods].End(), 0u);
- sections[ImageHeader::kSectionIMTConflictTables] =
- ImageSection(sections[ImageHeader::kSectionImTables].End(), 0u);
- sections[ImageHeader::kSectionRuntimeMethods] =
- ImageSection(sections[ImageHeader::kSectionIMTConflictTables].End(), 0u);
-
- // Round up to the alignment the string table expects. See HashSet::WriteToMemory.
- size_t cur_pos = RoundUp(sections[ImageHeader::kSectionRuntimeMethods].End(), sizeof(uint64_t));
-
- sections[ImageHeader::kSectionInternedStrings] =
- ImageSection(cur_pos, 0u);
-
- // Obtain the new position and round it up to the appropriate alignment.
- cur_pos = RoundUp(sections[ImageHeader::kSectionInternedStrings].End(), sizeof(uint64_t));
-
- sections[ImageHeader::kSectionClassTable] =
- ImageSection(cur_pos, 0u);
-
- // Round up to the alignment of the offsets we are going to store.
- cur_pos = RoundUp(sections[ImageHeader::kSectionClassTable].End(), sizeof(uint32_t));
-
- sections[ImageHeader::kSectionStringReferenceOffsets] =
- ImageSection(cur_pos, 0u);
-
- // Round up to the alignment of the offsets we are going to store.
- cur_pos =
- RoundUp(sections[ImageHeader::kSectionStringReferenceOffsets].End(), sizeof(uint32_t));
-
- sections[ImageHeader::kSectionMetadata] =
- ImageSection(cur_pos, 0u);
- }
-
- bool WriteImageRoot(std::string* error_msg) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- ScopedObjectAccess soa(Thread::Current());
- VariableSizedHandleScope handles(soa.Self());
-
- Handle<mirror::Class> object_array_class = handles.NewHandle(
- GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker));
-
- Handle<mirror::ObjectArray<mirror::Object>> image_roots = handles.NewHandle(
- mirror::ObjectArray<mirror::Object>::Alloc(
- soa.Self(), object_array_class.Get(), ImageHeader::kImageRootsMax));
-
- if (image_roots == nullptr) {
- DCHECK(soa.Self()->IsExceptionPending());
- soa.Self()->ClearException();
- *error_msg = "Out of memory when trying to generate a runtime app image";
- return false;
- }
-
- // Find the dex files that will be used for generating the app image.
- dchecked_vector<Handle<mirror::DexCache>> dex_caches;
- FindDexCaches(soa.Self(), dex_caches, handles);
-
- if (dex_caches.size() == 0) {
- *error_msg = "Did not find dex caches to generate an app image";
- return false;
- }
- const OatDexFile* oat_dex_file = dex_caches[0]->GetDexFile()->GetOatDexFile();
- VdexFile* vdex_file = oat_dex_file->GetOatFile()->GetVdexFile();
- // The first entry in `dex_caches` contains the location of the primary APK.
- dex_location_ = oat_dex_file->GetDexFileLocation();
-
- size_t number_of_dex_files = vdex_file->GetNumberOfDexFiles();
- if (number_of_dex_files != dex_caches.size()) {
- // This means some dex files haven't been executed. For simplicity, just
- // register them and recollect dex caches.
- Handle<mirror::ClassLoader> loader = handles.NewHandle(dex_caches[0]->GetClassLoader());
- VisitClassLoaderDexFiles(soa.Self(), loader, [&](const art::DexFile* dex_file)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- class_linker->RegisterDexFile(*dex_file, dex_caches[0]->GetClassLoader());
- return true; // Continue with other dex files.
- });
- dex_caches.clear();
- FindDexCaches(soa.Self(), dex_caches, handles);
- if (number_of_dex_files != dex_caches.size()) {
- *error_msg = "Number of dex caches does not match number of dex files in the primary APK";
- return false;
- }
- }
-
- // Create and populate the checksums aray.
- Handle<mirror::IntArray> checksums_array = handles.NewHandle(
- mirror::IntArray::Alloc(soa.Self(), number_of_dex_files));
-
- if (checksums_array == nullptr) {
- DCHECK(soa.Self()->IsExceptionPending());
- soa.Self()->ClearException();
- *error_msg = "Out of memory when trying to generate a runtime app image";
- return false;
- }
-
- const VdexFile::VdexChecksum* checksums = vdex_file->GetDexChecksumsArray();
- static_assert(sizeof(VdexFile::VdexChecksum) == sizeof(int32_t));
- for (uint32_t i = 0; i < number_of_dex_files; ++i) {
- checksums_array->Set(i, checksums[i]);
- }
-
- // Create and populate the dex caches aray.
- Handle<mirror::ObjectArray<mirror::Object>> dex_cache_array = handles.NewHandle(
- mirror::ObjectArray<mirror::Object>::Alloc(
- soa.Self(), object_array_class.Get(), dex_caches.size()));
-
- if (dex_cache_array == nullptr) {
- DCHECK(soa.Self()->IsExceptionPending());
- soa.Self()->ClearException();
- *error_msg = "Out of memory when trying to generate a runtime app image";
- return false;
- }
-
- for (uint32_t i = 0; i < dex_caches.size(); ++i) {
- dex_cache_array->Set(i, dex_caches[i].Get());
- }
-
- image_roots->Set(ImageHeader::kDexCaches, dex_cache_array.Get());
- image_roots->Set(ImageHeader::kClassRoots, class_linker->GetClassRoots());
- image_roots->Set(ImageHeader::kAppImageDexChecksums, checksums_array.Get());
-
- // Now that we have created all objects needed for the `image_roots`, copy
- // it into the buffer. Note that this will recursively copy all objects
- // contained in `image_roots`. That's acceptable as we don't have cycles,
- // nor a deep graph.
- ScopedAssertNoThreadSuspension sants("Writing runtime app image");
- CopyObject(image_roots.Get());
- return true;
- }
-
- class FixupVisitor {
- public:
- FixupVisitor(RuntimeImageHelper* image, size_t copy_offset)
- : image_(image), copy_offset_(copy_offset) {}
-
- // We do not visit native roots. These are handled with other logic.
- void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
- const {
- LOG(FATAL) << "UNREACHABLE";
- }
- void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {
- LOG(FATAL) << "UNREACHABLE";
- }
-
- void operator()(ObjPtr<mirror::Object> obj,
- MemberOffset offset,
- bool is_static ATTRIBUTE_UNUSED) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Object> ref = obj->GetFieldObject<mirror::Object>(offset);
- mirror::Object* address = image_->GetOrComputeImageAddress(ref.Ptr());
- mirror::Object* copy =
- reinterpret_cast<mirror::Object*>(image_->image_data_.data() + copy_offset_);
- copy->GetFieldObjectReferenceAddr<kVerifyNone>(offset)->Assign(address);
- }
-
- // java.lang.ref.Reference visitor.
- void operator()(ObjPtr<mirror::Class> klass ATTRIBUTE_UNUSED,
- ObjPtr<mirror::Reference> ref) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- operator()(ref, mirror::Reference::ReferentOffset(), /* is_static */ false);
- }
-
- private:
- RuntimeImageHelper* image_;
- size_t copy_offset_;
- };
-
- // Copy `obj` in `image_data_` and relocate references. Returns the offset
- // within our buffer.
- uint32_t CopyObject(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Copy the object in `image_data_`.
- size_t object_size = obj->SizeOf();
- size_t offset = image_data_.size();
- DCHECK(IsAligned<kObjectAlignment>(offset));
- object_offsets_.push_back(offset);
- image_data_.resize(RoundUp(image_data_.size() + object_size, kObjectAlignment));
- memcpy(image_data_.data() + offset, obj.Ptr(), object_size);
- object_section_size_ += RoundUp(object_size, kObjectAlignment);
-
- // Fixup reference pointers.
- FixupVisitor visitor(this, offset);
- obj->VisitReferences</*kVisitNativeRoots=*/ false>(visitor, visitor);
-
- // For dex caches, clear pointers to data that will be set at runtime.
- mirror::Object* copy = reinterpret_cast<mirror::Object*>(image_data_.data() + offset);
- if (obj->IsDexCache()) {
- reinterpret_cast<mirror::DexCache*>(copy)->ResetNativeArrays();
- reinterpret_cast<mirror::DexCache*>(copy)->SetDexFile(nullptr);
- }
- return offset;
- }
-
- class CollectDexCacheVisitor : public DexCacheVisitor {
- public:
- explicit CollectDexCacheVisitor(VariableSizedHandleScope& handles) : handles_(handles) {}
-
- void Visit(ObjPtr<mirror::DexCache> dex_cache)
- REQUIRES_SHARED(Locks::dex_lock_, Locks::mutator_lock_) override {
- dex_caches_.push_back(handles_.NewHandle(dex_cache));
- }
- const std::vector<Handle<mirror::DexCache>>& GetDexCaches() const {
- return dex_caches_;
- }
- private:
- VariableSizedHandleScope& handles_;
- std::vector<Handle<mirror::DexCache>> dex_caches_;
- };
-
- // Find dex caches corresponding to the primary APK.
- void FindDexCaches(Thread* self,
- dchecked_vector<Handle<mirror::DexCache>>& dex_caches,
- VariableSizedHandleScope& handles)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- DCHECK(dex_caches.empty());
- // Collect all dex caches.
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- CollectDexCacheVisitor visitor(handles);
- {
- ReaderMutexLock mu(self, *Locks::dex_lock_);
- class_linker->VisitDexCaches(&visitor);
- }
-
- // Find the primary APK.
- AppInfo* app_info = Runtime::Current()->GetAppInfo();
- for (Handle<mirror::DexCache> cache : visitor.GetDexCaches()) {
- if (app_info->GetRegisteredCodeType(cache->GetDexFile()->GetLocation()) ==
- AppInfo::CodeType::kPrimaryApk) {
- dex_caches.push_back(handles.NewHandle(cache.Get()));
- break;
- }
- }
-
- if (dex_caches.empty()) {
- return;
- }
-
- const OatDexFile* oat_dex_file = dex_caches[0]->GetDexFile()->GetOatDexFile();
- if (oat_dex_file == nullptr) {
- // We need a .oat file for loading an app image;
- dex_caches.clear();
- return;
- }
- const OatFile* oat_file = oat_dex_file->GetOatFile();
- for (Handle<mirror::DexCache> cache : visitor.GetDexCaches()) {
- if (cache.Get() != dex_caches[0].Get()) {
- const OatDexFile* other_oat_dex_file = cache->GetDexFile()->GetOatDexFile();
- if (other_oat_dex_file != nullptr && other_oat_dex_file->GetOatFile() == oat_file) {
- dex_caches.push_back(handles.NewHandle(cache.Get()));
- }
- }
- }
- }
-
- static uint64_t PointerToUint64(void* ptr) {
- return reinterpret_cast64<uint64_t>(ptr);
- }
-
- void WriteImageMethods() {
- ScopedObjectAccess soa(Thread::Current());
- // We can just use plain runtime pointers.
- Runtime* runtime = Runtime::Current();
- header_.image_methods_[ImageHeader::kResolutionMethod] =
- PointerToUint64(runtime->GetResolutionMethod());
- header_.image_methods_[ImageHeader::kImtConflictMethod] =
- PointerToUint64(runtime->GetImtConflictMethod());
- header_.image_methods_[ImageHeader::kImtUnimplementedMethod] =
- PointerToUint64(runtime->GetImtUnimplementedMethod());
- header_.image_methods_[ImageHeader::kSaveAllCalleeSavesMethod] =
- PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves));
- header_.image_methods_[ImageHeader::kSaveRefsOnlyMethod] =
- PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly));
- header_.image_methods_[ImageHeader::kSaveRefsAndArgsMethod] =
- PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs));
- header_.image_methods_[ImageHeader::kSaveEverythingMethod] =
- PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything));
- header_.image_methods_[ImageHeader::kSaveEverythingMethodForClinit] =
- PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit));
- header_.image_methods_[ImageHeader::kSaveEverythingMethodForSuspendCheck] =
- PointerToUint64(
- runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck));
- }
-
- // Header for the image, created at the end once we know the size of all
- // sections.
- ImageHeader header_;
-
- // Contents of the image sections.
- std::vector<uint8_t> image_data_;
-
- // Bitmap of live objects in `image_data_`. Populated from `object_offsets_`
- // once we know `object_section_size`.
- gc::accounting::ContinuousSpaceBitmap image_bitmap_;
-
- // A list of offsets in `image_data_` where objects begin.
- std::vector<uint32_t> object_offsets_;
-
- // Cached values of boot image information.
- const uint32_t boot_image_begin_;
- const uint32_t boot_image_size_;
-
- // Where the image begins: just after the boot image.
- const uint32_t image_begin_;
-
- // Size of the `kSectionObjects` section.
- size_t object_section_size_;
-
- // The location of the primary APK / dex file.
- std::string dex_location_;
-};
-
-std::string RuntimeImage::GetRuntimeImagePath(const std::string& dex_location) {
- const std::string& data_dir = Runtime::Current()->GetProcessDataDirectory();
-
- std::string new_location = ReplaceFileExtension(
- dex_location, (kRuntimePointerSize == PointerSize::k32 ? "art32" : "art64"));
-
- if (data_dir.empty()) {
- // The data ditectory is empty for tests.
- return new_location;
- } else {
- std::replace(new_location.begin(), new_location.end(), '/', '@');
- return data_dir + "/" + new_location;
- }
-}
-
-bool RuntimeImage::WriteImageToDisk(std::string* error_msg) {
- gc::Heap* heap = Runtime::Current()->GetHeap();
- if (!heap->HasBootImageSpace()) {
- *error_msg = "Cannot generate an app image without a boot image";
- return false;
- }
- RuntimeImageHelper image(heap);
- if (!image.Generate(error_msg)) {
- return false;
- }
-
- const std::string path = GetRuntimeImagePath(image.GetDexLocation());
- // We first generate the app image in a temporary file, which we will then
- // move to `path`.
- const std::string temp_path = path + std::to_string(getpid());
- std::unique_ptr<File> out(OS::CreateEmptyFileWriteOnly(temp_path.c_str()));
- if (out == nullptr) {
- *error_msg = "Could not open " + path + " for writing";
- return false;
- }
-
- // Write section infos. The header is written at the end in case we get killed.
- if (!out->Write(reinterpret_cast<const char*>(image.GetData().data()),
- image.GetData().size(),
- sizeof(ImageHeader))) {
- *error_msg = "Could not write image data to " + path;
- out->Unlink();
- return false;
- }
-
- // Write bitmap at aligned offset.
- size_t aligned_offset = RoundUp(sizeof(ImageHeader) + image.GetData().size(), kPageSize);
- if (!out->Write(reinterpret_cast<const char*>(image.GetImageBitmap().Begin()),
- image.GetImageBitmap().Size(),
- aligned_offset)) {
- *error_msg = "Could not write image bitmap " + path;
- out->Unlink();
- return false;
- }
-
- // Set the file length page aligned.
- size_t total_size = aligned_offset + RoundUp(image.GetImageBitmap().Size(), kPageSize);
- if (out->SetLength(total_size) != 0) {
- *error_msg = "Could not change size of image " + path;
- out->Unlink();
- return false;
- }
-
- // Now write header.
- if (!out->Write(reinterpret_cast<const char*>(&image.GetHeader()), sizeof(ImageHeader), 0u)) {
- *error_msg = "Could not write image header to " + path;
- out->Unlink();
- return false;
- }
-
- if (out->FlushClose() != 0) {
- *error_msg = "Could not flush and close " + path;
- out->Unlink();
- return false;
- }
-
- if (rename(temp_path.c_str(), path.c_str()) != 0) {
- *error_msg = "Failed to move runtime app image: " + std::string(strerror(errno));
- out->Unlink();
- return false;
- }
-
- return true;
-}
-
-} // namespace art
diff --git a/runtime/runtime_image.h b/runtime/runtime_image.h
deleted file mode 100644
index d494e1c..0000000
--- a/runtime/runtime_image.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 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_RUNTIME_IMAGE_H_
-#define ART_RUNTIME_RUNTIME_IMAGE_H_
-
-#include <string>
-
-namespace art {
-
-class RuntimeImage {
- public:
- // Writes an app image for the currently running process.
- static bool WriteImageToDisk(std::string* error_msg);
-
- // Gets the path where a runtime-generated app image is stored.
- static std::string GetRuntimeImagePath(const std::string& dex_location);
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_RUNTIME_IMAGE_H_
diff --git a/test/845-data-image/expected-stderr.txt b/test/845-data-image/expected-stderr.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/845-data-image/expected-stderr.txt
+++ /dev/null
diff --git a/test/845-data-image/expected-stdout.txt b/test/845-data-image/expected-stdout.txt
deleted file mode 100644
index 8db7853..0000000
--- a/test/845-data-image/expected-stdout.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-JNI_OnLoad called
-JNI_OnLoad called
diff --git a/test/845-data-image/info.txt b/test/845-data-image/info.txt
deleted file mode 100644
index dfcd0dd..0000000
--- a/test/845-data-image/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test the generation of app image at runtime.
diff --git a/test/845-data-image/run.py b/test/845-data-image/run.py
deleted file mode 100644
index 37c990f..0000000
--- a/test/845-data-image/run.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2022 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.
-
-import sys
-
-# We run the tests by disabling compilation with app image and forcing
-# relocation for better testing.
-# Run the test twice: one run for generating the image, a second run for using
-# the image.
-def run(ctx, args):
- ctx.default_run(args, app_image=False, relocate=True)
- # Pass another argument to let the test know it should now expect an image.
- ctx.default_run(args, app_image=False, relocate=True, test_args=["--second-run"])
diff --git a/test/845-data-image/src-art/Main.java b/test/845-data-image/src-art/Main.java
deleted file mode 100644
index d9da5d4..0000000
--- a/test/845-data-image/src-art/Main.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-import java.io.File;
-import java.io.IOException;
-
-public class Main {
- public static void main(String[] args) throws Exception {
- System.loadLibrary(args[0]);
-
- // Register the dex file so that the runtime can pick up which
- // dex file to compile for the image.
- File file = null;
- try {
- file = createTempFile();
- String codePath = DEX_LOCATION + "/845-data-image.jar";
- VMRuntime.registerAppInfo(
- "test.app",
- file.getPath(),
- file.getPath(),
- new String[] {codePath},
- VMRuntime.CODE_PATH_TYPE_PRIMARY_APK);
- } finally {
- if (file != null) {
- file.delete();
- }
- }
-
- if (!hasOatFile() || !hasImage()) {
- // We only generate an app image if there is at least a vdex file and a boot image.
- return;
- }
-
- if (args.length == 2 && "--second-run".equals(args[1])) {
- DexFile.OptimizationInfo info = VMRuntime.getBaseApkOptimizationInfo();
- if (!info.isOptimized()) {
- throw new Error("Expected image to be loaded");
- }
- }
-
- VMRuntime runtime = VMRuntime.getRuntime();
- runtime.notifyStartupCompleted();
-
- String filter = getCompilerFilter(Main.class);
- if ("speed-profile".equals(filter) || "speed".equals(filter)) {
- // We only generate an app image for filters that don't compile.
- return;
- }
-
- // Wait for the file to be generated.
- File image = new File(
- DEX_LOCATION + "/845-data-image.art" + (runtime.is64Bit() ? "64" : "32"));
- while (!image.exists()) {
- Thread.yield();
- }
- }
-
- private static native boolean hasOatFile();
- private static native boolean hasImage();
- private static native String getCompilerFilter(Class<?> cls);
-
- private static final String TEMP_FILE_NAME_PREFIX = "temp";
- private static final String TEMP_FILE_NAME_SUFFIX = "-file";
- private static final String DEX_LOCATION = System.getenv("DEX_LOCATION");
-
- private static File createTempFile() throws Exception {
- try {
- return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
- } catch (IOException e) {
- System.setProperty("java.io.tmpdir", "/data/local/tmp");
- try {
- return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
- } catch (IOException e2) {
- System.setProperty("java.io.tmpdir", "/sdcard");
- return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
- }
- }
- }
-}
diff --git a/test/846-multidex-data-image/expected-stderr.txt b/test/846-multidex-data-image/expected-stderr.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/846-multidex-data-image/expected-stderr.txt
+++ /dev/null
diff --git a/test/846-multidex-data-image/expected-stdout.txt b/test/846-multidex-data-image/expected-stdout.txt
deleted file mode 100644
index 8db7853..0000000
--- a/test/846-multidex-data-image/expected-stdout.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-JNI_OnLoad called
-JNI_OnLoad called
diff --git a/test/846-multidex-data-image/info.txt b/test/846-multidex-data-image/info.txt
deleted file mode 100644
index 3b83d2c..0000000
--- a/test/846-multidex-data-image/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Test the generation of app image at runtime, when the primary APK contains
-multiple dex files.
diff --git a/test/846-multidex-data-image/run.py b/test/846-multidex-data-image/run.py
deleted file mode 100644
index 3976af2..0000000
--- a/test/846-multidex-data-image/run.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (C) 2022 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.
-
-import sys
-
-# We run the tests by disabling compilation with app image.
-# Run the test twice: one run for generating the image, a second run for using
-# the image.
-def run(ctx, args):
- ctx.default_run(args, app_image=False)
- # Pass another argument to let the test know it should now expect an image.
- ctx.default_run(args, app_image=False, test_args=["--second-run"])
diff --git a/test/846-multidex-data-image/src-art/Main.java b/test/846-multidex-data-image/src-art/Main.java
deleted file mode 100644
index 1169c53..0000000
--- a/test/846-multidex-data-image/src-art/Main.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-import java.io.File;
-import java.io.IOException;
-
-public class Main {
- public static void main(String[] args) throws Exception {
- System.loadLibrary(args[0]);
-
- // Register the dex file so that the runtime can pick up which
- // dex file to compile for the image.
- File file = null;
- try {
- file = createTempFile();
- String codePath = DEX_LOCATION + "/846-multidex-data-image.jar";
- VMRuntime.registerAppInfo(
- "test.app",
- file.getPath(),
- file.getPath(),
- new String[] {codePath},
- VMRuntime.CODE_PATH_TYPE_PRIMARY_APK);
- } finally {
- if (file != null) {
- file.delete();
- }
- }
-
- if (!hasOatFile() || !hasImage()) {
- // We only generate an app image if there is at least a vdex file and a boot image.
- return;
- }
-
- if (args.length == 2 && "--second-run".equals(args[1])) {
- DexFile.OptimizationInfo info = VMRuntime.getBaseApkOptimizationInfo();
- if (!info.isOptimized()) {
- throw new Error("Expected image to be loaded");
- }
- }
-
- VMRuntime runtime = VMRuntime.getRuntime();
- runtime.notifyStartupCompleted();
-
- String filter = getCompilerFilter(Main.class);
- if ("speed-profile".equals(filter) || "speed".equals(filter)) {
- // We only generate an app image for filters that don't compile.
- return;
- }
-
- // Wait for the file to be generated.
- File image = new File(
- DEX_LOCATION + "/846-multidex-data-image.art" + (runtime.is64Bit() ? "64" : "32"));
- while (!image.exists()) {
- Thread.yield();
- }
-
- // Test that we can load a class from the other dex file. We do this after creating the image to
- // check that the runtime can deal with a missing dex cache.
- Class.forName("Foo");
- }
-
- private static native boolean hasOatFile();
- private static native boolean hasImage();
- private static native String getCompilerFilter(Class<?> cls);
-
- private static final String TEMP_FILE_NAME_PREFIX = "temp";
- private static final String TEMP_FILE_NAME_SUFFIX = "-file";
- private static final String DEX_LOCATION = System.getenv("DEX_LOCATION");
-
- private static File createTempFile() throws Exception {
- try {
- return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
- } catch (IOException e) {
- System.setProperty("java.io.tmpdir", "/data/local/tmp");
- try {
- return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
- } catch (IOException e2) {
- System.setProperty("java.io.tmpdir", "/sdcard");
- return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
- }
- }
- }
-}
diff --git a/test/846-multidex-data-image/src-multidex/Foo.java b/test/846-multidex-data-image/src-multidex/Foo.java
deleted file mode 100644
index 4e36e88..0000000
--- a/test/846-multidex-data-image/src-multidex/Foo.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-public class Foo {
-}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index f335dd5..b980eac 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1162,8 +1162,6 @@
"844-exception",
"844-exception2",
"845-fast-verify",
- "845-data-image",
- "846-multidex-data-image",
"999-redefine-hiddenapi",
"1000-non-moving-space-stress",
"1001-app-image-regions",