diff options
Diffstat (limited to 'dexlayout')
| -rw-r--r-- | dexlayout/Android.bp | 2 | ||||
| -rw-r--r-- | dexlayout/dex_ir.h | 20 | ||||
| -rw-r--r-- | dexlayout/dex_writer.cc | 2 | ||||
| -rw-r--r-- | dexlayout/dexdiag_test.cc | 41 | ||||
| -rw-r--r-- | dexlayout/dexlayout.cc | 263 | ||||
| -rw-r--r-- | dexlayout/dexlayout.h | 15 | ||||
| -rw-r--r-- | dexlayout/dexlayout_main.cc | 2 | ||||
| -rw-r--r-- | dexlayout/dexlayout_test.cc | 55 |
8 files changed, 325 insertions, 75 deletions
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index 922e1346b8..ec7fdf6c79 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -106,6 +106,7 @@ art_cc_library { apex_available: [ "com.android.art", "com.android.art.debug", + "test_broken_com.android.art", ], } @@ -191,6 +192,7 @@ art_cc_binary { apex_available: [ "com.android.art", "com.android.art.debug", + "test_broken_com.android.art", ], } diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 66ca84bbd4..c819c672e3 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -20,7 +20,7 @@ #define ART_DEXLAYOUT_DEX_IR_H_ #include <stdint.h> - +#include <unordered_map> #include <vector> #include "base/iteration_range.h" @@ -262,13 +262,21 @@ template<class T> class CollectionVector : public CollectionBase { // Sort the vector by copying pointers over. template <typename MapType> void SortByMapOrder(const MapType& map) { - auto it = map.begin(); CHECK_EQ(map.size(), Size()); + + // Move all pointers to a temporary map owning the pointers. + std::unordered_map<T*, ElementType> pointers_map; + pointers_map.reserve(Size()); + for (std::unique_ptr<T>& element : collection_) { + pointers_map[element.get()] = std::move(element); + } + + // Move back the pointers to the original vector according to the map order. + auto it = map.begin(); for (size_t i = 0; i < Size(); ++i) { - // There are times when the array will temporarily contain the same pointer twice, doing the - // release here sure there is no double free errors. - collection_[i].release(); - collection_[i].reset(it->second); + auto element_it = pointers_map.find(it->second); + DCHECK(element_it != pointers_map.end()); + collection_[i] = std::move(element_it->second); ++it; } } diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index 7f05ae89fb..e7473c0a60 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -30,8 +30,6 @@ namespace art { -constexpr uint32_t DexWriter::kDataSectionAlignment; - static size_t EncodeIntValue(int32_t value, uint8_t* buffer) { size_t length = 0; if (value >= 0) { diff --git a/dexlayout/dexdiag_test.cc b/dexlayout/dexdiag_test.cc index 27ac402120..3cd80b409f 100644 --- a/dexlayout/dexdiag_test.cc +++ b/dexlayout/dexdiag_test.cc @@ -33,9 +33,7 @@ static const char* kDexDiagBinaryName = "dexdiag"; class DexDiagTest : public CommonArtTest { protected: - void SetUp() override { - CommonArtTest::SetUp(); - } + void SetUp() override { CommonArtTest::SetUp(); } // Path to the dexdiag(d?)[32|64] binary. std::string GetDexDiagFilePath() { @@ -63,11 +61,11 @@ class DexDiagTest : public CommonArtTest { EXPECT_TRUE(!oat_location.empty()); std::cout << "==" << oat_location << std::endl; std::string error_msg; - std::unique_ptr<OatFile> oat(OatFile::Open(/*zip_fd=*/ -1, - oat_location.c_str(), - oat_location.c_str(), - /*executable=*/ false, - /*low_4gb=*/ false, + std::unique_ptr<OatFile> oat(OatFile::Open(/*zip_fd=*/-1, + oat_location, + oat_location, + /*executable=*/false, + /*low_4gb=*/false, &error_msg)); EXPECT_TRUE(oat != nullptr) << error_msg; return oat; @@ -82,8 +80,8 @@ class DexDiagTest : public CommonArtTest { // Build the command line "dexdiag <args> this_pid". std::string executable_path = GetDexDiagFilePath(); - EXPECT_TRUE(OS::FileExists(executable_path.c_str())) << executable_path - << " should be a valid file path"; + EXPECT_TRUE(OS::FileExists(executable_path.c_str())) + << executable_path << " should be a valid file path"; exec_argv.push_back(executable_path); for (const auto& arg : args) { exec_argv.push_back(arg); @@ -102,11 +100,11 @@ class DexDiagTest : public CommonArtTest { TEST_F(DexDiagTest, DexDiagHelpTest) { // TODO: test the resulting output. std::string error_msg; - ASSERT_TRUE(Exec(getpid(), { kDexDiagHelp }, &error_msg)) << "Failed to execute -- because: " - << error_msg; + ASSERT_TRUE(Exec(getpid(), {kDexDiagHelp}, &error_msg)) + << "Failed to execute -- because: " << error_msg; } -#if defined (ART_TARGET) +#if defined(ART_TARGET) TEST_F(DexDiagTest, DexDiagContainsTest) { #else TEST_F(DexDiagTest, DISABLED_DexDiagContainsTest) { @@ -114,11 +112,11 @@ TEST_F(DexDiagTest, DISABLED_DexDiagContainsTest) { std::unique_ptr<OatFile> oat = OpenOatAndVdexFiles(); // TODO: test the resulting output. std::string error_msg; - ASSERT_TRUE(Exec(getpid(), { kDexDiagContains }, &error_msg)) << "Failed to execute -- because: " - << error_msg; + ASSERT_TRUE(Exec(getpid(), {kDexDiagContains}, &error_msg)) + << "Failed to execute -- because: " << error_msg; } -#if defined (ART_TARGET) +#if defined(ART_TARGET) TEST_F(DexDiagTest, DexDiagContainsFailsTest) { #else TEST_F(DexDiagTest, DISABLED_DexDiagContainsFailsTest) { @@ -126,12 +124,11 @@ TEST_F(DexDiagTest, DISABLED_DexDiagContainsFailsTest) { std::unique_ptr<OatFile> oat = OpenOatAndVdexFiles(); // TODO: test the resulting output. std::string error_msg; - ASSERT_FALSE(Exec(getpid(), { kDexDiagContainsFails }, &error_msg)) - << "Failed to execute -- because: " - << error_msg; + ASSERT_FALSE(Exec(getpid(), {kDexDiagContainsFails}, &error_msg)) + << "Failed to execute -- because: " << error_msg; } -#if defined (ART_TARGET) +#if defined(ART_TARGET) TEST_F(DexDiagTest, DexDiagVerboseTest) { #else TEST_F(DexDiagTest, DISABLED_DexDiagVerboseTest) { @@ -139,8 +136,8 @@ TEST_F(DexDiagTest, DISABLED_DexDiagVerboseTest) { // TODO: test the resulting output. std::unique_ptr<OatFile> oat = OpenOatAndVdexFiles(); std::string error_msg; - ASSERT_TRUE(Exec(getpid(), { kDexDiagVerbose }, &error_msg)) << "Failed to execute -- because: " - << error_msg; + ASSERT_TRUE(Exec(getpid(), {kDexDiagVerbose}, &error_msg)) + << "Failed to execute -- because: " << error_msg; } } // namespace art diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 648c52dd1e..9152c18b1f 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -25,16 +25,17 @@ #include <inttypes.h> #include <stdio.h> +#include <cstdint> #include <iostream> +#include <iterator> #include <memory> #include <sstream> #include <unordered_set> #include <vector> #include "android-base/stringprintf.h" - -#include "base/logging.h" // For VLOG_IS_ON. #include "base/hiddenapi_flags.h" +#include "base/logging.h" // For VLOG_IS_ON. #include "base/mem_map.h" #include "base/mman.h" // For the PROT_* and MAP_* constants. #include "base/os.h" @@ -47,6 +48,7 @@ #include "dex/dex_file_types.h" #include "dex/dex_file_verifier.h" #include "dex/dex_instruction-inl.h" +#include "dex_ir.h" #include "dex_ir_builder.h" #include "dex_verify.h" #include "dex_visualize.h" @@ -533,6 +535,9 @@ static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, method.c_str(), proto.c_str(), width, index, width, secondary_index); } break; + case Instruction::kIndexCallSiteRef: + outSize = snprintf(buf.get(), buf_size, "call_site@%0*x", width, index); + break; // SOME NOT SUPPORTED: // case Instruction::kIndexVaries: // case Instruction::kIndexInlineMethod: @@ -1607,6 +1612,226 @@ void DexLayout::DumpClass(int idx, char** last_package) { free(access_str); } +void DexLayout::DumpMethodHandle(int idx) { + const dex_ir::MethodHandleItem* mh = header_->MethodHandleItems()[idx]; + const char* type = nullptr; + bool is_instance = false; + bool is_invoke = false; + + switch (mh->GetMethodHandleType()) { + case DexFile::MethodHandleType::kStaticPut: + type = "put-static"; + is_instance = false; + is_invoke = false; + break; + case DexFile::MethodHandleType::kStaticGet: + type = "get-static"; + is_instance = false; + is_invoke = false; + break; + case DexFile::MethodHandleType::kInstancePut: + type = "put-instance"; + is_instance = true; + is_invoke = false; + break; + case DexFile::MethodHandleType::kInstanceGet: + type = "get-instance"; + is_instance = true; + is_invoke = false; + break; + case DexFile::MethodHandleType::kInvokeStatic: + type = "invoke-static"; + is_instance = false; + is_invoke = true; + break; + case DexFile::MethodHandleType::kInvokeInstance: + type = "invoke-instance"; + is_instance = true; + is_invoke = true; + break; + case DexFile::MethodHandleType::kInvokeConstructor: + type = "invoke-constructor"; + is_instance = true; + is_invoke = true; + break; + case DexFile::MethodHandleType::kInvokeDirect: + type = "invoke-direct"; + is_instance = true; + is_invoke = true; + break; + case DexFile::MethodHandleType::kInvokeInterface: + type = "invoke-interface"; + is_instance = true; + is_invoke = true; + break; + default: + type = "????"; + break; + } // switch + + const char* declaring_class; + const char* member; + std::string member_type; + if (type != nullptr) { + if (is_invoke) { + auto method_id = static_cast<dex_ir::MethodId*>(mh->GetFieldOrMethodId()); + declaring_class = method_id->Class()->GetStringId()->Data(); + member = method_id->Name()->Data(); + auto proto_id = method_id->Proto(); + member_type = GetSignatureForProtoId(proto_id); + } else { + auto field_id = static_cast<dex_ir::FieldId*>(mh->GetFieldOrMethodId()); + declaring_class = field_id->Class()->GetStringId()->Data(); + member = field_id->Name()->Data(); + member_type = field_id->Type()->GetStringId()->Data(); + } + if (is_instance) { + member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1); + } + } else { + type = "?"; + declaring_class = "?"; + member = "?"; + member_type = "?"; + } + + if (options_.output_format_ == kOutputPlain) { + fprintf(out_file_, "Method handle #%u:\n", idx); + fprintf(out_file_, " type : %s\n", type); + fprintf(out_file_, " target : %s %s\n", declaring_class, member); + fprintf(out_file_, " target_type : %s\n", member_type.c_str()); + } +} + +void DexLayout::DumpCallSite(int idx) { + const dex_ir::CallSiteId* call_site_id = header_->CallSiteIds()[idx]; + auto call_site_items = call_site_id->CallSiteItem()->GetEncodedValues(); + if (call_site_items->size() < 3) { + LOG(ERROR) << "ERROR: Call site " << idx << " has too few values."; + return; + } + uint32_t offset = call_site_id->CallSiteItem()->GetOffset(); + + auto it = call_site_items->begin(); + if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodHandle) { + LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a MethodHandle as its first item." + << " Found " << (*it)->Type(); + return; + } + auto method_handle = (*it)->GetMethodHandle(); + uint32_t method_handle_idx = method_handle->GetIndex(); + + it++; + if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kString) { + LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a String for method name " + << "as its second item." + << " Found " << (*it)->Type(); + return; + } + const char* method_name = (*it)->GetStringId()->Data(); + + it++; + if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodType) { + LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a Prototype as its third item." + << " Found " << (*it)->Type(); + return; + } + auto proto_id = (*it)->GetProtoId(); + std::string method_type = GetSignatureForProtoId(proto_id); + + it++; + if (options_.output_format_ == kOutputPlain) { + fprintf(out_file_, "Call site #%u: // offset %u\n", idx, offset); + fprintf(out_file_, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx); + fprintf(out_file_, " link_argument[1] : %s (String)\n", method_name); + fprintf(out_file_, " link_argument[2] : %s (MethodType)\n", method_type.c_str()); + } + + size_t argument = 3; + + while (it != call_site_items->end()) { + const char* type; + std::string value; + switch ((*it)->Type()) { + case EncodedArrayValueIterator::ValueType::kByte: + type = "byte"; + value = android::base::StringPrintf("%u", (*it)->GetByte()); + break; + case EncodedArrayValueIterator::ValueType::kShort: + type = "short"; + value = android::base::StringPrintf("%d", (*it)->GetShort()); + break; + case EncodedArrayValueIterator::ValueType::kChar: + type = "char"; + value = android::base::StringPrintf("%u", (*it)->GetChar()); + break; + case EncodedArrayValueIterator::ValueType::kInt: + type = "int"; + value = android::base::StringPrintf("%d", (*it)->GetInt()); + break; + case EncodedArrayValueIterator::ValueType::kLong: + type = "long"; + value = android::base::StringPrintf("%" PRId64, (*it)->GetLong()); + break; + case EncodedArrayValueIterator::ValueType::kFloat: + type = "float"; + value = android::base::StringPrintf("%g", (*it)->GetFloat()); + break; + case EncodedArrayValueIterator::ValueType::kDouble: + type = "double"; + value = android::base::StringPrintf("%g", (*it)->GetDouble()); + break; + case EncodedArrayValueIterator::ValueType::kMethodType: { + type = "MethodType"; + auto proto_id_item = (*it)->GetProtoId(); + value = GetSignatureForProtoId(proto_id_item); + break; + } + case EncodedArrayValueIterator::ValueType::kMethodHandle: { + type = "MethodHandle"; + auto method_handle_item = (*it)->GetMethodHandle(); + value = android::base::StringPrintf("%d", method_handle_item->GetIndex()); + break; + } + case EncodedArrayValueIterator::ValueType::kString: { + type = "String"; + auto string_id = (*it)->GetStringId(); + value = string_id->Data(); + break; + } + case EncodedArrayValueIterator::ValueType::kType: { + type = "Class"; + auto type_id = (*it)->GetTypeId(); + value = type_id->GetStringId()->Data(); + break; + } + case EncodedArrayValueIterator::ValueType::kField: + case EncodedArrayValueIterator::ValueType::kMethod: + case EncodedArrayValueIterator::ValueType::kEnum: + case EncodedArrayValueIterator::ValueType::kArray: + case EncodedArrayValueIterator::ValueType::kAnnotation: + // Unreachable based on current EncodedArrayValueIterator::Next(). + UNIMPLEMENTED(FATAL) << " type " << (*it)->Type(); + UNREACHABLE(); + case EncodedArrayValueIterator::ValueType::kNull: + type = "Null"; + value = "null"; + break; + case EncodedArrayValueIterator::ValueType::kBoolean: + type = "boolean"; + value = (*it)->GetBoolean() ? "true" : "false"; + break; + } + + if (options_.output_format_ == kOutputPlain) { + fprintf(out_file_, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type); + } + + it++; + argument++; + } +} + void DexLayout::DumpDexFile() { // Headers. if (options_.show_file_headers_) { @@ -1625,6 +1850,16 @@ void DexLayout::DumpDexFile() { DumpClass(i, &package); } // for + const uint32_t mh_items_size = header_->MethodHandleItems().Size(); + for (uint32_t i = 0; i < mh_items_size; i++) { + DumpMethodHandle(i); + } + + const uint32_t call_sites_size = header_->CallSiteIds().Size(); + for (uint32_t i = 0; i < call_sites_size; i++) { + DumpCallSite(i); + } + // Free the last package allocated. if (package != nullptr) { fprintf(out_file_, "</package>\n"); @@ -2009,23 +2244,19 @@ bool DexLayout::ProcessDexFile(const char* file_name, std::string location = "memory mapped file for " + std::string(file_name); // Dex file verifier cannot handle compact dex. bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone; - const ArtDexFileLoader dex_file_loader; DexContainer::Section* const main_section = (*dex_container)->GetMainSection(); DexContainer::Section* const data_section = (*dex_container)->GetDataSection(); DCHECK_EQ(file_size, main_section->Size()) << main_section->Size() << " " << data_section->Size(); + auto container = std::make_unique<DexLoaderContainer>( + main_section->Begin(), main_section->End(), data_section->Begin(), data_section->End()); + ArtDexFileLoader dex_file_loader(std::move(container), location); std::unique_ptr<const DexFile> output_dex_file( - dex_file_loader.OpenWithDataSection( - main_section->Begin(), - main_section->Size(), - data_section->Begin(), - data_section->Size(), - location, - /* location_checksum= */ 0, - /*oat_dex_file=*/ nullptr, - verify, - /*verify_checksum=*/ false, - error_msg)); + dex_file_loader.Open(/* location_checksum= */ 0, + /*oat_dex_file=*/nullptr, + verify, + /*verify_checksum=*/false, + error_msg)); CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << *error_msg; // Do IR-level comparison between input and output. This check ignores potential differences @@ -2059,10 +2290,10 @@ int DexLayout::ProcessFile(const char* file_name) { // all of which are Zip archives with "classes.dex" inside. const bool verify_checksum = !options_.ignore_bad_checksum_; std::string error_msg; - const ArtDexFileLoader dex_file_loader; + ArtDexFileLoader dex_file_loader(file_name); std::vector<std::unique_ptr<const DexFile>> dex_files; if (!dex_file_loader.Open( - file_name, file_name, /* verify= */ true, verify_checksum, &error_msg, &dex_files)) { + /* verify= */ true, verify_checksum, &error_msg, &dex_files)) { // Display returned error message to user. Note that this error behavior // differs from the error messages shown by the original Dalvik dexdump. LOG(ERROR) << error_msg; diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index bdc7863cd1..c6f76e5d9f 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -140,6 +140,8 @@ class DexLayout { void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset); void DumpCatches(const dex_ir::CodeItem* code); void DumpClass(int idx, char** last_package); + void DumpMethodHandle(int idx); + void DumpCallSite(int idx); void DumpClassAnnotations(int idx); void DumpClassDef(int idx); void DumpCode(uint32_t idx, @@ -199,6 +201,19 @@ class DexLayout { DISALLOW_COPY_AND_ASSIGN(DexLayout); }; +class DexLoaderContainer : public MemoryDexFileContainer { + public: + DexLoaderContainer(const uint8_t* begin, + const uint8_t* end, + const uint8_t* data_begin, + const uint8_t* data_end) + : MemoryDexFileContainer(begin, end), data_(data_begin, data_end - data_begin) {} + ArrayRef<const uint8_t> Data() const override { return data_; } + + private: + ArrayRef<const uint8_t> data_; +}; + } // namespace art #endif // ART_DEXLAYOUT_DEXLAYOUT_H_ diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc index 12674f5a5e..6c37b1d91f 100644 --- a/dexlayout/dexlayout_main.cc +++ b/dexlayout/dexlayout_main.cc @@ -180,7 +180,7 @@ int DexlayoutDriver(int argc, char** argv) { // Open alternative output file. FILE* out_file = stdout; if (options.output_file_name_) { - out_file = fopen(options.output_file_name_, "w"); + out_file = fopen(options.output_file_name_, "we"); if (!out_file) { PLOG(ERROR) << "Can't open " << options.output_file_name_; return 1; diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index 3c37e6dffb..03df258f04 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -14,13 +14,16 @@ * limitations under the License. */ -#include <sstream> -#include <string> -#include <vector> +#include "dexlayout.h" #include <sys/types.h> #include <unistd.h> +#include <memory> +#include <sstream> +#include <string> +#include <vector> + #include "base/common_art_test.h" #include "base/unix_file/fd_file.h" #include "base/utils.h" @@ -30,7 +33,6 @@ #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 "profile/profile_compilation_info.h" @@ -328,11 +330,9 @@ class DexLayoutTest : public CommonArtTest { const std::string& out_profile) { std::vector<std::unique_ptr<const DexFile>> dex_files; std::string error_msg; - const ArtDexFileLoader dex_file_loader; - bool result = dex_file_loader.Open(input_dex.c_str(), - input_dex, - /*verify=*/ true, - /*verify_checksum=*/ false, + ArtDexFileLoader dex_file_loader(input_dex); + bool result = dex_file_loader.Open(/*verify=*/true, + /*verify_checksum=*/false, &error_msg, &dex_files); @@ -772,14 +772,15 @@ TEST_F(DexLayoutTest, LinkData) { 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; + { + ArtDexFileLoader dex_file_loader(input_jar); + CHECK(dex_file_loader.Open(/*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); @@ -802,18 +803,16 @@ TEST_F(DexLayoutTest, ClassFilter) { &out, &error_msg); ASSERT_TRUE(result) << "Failed to run dexlayout " << error_msg; - 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(), - /* location_checksum= */ 0, - /*oat_dex_file=*/ nullptr, - /* verify= */ true, - /*verify_checksum=*/ false, - &error_msg)); + auto container = std::make_unique<DexLoaderContainer>(out->GetMainSection()->Begin(), + out->GetMainSection()->End(), + out->GetDataSection()->Begin(), + out->GetDataSection()->End()); + ArtDexFileLoader dex_file_loader(std::move(container), dex_file->GetLocation()); + std::unique_ptr<const DexFile> output_dex_file(dex_file_loader.Open(/* location_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(), options.class_filter_.size()); |