diff options
| -rw-r--r-- | dexlayout/Android.bp | 1 | ||||
| -rw-r--r-- | dexlayout/dex_ir_builder.cc | 29 | ||||
| -rw-r--r-- | dexlayout/dex_ir_builder.h | 7 | ||||
| -rw-r--r-- | dexlayout/dexdiag.cc | 5 | ||||
| -rw-r--r-- | dexlayout/dexlayout.cc | 10 | ||||
| -rw-r--r-- | dexlayout/dexlayout.h | 1 | ||||
| -rw-r--r-- | dexlayout/dexlayout_test.cc | 55 | ||||
| -rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc | 79 | ||||
| -rw-r--r-- | openjdkjvmti/fixed_up_dex_file.h | 3 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class.cc | 3 | ||||
| -rw-r--r-- | openjdkjvmti/ti_class_definition.cc | 4 |
11 files changed, 138 insertions, 59 deletions
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index 23ad5fd17e..63650bf121 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -85,6 +85,7 @@ art_cc_binary { art_cc_test { name: "art_dexlayout_tests", defaults: ["art_gtest_defaults"], + shared_libs: ["libart-dexlayout"], srcs: ["dexlayout_test.cc"], } diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc index 3ec163cea1..4f9bcdd742 100644 --- a/dexlayout/dex_ir_builder.cc +++ b/dexlayout/dex_ir_builder.cc @@ -20,13 +20,18 @@ #include <vector> #include "dex_ir_builder.h" +#include "dexlayout.h" namespace art { namespace dex_ir { -static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections); +static void CheckAndSetRemainingOffsets(const DexFile& dex_file, + Collections* collections, + const Options& options); -Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) { +Header* DexIrBuilder(const DexFile& dex_file, + bool eagerly_assign_offsets, + const Options& options) { const DexFile::Header& disk_header = dex_file.GetHeader(); Header* header = new Header(disk_header.magic_, disk_header.checksum_, @@ -70,13 +75,22 @@ Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) { // ClassDef table. collections.SetClassDefsOffset(disk_header.class_defs_off_); for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) { + if (!options.class_filter_.empty()) { + // If the filter is enabled (not empty), filter out classes that don't have a matching + // descriptor. + const DexFile::ClassDef& class_def = dex_file.GetClassDef(i); + const char* descriptor = dex_file.GetClassDescriptor(class_def); + if (options.class_filter_.find(descriptor) == options.class_filter_.end()) { + continue; + } + } collections.CreateClassDef(dex_file, i); } // MapItem. collections.SetMapListOffset(disk_header.map_off_); // CallSiteIds and MethodHandleItems. collections.CreateCallSitesAndMethodHandles(dex_file); - CheckAndSetRemainingOffsets(dex_file, &collections); + CheckAndSetRemainingOffsets(dex_file, &collections, options); // Sort the vectors by the map order (same order as the file). collections.SortVectorsByMapOrder(); @@ -89,7 +103,9 @@ Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets) { return header; } -static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections) { +static void CheckAndSetRemainingOffsets(const DexFile& dex_file, + Collections* collections, + const Options& options) { const DexFile::Header& disk_header = dex_file.GetHeader(); // Read MapItems and validate/set remaining offsets. const DexFile::MapList* map = dex_file.GetMapList(); @@ -122,7 +138,10 @@ static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* co CHECK_EQ(item->offset_, collections->MethodIdsOffset()); break; case DexFile::kDexTypeClassDefItem: - CHECK_EQ(item->size_, collections->ClassDefsSize()); + if (options.class_filter_.empty()) { + // The filter may have removed some classes, this will get fixed up during writing. + CHECK_EQ(item->size_, collections->ClassDefsSize()); + } CHECK_EQ(item->offset_, collections->ClassDefsOffset()); break; case DexFile::kDexTypeCallSiteIdItem: diff --git a/dexlayout/dex_ir_builder.h b/dexlayout/dex_ir_builder.h index 4d4b4e8699..43b5290756 100644 --- a/dexlayout/dex_ir_builder.h +++ b/dexlayout/dex_ir_builder.h @@ -22,11 +22,16 @@ #include "dex_ir.h" namespace art { + +class Options; + namespace dex_ir { // Eagerly assign offsets assigns offsets based on the original offsets in the input dex file. If // this not done, dex_ir::Item::GetOffset will abort when reading uninitialized offsets. -dex_ir::Header* DexIrBuilder(const DexFile& dex_file, bool eagerly_assign_offsets); +dex_ir::Header* DexIrBuilder(const DexFile& dex_file, + bool eagerly_assign_offsets, + const Options& options); } // namespace dex_ir } // namespace art diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc index 99b1f38f73..c0d6f02c00 100644 --- a/dexlayout/dexdiag.cc +++ b/dexlayout/dexdiag.cc @@ -29,6 +29,7 @@ #include "base/logging.h" // For InitLogging. #include "base/stringpiece.h" +#include "dexlayout.h" #include "dex/dex_file.h" #include "dex_ir.h" #include "dex_ir_builder.h" @@ -290,8 +291,10 @@ static void ProcessOneDexMapping(uint64_t* pagemap, // Build a list of the dex file section types, sorted from highest offset to lowest. std::vector<dex_ir::DexFileSection> sections; { + Options options; std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, - /*eagerly_assign_offsets*/ true)); + /*eagerly_assign_offsets*/ true, + options)); sections = dex_ir::GetSortedDexFileSections(header.get(), dex_ir::SortDirection::kSortDescending); } diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 1b32f7b0d9..c51e50b577 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -1873,7 +1873,9 @@ void DexLayout::ProcessDexFile(const char* file_name, // These options required the offsets for dumping purposes. eagerly_assign_offsets = true; } - std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, eagerly_assign_offsets)); + std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, + eagerly_assign_offsets, + GetOptions())); SetHeader(header.get()); if (options_.verbose_) { @@ -1948,10 +1950,12 @@ void DexLayout::ProcessDexFile(const char* file_name, // Regenerate output IR to catch any bugs that might happen during writing. std::unique_ptr<dex_ir::Header> output_header( dex_ir::DexIrBuilder(*output_dex_file, - /*eagerly_assign_offsets*/ true)); + /*eagerly_assign_offsets*/ true, + GetOptions())); std::unique_ptr<dex_ir::Header> orig_header( dex_ir::DexIrBuilder(*dex_file, - /*eagerly_assign_offsets*/ true)); + /*eagerly_assign_offsets*/ true, + GetOptions())); CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), &error_msg)) << error_msg; } } diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index 00d24dbda4..e66710fa55 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -72,6 +72,7 @@ class Options { const char* output_dex_directory_ = nullptr; const char* output_file_name_ = nullptr; const char* profile_file_name_ = nullptr; + std::set<std::string> class_filter_; }; // Hotness info diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index 3a7f9eeda6..e93ade1412 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -27,6 +27,7 @@ #include "dex/code_item_accessors-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" +#include "dexlayout.h" #include "exec_utils.h" #include "jit/profile_compilation_info.h" #include "utils.h" @@ -778,4 +779,58 @@ TEST_F(DexLayoutTest, LinkData) { ASSERT_TRUE(::art::Exec(rm_exec_argv, &error_msg)); } +TEST_F(DexLayoutTest, ClassFilter) { + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + const ArtDexFileLoader dex_file_loader; + const std::string input_jar = GetTestDexFileName("ManyMethods"); + CHECK(dex_file_loader.Open(input_jar.c_str(), + input_jar.c_str(), + /*verify*/ true, + /*verify_checksum*/ true, + &error_msg, + &dex_files)) << error_msg; + ASSERT_EQ(dex_files.size(), 1u); + for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { + EXPECT_GT(dex_file->NumClassDefs(), 1u); + for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { + const DexFile::ClassDef& class_def = dex_file->GetClassDef(i); + LOG(INFO) << dex_file->GetClassDescriptor(class_def); + } + Options options; + // Filter out all the classes other than the one below based on class descriptor. + options.class_filter_.insert("LManyMethods$Strings;"); + DexLayout dexlayout(options, + /*info*/ nullptr, + /*out_file*/ nullptr, + /*header*/ nullptr); + std::unique_ptr<DexContainer> out; + dexlayout.ProcessDexFile(dex_file->GetLocation().c_str(), + dex_file.get(), + /*dex_file_index*/ 0, + &out); + std::unique_ptr<const DexFile> output_dex_file( + dex_file_loader.OpenWithDataSection( + out->GetMainSection()->Begin(), + out->GetMainSection()->Size(), + out->GetDataSection()->Begin(), + out->GetDataSection()->Size(), + dex_file->GetLocation().c_str(), + /* checksum */ 0, + /*oat_dex_file*/ nullptr, + /* verify */ true, + /*verify_checksum*/ false, + &error_msg)); + ASSERT_TRUE(output_dex_file != nullptr); + + ASSERT_EQ(output_dex_file->NumClassDefs(), 1u); + for (uint32_t i = 0; i < output_dex_file->NumClassDefs(); ++i) { + // Check that every class is in the filter. + const DexFile::ClassDef& class_def = output_dex_file->GetClassDef(i); + ASSERT_TRUE(options.class_filter_.find(output_dex_file->GetClassDescriptor(class_def)) != + options.class_filter_.end()); + } + } +} + } // namespace art diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index cc56a7b714..6c66f12bb1 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -67,72 +67,59 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, const art::DexFile& vdex->UnquickenDexFile(new_dex_file, original_dex_file, /* decompile_return_instruction */true); } -std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original) { +std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& original, + const char* descriptor) { // Copy the data into mutable memory. std::vector<unsigned char> data; - if (original.IsCompactDexFile()) { - // Compact dex has a separate data section that is relative from the original dex. - // We need to copy the shared data section so that dequickening doesn't change anything. - data.resize(original.Size() + original.DataSize()); - memcpy(data.data(), original.Begin(), original.Size()); - memcpy(data.data() + original.Size(), original.DataBegin(), original.DataSize()); - // Go patch up the header to point to the copied data section. - art::CompactDexFile::Header* const header = - const_cast<art::CompactDexFile::Header*>(art::CompactDexFile::Header::At(data.data())); - header->data_off_ = original.Size(); - header->data_size_ = original.DataSize(); - } else { - data.resize(original.Size()); - memcpy(data.data(), original.Begin(), original.Size()); - } + std::unique_ptr<const art::DexFile> new_dex_file; std::string error; const art::ArtDexFileLoader dex_file_loader; - std::unique_ptr<const art::DexFile> new_dex_file(dex_file_loader.Open( - data.data(), - data.size(), - /*location*/"Unquickening_dexfile.dex", - /*location_checksum*/0, - /*oat_dex_file*/nullptr, - /*verify*/false, - /*verify_checksum*/false, - &error)); - if (new_dex_file.get() == nullptr) { - LOG(ERROR) << "Unable to open dex file from memory for unquickening! error: " << error; - return nullptr; - } - - DoDexUnquicken(*new_dex_file, original); if (original.IsCompactDexFile()) { - // Since we are supposed to return a standard dex, convert back using dexlayout. + // Since we are supposed to return a standard dex, convert back using dexlayout. It's OK to do + // this before unquickening. art::Options options; options.compact_dex_level_ = art::CompactDexLevel::kCompactDexLevelNone; - options.update_checksum_ = true; + // Add a filter to only include the class that has the matching descriptor. + static constexpr bool kFilterByDescriptor = true; + if (kFilterByDescriptor) { + options.class_filter_.insert(descriptor); + } art::DexLayout dex_layout(options, /*info*/ nullptr, /*out_file*/ nullptr, /*header*/ nullptr); std::unique_ptr<art::DexContainer> dex_container; - dex_layout.ProcessDexFile(new_dex_file->GetLocation().c_str(), - new_dex_file.get(), + dex_layout.ProcessDexFile(original.GetLocation().c_str(), + &original, 0, &dex_container); art::DexContainer::Section* main_section = dex_container->GetMainSection(); CHECK_EQ(dex_container->GetDataSection()->Size(), 0u); - // Overwrite the dex file stored in data with the new result. - data.clear(); data.insert(data.end(), main_section->Begin(), main_section->End()); - new_dex_file = dex_file_loader.Open( - data.data(), - data.size(), - /*location*/"Unquickening_dexfile.dex", - /*location_checksum*/0, - /*oat_dex_file*/nullptr, - /*verify*/false, - /*verify_checksum*/false, - &error); + } else { + data.resize(original.Size()); + memcpy(data.data(), original.Begin(), original.Size()); } + // Open the dex file in the buffer. + new_dex_file = dex_file_loader.Open( + data.data(), + data.size(), + /*location*/"Unquickening_dexfile.dex", + /*location_checksum*/0, + /*oat_dex_file*/nullptr, + /*verify*/false, + /*verify_checksum*/false, + &error); + + if (new_dex_file == nullptr) { + LOG(ERROR) << "Unable to open dex file from memory for unquickening! error: " << error; + return nullptr; + } + + DoDexUnquicken(*new_dex_file, original); + RecomputeDexChecksum(const_cast<art::DexFile*>(new_dex_file.get())); std::unique_ptr<FixedUpDexFile> ret(new FixedUpDexFile(std::move(new_dex_file), std::move(data))); return ret; diff --git a/openjdkjvmti/fixed_up_dex_file.h b/openjdkjvmti/fixed_up_dex_file.h index b8f349cf8c..7f05a2930a 100644 --- a/openjdkjvmti/fixed_up_dex_file.h +++ b/openjdkjvmti/fixed_up_dex_file.h @@ -49,7 +49,8 @@ namespace openjdkjvmti { // are running on. class FixedUpDexFile { public: - static std::unique_ptr<FixedUpDexFile> Create(const art::DexFile& original) + static std::unique_ptr<FixedUpDexFile> Create(const art::DexFile& original, + const char* descriptor) REQUIRES_SHARED(art::Locks::mutator_lock_); const art::DexFile& GetDexFile() { diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index b3f5c1886e..1868631020 100644 --- a/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc @@ -191,7 +191,8 @@ struct ClassCallback : public art::ClassLoadCallback { art::JNIEnvExt* env = self->GetJniEnv(); ScopedLocalRef<jobject> loader( env, class_loader.IsNull() ? nullptr : env->AddLocalReference<jobject>(class_loader.Get())); - std::unique_ptr<FixedUpDexFile> dex_file_copy(FixedUpDexFile::Create(initial_dex_file)); + std::unique_ptr<FixedUpDexFile> dex_file_copy(FixedUpDexFile::Create(initial_dex_file, + descriptor)); // Go back to native. art::ScopedThreadSuspension sts(self, art::ThreadState::kNative); diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc index 6560570136..c8a3047d9a 100644 --- a/openjdkjvmti/ti_class_definition.cc +++ b/openjdkjvmti/ti_class_definition.cc @@ -122,7 +122,9 @@ static jvmtiError GetDexDataForRetransformation(ArtJvmTiEnv* env, if (dex_file == nullptr) { dex_file = &klass->GetDexFile(); } - std::unique_ptr<FixedUpDexFile> fixed_dex_file(FixedUpDexFile::Create(*dex_file)); + std::string storage; + std::unique_ptr<FixedUpDexFile> fixed_dex_file( + FixedUpDexFile::Create(*dex_file, klass->GetDescriptor(&storage))); *dex_data_len = static_cast<jint>(fixed_dex_file->Size()); return CopyDataIntoJvmtiBuffer(env, fixed_dex_file->Begin(), |