diff options
26 files changed, 634 insertions, 482 deletions
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h index a9bc5664c0..a627f65ed4 100644 --- a/compiler/optimizing/optimizing_unit_test.h +++ b/compiler/optimizing/optimizing_unit_test.h @@ -129,12 +129,10 @@ class OptimizingUnitTestHelper { // Create the dex file based on the fake data. Call the constructor so that we can use virtual // functions. Don't use the arena for the StandardDexFile otherwise the dex location leaks. dex_files_.emplace_back(new StandardDexFile( - dex_data, - sizeof(StandardDexFile::Header), + std::make_unique<NonOwningDexFileContainer>(dex_data, sizeof(StandardDexFile::Header)), "no_location", /*location_checksum*/ 0, - /*oat_dex_file*/ nullptr, - /*container*/ nullptr)); + /*oat_dex_file*/ nullptr)); return new (allocator) HGraph( allocator, diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index c9eb71d809..8dca889de5 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -2613,11 +2613,11 @@ class Dex2Oat FINAL { // set up. interpreter::UnstartedRuntime::Initialize(); - runtime_->GetClassLinker()->RunRootClinits(); + Thread* self = Thread::Current(); + runtime_->RunRootClinits(self); // Runtime::Create acquired the mutator_lock_ that is normally given away when we // Runtime::Start, give it away now so that we don't starve GC. - Thread* self = Thread::Current(); self->TransitionFromRunnableToSuspended(kNative); return true; diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc index 392ce1e7f5..05986ecce3 100644 --- a/libdexfile/dex/art_dex_file_loader.cc +++ b/libdexfile/dex/art_dex_file_loader.cc @@ -71,6 +71,14 @@ class MemMapContainer : public DexFileContainer { } } + const uint8_t* Begin() OVERRIDE { + return mem_map_->Begin(); + } + + size_t Size() OVERRIDE { + return mem_map_->Size(); + } + private: std::unique_ptr<MemMap> mem_map_; DISALLOW_COPY_AND_ASSIGN(MemMapContainer); @@ -164,17 +172,14 @@ std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const uint8_t* base, bool verify_checksum, std::string* error_msg) const { ScopedTrace trace(std::string("Open dex file from RAM ") + location); - return OpenCommon(base, - size, - /*data_base*/ nullptr, - /*data_size*/ 0u, + return OpenCommon(std::make_unique<NonOwningDexFileContainer>(base, size), + std::make_unique<EmptyDexFileContainer>(), location, location_checksum, oat_dex_file, verify, verify_checksum, error_msg, - /*container*/ nullptr, /*verify_result*/ nullptr); } @@ -194,18 +199,16 @@ std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const std::string& locatio return nullptr; } - std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), - map->Size(), - /*data_base*/ nullptr, - /*data_size*/ 0u, - location, - location_checksum, - kNoOatDexFile, - verify, - verify_checksum, - error_msg, - std::make_unique<MemMapContainer>(std::move(map)), - /*verify_result*/ nullptr); + std::unique_ptr<DexFile> dex_file = + OpenCommon(std::make_unique<MemMapContainer>(std::move(map)), + std::make_unique<EmptyDexFileContainer>(), + location, + location_checksum, + kNoOatDexFile, + verify, + verify_checksum, + error_msg, + /*verify_result*/ nullptr); // Opening CompactDex is only supported from vdex files. if (dex_file != nullptr && dex_file->IsCompactDexFile()) { *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files", @@ -323,18 +326,16 @@ std::unique_ptr<const DexFile> ArtDexFileLoader::OpenFile(int fd, const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin()); - std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), - map->Size(), - /*data_base*/ nullptr, - /*data_size*/ 0u, - location, - dex_header->checksum_, - kNoOatDexFile, - verify, - verify_checksum, - error_msg, - std::make_unique<MemMapContainer>(std::move(map)), - /*verify_result*/ nullptr); + std::unique_ptr<DexFile> dex_file = + OpenCommon(std::make_unique<MemMapContainer>(std::move(map)), + std::make_unique<EmptyDexFileContainer>(), + location, + dex_header->checksum_, + kNoOatDexFile, + verify, + verify_checksum, + error_msg, + /*verify_result*/ nullptr); // Opening CompactDex is only supported from vdex files. if (dex_file != nullptr && dex_file->IsCompactDexFile()) { @@ -398,18 +399,16 @@ std::unique_ptr<const DexFile> ArtDexFileLoader::OpenOneDexFileFromZip( return nullptr; } VerifyResult verify_result; - std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), - map->Size(), - /*data_base*/ nullptr, - /*data_size*/ 0u, - location, - zip_entry->GetCrc32(), - kNoOatDexFile, - verify, - verify_checksum, - error_msg, - std::make_unique<MemMapContainer>(std::move(map)), - &verify_result); + std::unique_ptr<DexFile> dex_file = + OpenCommon(std::make_unique<MemMapContainer>(std::move(map)), + std::make_unique<EmptyDexFileContainer>(), + location, + zip_entry->GetCrc32(), + kNoOatDexFile, + verify, + verify_checksum, + error_msg, + &verify_result); if (dex_file != nullptr && dex_file->IsCompactDexFile()) { *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files", location.c_str()); @@ -506,29 +505,24 @@ bool ArtDexFileLoader::OpenAllDexFilesFromZip( } } -std::unique_ptr<DexFile> ArtDexFileLoader::OpenCommon(const uint8_t* base, - size_t size, - const uint8_t* data_base, - size_t data_size, - const std::string& location, - uint32_t location_checksum, - const OatDexFile* oat_dex_file, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::unique_ptr<DexFileContainer> container, - VerifyResult* verify_result) { - std::unique_ptr<DexFile> dex_file = DexFileLoader::OpenCommon(base, - size, - data_base, - data_size, +std::unique_ptr<DexFile> ArtDexFileLoader::OpenCommon( + std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, + const std::string& location, + uint32_t location_checksum, + const OatDexFile* oat_dex_file, + bool verify, + bool verify_checksum, + std::string* error_msg, + VerifyResult* verify_result) { + std::unique_ptr<DexFile> dex_file = DexFileLoader::OpenCommon(std::move(main_section), + std::move(data_section), location, location_checksum, oat_dex_file, verify, verify_checksum, error_msg, - std::move(container), verify_result); // Check if this dex file is located in the framework directory. diff --git a/libdexfile/dex/art_dex_file_loader.h b/libdexfile/dex/art_dex_file_loader.h index a460aee60f..9f92b721a2 100644 --- a/libdexfile/dex/art_dex_file_loader.h +++ b/libdexfile/dex/art_dex_file_loader.h @@ -121,17 +121,17 @@ class ArtDexFileLoader : public DexFileLoader { std::string* error_msg, ZipOpenErrorCode* error_code) const; - static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base, - size_t size, - const uint8_t* data_base, - size_t data_size, + // main_section points to the header and fixed-sized objects (ids, etc.) + // If not empty (Begin != nullptr) data_section points to the dex file's variable-sized + // objects such as strings, class_data_items, etc. + static std::unique_ptr<DexFile> OpenCommon(std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, const std::string& location, uint32_t location_checksum, const OatDexFile* oat_dex_file, bool verify, bool verify_checksum, std::string* error_msg, - std::unique_ptr<DexFileContainer> container, VerifyResult* verify_result); }; diff --git a/libdexfile/dex/compact_dex_file.cc b/libdexfile/dex/compact_dex_file.cc index 302b59ee91..4bd1675423 100644 --- a/libdexfile/dex/compact_dex_file.cc +++ b/libdexfile/dex/compact_dex_file.cc @@ -84,22 +84,16 @@ uint32_t CompactDexFile::CalculateChecksum() const { return CalculateChecksum(Begin(), Size(), DataBegin(), DataSize()); } -CompactDexFile::CompactDexFile(const uint8_t* base, - size_t size, - const uint8_t* data_begin, - size_t data_size, +CompactDexFile::CompactDexFile(std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, const std::string& location, uint32_t location_checksum, - const OatDexFile* oat_dex_file, - std::unique_ptr<DexFileContainer> container) - : DexFile(base, - size, - data_begin, - data_size, + const OatDexFile* oat_dex_file) + : DexFile(std::move(main_section), + std::move(data_section), location, location_checksum, oat_dex_file, - std::move(container), /*is_compact_dex*/ true), debug_info_offsets_(DataBegin() + GetHeader().debug_info_offsets_pos_, GetHeader().debug_info_base_, diff --git a/libdexfile/dex/compact_dex_file.h b/libdexfile/dex/compact_dex_file.h index affc9a20b0..ffaa9a7155 100644 --- a/libdexfile/dex/compact_dex_file.h +++ b/libdexfile/dex/compact_dex_file.h @@ -284,14 +284,11 @@ class CompactDexFile : public DexFile { virtual uint32_t CalculateChecksum() const OVERRIDE; private: - CompactDexFile(const uint8_t* base, - size_t size, - const uint8_t* data_begin, - size_t data_size, + CompactDexFile(std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, const std::string& location, uint32_t location_checksum, - const OatDexFile* oat_dex_file, - std::unique_ptr<DexFileContainer> container); + const OatDexFile* oat_dex_file); CompactOffsetTable::Accessor debug_info_offsets_; diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc index f1f896058c..c2b478aded 100644 --- a/libdexfile/dex/dex_file.cc +++ b/libdexfile/dex/dex_file.cc @@ -73,61 +73,101 @@ uint32_t DexFile::ChecksumMemoryRange(const uint8_t* begin, size_t size) { } int DexFile::GetPermissions() const { - CHECK(container_.get() != nullptr); - return container_->GetPermissions(); + CHECK(main_section_ != nullptr); + return main_section_->GetPermissions(); } bool DexFile::IsReadOnly() const { - CHECK(container_.get() != nullptr); - return container_->IsReadOnly(); + CHECK(main_section_ != nullptr); + return main_section_->IsReadOnly(); } bool DexFile::EnableWrite() const { - CHECK(container_.get() != nullptr); - return container_->EnableWrite(); + CHECK(main_section_ != nullptr); + return main_section_->EnableWrite(); } bool DexFile::DisableWrite() const { - CHECK(container_.get() != nullptr); - return container_->DisableWrite(); + CHECK(main_section_ != nullptr); + return main_section_->DisableWrite(); } -DexFile::DexFile(const uint8_t* base, - size_t size, - const uint8_t* data_begin, - size_t data_size, +DexFile::DexFile(std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, const std::string& location, uint32_t location_checksum, const OatDexFile* oat_dex_file, - std::unique_ptr<DexFileContainer> container, bool is_compact_dex) - : begin_(base), - size_(size), - data_begin_(data_begin), - data_size_(data_size), + : main_section_(std::move(main_section)), location_(location), location_checksum_(location_checksum), - header_(reinterpret_cast<const Header*>(base)), - string_ids_(reinterpret_cast<const StringId*>(base + header_->string_ids_off_)), - type_ids_(reinterpret_cast<const TypeId*>(base + header_->type_ids_off_)), - field_ids_(reinterpret_cast<const FieldId*>(base + header_->field_ids_off_)), - method_ids_(reinterpret_cast<const MethodId*>(base + header_->method_ids_off_)), - proto_ids_(reinterpret_cast<const ProtoId*>(base + header_->proto_ids_off_)), - class_defs_(reinterpret_cast<const ClassDef*>(base + header_->class_defs_off_)), + header_(reinterpret_cast<const Header*>(main_section_->Begin())), + string_ids_(reinterpret_cast<const StringId*>(main_section_->Begin() + + header_->string_ids_off_)), + type_ids_(reinterpret_cast<const TypeId*>(main_section_->Begin() + header_->type_ids_off_)), + field_ids_(reinterpret_cast<const FieldId*>(main_section_->Begin() + + header_->field_ids_off_)), + method_ids_(reinterpret_cast<const MethodId*>(main_section_->Begin() + + header_->method_ids_off_)), + proto_ids_(reinterpret_cast<const ProtoId*>(main_section_->Begin() + + header_->proto_ids_off_)), + class_defs_(reinterpret_cast<const ClassDef*>(main_section_->Begin() + + header_->class_defs_off_)), method_handles_(nullptr), num_method_handles_(0), call_site_ids_(nullptr), num_call_site_ids_(0), oat_dex_file_(oat_dex_file), - container_(std::move(container)), is_compact_dex_(is_compact_dex), is_platform_dex_(false) { - CHECK(begin_ != nullptr) << GetLocation(); - CHECK_GT(size_, 0U) << GetLocation(); + CHECK(main_section_->Begin() != nullptr) << GetLocation(); + CHECK_GT(main_section_->Size(), 0U) << GetLocation(); // Check base (=header) alignment. // Must be 4-byte aligned to avoid undefined behavior when accessing // any of the sections via a pointer. - CHECK_ALIGNED(begin_, alignof(Header)); + CHECK_ALIGNED(main_section_->Begin(), alignof(Header)); + + data_section_ = std::move(data_section); + + InitializeSectionsFromMapList(); +} + +DexFile::DexFile(std::unique_ptr<DexFileContainer> main_section, + const std::string& location, + uint32_t location_checksum, + const OatDexFile* oat_dex_file, + bool is_compact_dex) + : main_section_(std::move(main_section)), + location_(location), + location_checksum_(location_checksum), + header_(reinterpret_cast<const Header*>(main_section_->Begin())), + string_ids_(reinterpret_cast<const StringId*>(main_section_->Begin() + + header_->string_ids_off_)), + type_ids_(reinterpret_cast<const TypeId*>(main_section_->Begin() + header_->type_ids_off_)), + field_ids_(reinterpret_cast<const FieldId*>(main_section_->Begin() + + header_->field_ids_off_)), + method_ids_(reinterpret_cast<const MethodId*>(main_section_->Begin() + + header_->method_ids_off_)), + proto_ids_(reinterpret_cast<const ProtoId*>(main_section_->Begin() + + header_->proto_ids_off_)), + class_defs_(reinterpret_cast<const ClassDef*>(main_section_->Begin() + + header_->class_defs_off_)), + method_handles_(nullptr), + num_method_handles_(0), + call_site_ids_(nullptr), + num_call_site_ids_(0), + oat_dex_file_(oat_dex_file), + is_compact_dex_(is_compact_dex), + is_platform_dex_(false) { + CHECK(main_section_->Begin() != nullptr) << GetLocation(); + CHECK_GT(main_section_->Size(), 0U) << GetLocation(); + // Check base (=header) alignment. + // Must be 4-byte aligned to avoid undefined behavior when accessing + // any of the sections via a pointer. + CHECK_ALIGNED(main_section_->Begin(), alignof(Header)); + + data_section_ = std::make_unique<NonOwningDexFileContainer>(main_section_->Begin(), + main_section_->Size()); InitializeSectionsFromMapList(); } diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h index 67abdca148..c94c786699 100644 --- a/libdexfile/dex/dex_file.h +++ b/libdexfile/dex/dex_file.h @@ -56,11 +56,48 @@ class DexFileContainer { virtual bool IsReadOnly() = 0; virtual bool EnableWrite() = 0; virtual bool DisableWrite() = 0; + virtual const uint8_t* Begin() = 0; + virtual size_t Size() = 0; private: DISALLOW_COPY_AND_ASSIGN(DexFileContainer); }; +class EmptyDexFileContainer FINAL : public DexFileContainer { + public: + EmptyDexFileContainer() { } + ~EmptyDexFileContainer() { } + + int GetPermissions() OVERRIDE { return 0; } + bool IsReadOnly() OVERRIDE { return true; } + bool EnableWrite() OVERRIDE { return false; } + bool DisableWrite() OVERRIDE { return false; } + const uint8_t* Begin() OVERRIDE { return nullptr; } + size_t Size() OVERRIDE { return 0U; } + + private: + DISALLOW_COPY_AND_ASSIGN(EmptyDexFileContainer); +}; + +class NonOwningDexFileContainer FINAL : public DexFileContainer { + public: + NonOwningDexFileContainer(const uint8_t* begin, size_t size) : begin_(begin), size_(size) { } + ~NonOwningDexFileContainer() { } + + int GetPermissions() OVERRIDE { return 0; } + bool IsReadOnly() OVERRIDE { return true; } + bool EnableWrite() OVERRIDE { return false; } + bool DisableWrite() OVERRIDE { return false; } + const uint8_t* Begin() OVERRIDE { return begin_; } + size_t Size() OVERRIDE { return size_; } + + private: + const uint8_t* begin_; + size_t size_; + + DISALLOW_COPY_AND_ASSIGN(NonOwningDexFileContainer); +}; + // Dex file is the API that exposes native dex files (ordinary dex files) and CompactDex. // Originally, the dex file format used by ART was mostly the same as APKs. The only change was // quickened opcodes and layout optimizations. @@ -754,7 +791,7 @@ class DexFile { // Check that the offset is in bounds. // Note that although the specification says that 0 should be used if there // is no debug information, some applications incorrectly use 0xFFFFFFFF. - return (debug_info_off == 0 || debug_info_off >= data_size_) + return (debug_info_off == 0 || debug_info_off >= DataSize()) ? nullptr : DataBegin() + debug_info_off; } @@ -929,19 +966,19 @@ class DexFile { bool DisableWrite() const; const uint8_t* Begin() const { - return begin_; + return main_section_->Begin(); } size_t Size() const { - return size_; + return main_section_->Size(); } const uint8_t* DataBegin() const { - return data_begin_; + return data_section_->Begin(); } size_t DataSize() const { - return data_size_; + return data_section_->Size(); } template <typename T> @@ -1009,7 +1046,7 @@ class DexFile { } DexFileContainer* GetContainer() const { - return container_.get(); + return main_section_.get(); } // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags. @@ -1021,14 +1058,25 @@ class DexFile { // First Dex format version supporting default methods. static const uint32_t kDefaultMethodsVersion = 37; - DexFile(const uint8_t* base, - size_t size, - const uint8_t* data_begin, - size_t data_size, + // For the two constructors, some notation needs explanation. + // Dex files consist of two sections: + // 1) "main" -- contains the header and fixed-sized objects (ids, etc.) + // 2) "data" -- contains variable-sized objects such as strings, class_data_items, etc. + // For StandardDexFile, both sections are addressed through one pointer. + // For CompactDexFile multiple dex files share one data section, but each has its + // own main section, and hence we need two pointers. + + DexFile(std::unique_ptr<DexFileContainer> main_section, + const std::string& location, + uint32_t location_checksum, + const OatDexFile* oat_dex_file, + bool is_compact_dex); + + DexFile(std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, const std::string& location, uint32_t location_checksum, const OatDexFile* oat_dex_file, - std::unique_ptr<DexFileContainer> container, bool is_compact_dex); // Top-level initializer that calls other Init methods. @@ -1040,17 +1088,11 @@ class DexFile { // Initialize section info for sections only found in map. Returns true on success. void InitializeSectionsFromMapList(); - // The base address of the memory mapping. - const uint8_t* const begin_; - - // The size of the underlying memory allocation in bytes. - const size_t size_; + // The container for the header and fixed portions. + std::unique_ptr<DexFileContainer> main_section_; - // The base address of the data section (same as Begin() for standard dex). - const uint8_t* const data_begin_; - - // The size of the data section. - const size_t data_size_; + // The container for the data section + std::unique_ptr<DexFileContainer> data_section_; // Typically the dex file name when available, alternatively some identifying string. // @@ -1098,9 +1140,6 @@ class DexFile { // null. mutable const OatDexFile* oat_dex_file_; - // Manages the underlying memory allocation. - std::unique_ptr<DexFileContainer> container_; - // If the dex file is a compact dex file. If false then the dex file is a standard dex file. const bool is_compact_dex_; diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc index 457addf114..156f655150 100644 --- a/libdexfile/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc @@ -54,8 +54,17 @@ class VectorContainer : public DexFileContainer { return false; } + uint8_t* Begin() OVERRIDE { + return vector_.data(); + } + + size_t Size() OVERRIDE { + return vector_.size(); + } + private: std::vector<uint8_t> vector_; + DISALLOW_COPY_AND_ASSIGN(VectorContainer); }; @@ -224,17 +233,14 @@ std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base, bool verify, bool verify_checksum, std::string* error_msg) const { - return OpenCommon(base, - size, - /*data_base*/ nullptr, - /*data_size*/ 0, + return OpenCommon(std::make_unique<NonOwningDexFileContainer>(base, size), + std::make_unique<EmptyDexFileContainer>(), location, location_checksum, oat_dex_file, verify, verify_checksum, error_msg, - /*container*/ nullptr, /*verify_result*/ nullptr); } @@ -249,17 +255,14 @@ std::unique_ptr<const DexFile> DexFileLoader::OpenWithDataSection( bool verify, bool verify_checksum, std::string* error_msg) const { - return OpenCommon(base, - size, - data_base, - data_size, + return OpenCommon(std::make_unique<NonOwningDexFileContainer>(base, size), + std::make_unique<NonOwningDexFileContainer>(data_base, data_size), location, location_checksum, oat_dex_file, verify, verify_checksum, error_msg, - /*container*/ nullptr, /*verify_result*/ nullptr); } @@ -307,49 +310,47 @@ bool DexFileLoader::OpenAll( return false; } -std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base, - size_t size, - const uint8_t* data_base, - size_t data_size, +std::unique_ptr<DexFile> DexFileLoader::OpenCommon(std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, const std::string& location, uint32_t location_checksum, const OatDexFile* oat_dex_file, bool verify, bool verify_checksum, std::string* error_msg, - std::unique_ptr<DexFileContainer> container, VerifyResult* verify_result) { if (verify_result != nullptr) { *verify_result = VerifyResult::kVerifyNotAttempted; } std::unique_ptr<DexFile> dex_file; - if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(base)) { - if (data_size != 0) { - CHECK_EQ(base, data_base) << "Unsupported for standard dex"; + if (main_section->Size() >= sizeof(StandardDexFile::Header) && + StandardDexFile::IsMagicValid(main_section->Begin())) { + if (data_section->Size() != 0) { + CHECK_EQ(main_section->Begin(), data_section->Begin()) << "Unsupported for standard dex"; } - dex_file.reset(new StandardDexFile(base, - size, + CHECK(main_section != nullptr); + CHECK(main_section->Begin() != nullptr); + dex_file.reset(new StandardDexFile(std::move(main_section), location, location_checksum, - oat_dex_file, - std::move(container))); - } else if (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(base)) { - if (data_base == nullptr) { + oat_dex_file)); + } else if (main_section->Size() >= sizeof(CompactDexFile::Header) && + CompactDexFile::IsMagicValid(main_section->Begin())) { + if (data_section->Begin() == nullptr) { // TODO: Is there a clean way to support both an explicit data section and reading the one // from the header. - CHECK_EQ(data_size, 0u); - const CompactDexFile::Header* const header = CompactDexFile::Header::At(base); - data_base = base + header->data_off_; - data_size = header->data_size_; + CHECK_EQ(data_section->Size(), 0u); + const CompactDexFile::Header* const header = + CompactDexFile::Header::At(main_section->Begin()); + data_section = + std::make_unique<NonOwningDexFileContainer>(main_section->Begin() + header->data_off_, + header->data_size_); } - dex_file.reset(new CompactDexFile(base, - size, - data_base, - data_size, + dex_file.reset(new CompactDexFile(std::move(main_section), + std::move(data_section), location, location_checksum, - oat_dex_file, - std::move(container))); + oat_dex_file)); // Disable verification for CompactDex input. verify = false; } else { @@ -409,19 +410,16 @@ std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip( return nullptr; } VerifyResult verify_result; - std::unique_ptr<const DexFile> dex_file = OpenCommon( - map.data(), - map.size(), - /*data_base*/ nullptr, - /*data_size*/ 0u, - location, - zip_entry->GetCrc32(), - /*oat_dex_file*/ nullptr, - verify, - verify_checksum, - error_msg, - std::make_unique<VectorContainer>(std::move(map)), - &verify_result); + std::unique_ptr<const DexFile> dex_file = + OpenCommon(std::make_unique<VectorContainer>(std::move(map)), + std::make_unique<EmptyDexFileContainer>(), + location, + zip_entry->GetCrc32(), + /*oat_dex_file*/ nullptr, + verify, + verify_checksum, + error_msg, + &verify_result); if (dex_file == nullptr) { if (verify_result == VerifyResult::kVerifyNotAttempted) { *error_code = ZipOpenErrorCode::kDexFileError; diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h index 01532203eb..0bd6446b7b 100644 --- a/libdexfile/dex/dex_file_loader.h +++ b/libdexfile/dex/dex_file_loader.h @@ -161,17 +161,17 @@ class DexFileLoader { kVerifyFailed }; - static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base, - size_t size, - const uint8_t* data_base, - size_t data_size, + // main_section points to the header and fixed-sized objects (ids, etc.) + // If not empty (Begin != nullptr) data_section points to the dex file's variable-sized + // objects such as strings, class_data_items, etc. + static std::unique_ptr<DexFile> OpenCommon(std::unique_ptr<DexFileContainer> main_section, + std::unique_ptr<DexFileContainer> data_section, const std::string& location, uint32_t location_checksum, const OatDexFile* oat_dex_file, bool verify, bool verify_checksum, std::string* error_msg, - std::unique_ptr<DexFileContainer> container, VerifyResult* verify_result); private: diff --git a/libdexfile/dex/dex_file_verifier_test.cc b/libdexfile/dex/dex_file_verifier_test.cc index c9bac0fef2..9d9f1bd025 100644 --- a/libdexfile/dex/dex_file_verifier_test.cc +++ b/libdexfile/dex/dex_file_verifier_test.cc @@ -56,7 +56,10 @@ static void FixUpChecksum(uint8_t* dex_file) { class DexFileVerifierTest : public testing::Test { protected: DexFile* GetDexFile(const uint8_t* dex_bytes, size_t length) { - return new StandardDexFile(dex_bytes, length, "tmp", 0, nullptr, nullptr); + return new StandardDexFile(std::make_unique<NonOwningDexFileContainer>(dex_bytes, length), + "tmp", + 0, + nullptr); } void VerifyModification(const char* dex_file_base64_content, diff --git a/libdexfile/dex/standard_dex_file.h b/libdexfile/dex/standard_dex_file.h index 999e5b99e9..0121d6039a 100644 --- a/libdexfile/dex/standard_dex_file.h +++ b/libdexfile/dex/standard_dex_file.h @@ -88,20 +88,14 @@ class StandardDexFile : public DexFile { } private: - StandardDexFile(const uint8_t* base, - size_t size, + StandardDexFile(std::unique_ptr<DexFileContainer> container, const std::string& location, uint32_t location_checksum, - const OatDexFile* oat_dex_file, - std::unique_ptr<DexFileContainer> container) - : DexFile(base, - size, - /*data_begin*/ base, - /*data_size*/ size, + const OatDexFile* oat_dex_file) + : DexFile(std::move(container), location, location_checksum, oat_dex_file, - std::move(container), /*is_compact_dex*/ false) {} friend class DexFileLoader; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c219d3dd68..4a5da1f1e9 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -864,8 +864,7 @@ void ClassLinker::FinishInit(Thread* self) { VLOG(startup) << "ClassLinker::FinishInit exiting"; } -void ClassLinker::RunRootClinits() { - Thread* self = Thread::Current(); +void ClassLinker::RunRootClinits(Thread* self) { for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); ++i) { ObjPtr<mirror::Class> c = GetClassRoot(ClassRoot(i), this); if (!c->IsArrayClass() && !c->IsPrimitive()) { @@ -873,6 +872,8 @@ void ClassLinker::RunRootClinits() { Handle<mirror::Class> h_class(hs.NewHandle(c)); EnsureInitialized(self, h_class, true, true); self->AssertNoPendingException(); + } else { + DCHECK(c->IsInitialized()); } } } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 30c242399d..e4d9c96696 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -405,7 +405,7 @@ class ClassLinker { // Initializes classes that have instances in the image but that have // <clinit> methods so they could not be initialized by the compiler. - void RunRootClinits() + void RunRootClinits(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index e40f1dbcdf..2a2aff1002 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -1521,12 +1521,12 @@ TEST_F(ClassLinkerTest, RegisterDexFileName) { dex_cache->SetLocation(location.Get()); const DexFile* old_dex_file = dex_cache->GetDexFile(); - std::unique_ptr<DexFile> dex_file(new StandardDexFile(old_dex_file->Begin(), - old_dex_file->Size(), - location->ToModifiedUtf8(), - 0u, - nullptr, - nullptr)); + std::unique_ptr<DexFile> dex_file( + new StandardDexFile(std::make_unique<NonOwningDexFileContainer>(old_dex_file->Begin(), + old_dex_file->Size()), + location->ToModifiedUtf8(), + 0u, + nullptr)); { WriterMutexLock mu(soa.Self(), *Locks::dex_lock_); // Check that inserting with a UTF16 name works. diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 75b091d98f..be39631e44 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -182,7 +182,7 @@ void CommonRuntimeTestImpl::FinalizeSetup() { { ScopedObjectAccess soa(Thread::Current()); - class_linker_->RunRootClinits(); + runtime_->RunRootClinits(soa.Self()); } // We're back in native, take the opportunity to initialize well known classes. diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index 12baede59b..edaa043ce6 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -2612,16 +2612,8 @@ mirror::Object* ConcurrentCopying::MarkNonMoving(Thread* const self, bool is_los = mark_bitmap == nullptr; if (!is_los && mark_bitmap->Test(ref)) { // Already marked. - if (kUseBakerReadBarrier) { - DCHECK(ref->GetReadBarrierState() == ReadBarrier::GrayState() || - ref->GetReadBarrierState() == ReadBarrier::WhiteState()); - } } else if (is_los && los_bitmap->Test(ref)) { // Already marked in LOS. - if (kUseBakerReadBarrier) { - DCHECK(ref->GetReadBarrierState() == ReadBarrier::GrayState() || - ref->GetReadBarrierState() == ReadBarrier::WhiteState()); - } } else { // Not marked. if (IsOnAllocStack(ref)) { diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index a961cb2597..e54674f72b 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -60,6 +60,7 @@ static jobjectArray Constructor_getExceptionTypes(JNIEnv* env, jobject javaMetho static jobject Constructor_newInstance0(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) { ScopedFastNativeObjectAccess soa(env); ObjPtr<mirror::Constructor> m = soa.Decode<mirror::Constructor>(javaMethod); + ArtMethod* constructor_art_method = m->GetArtMethod(); StackHandleScope<1> hs(soa.Self()); Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass())); if (UNLIKELY(c->IsAbstract())) { @@ -100,18 +101,20 @@ static jobject Constructor_newInstance0(JNIEnv* env, jobject javaMethod, jobject } // String constructor is replaced by a StringFactory method in InvokeMethod. - if (c->IsStringClass()) { + if (UNLIKELY(c->IsStringClass())) { return InvokeMethod(soa, javaMethod, nullptr, javaArgs, 2); } ObjPtr<mirror::Object> receiver = movable ? c->AllocObject(soa.Self()) : c->AllocNonMovableObject(soa.Self()); - if (receiver == nullptr) { + if (UNLIKELY(receiver == nullptr)) { + DCHECK(soa.Self()->IsExceptionPending()); return nullptr; } jobject javaReceiver = soa.AddLocalReference<jobject>(receiver); - InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, 2); - // Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod. + + InvokeConstructor(soa, constructor_art_method, receiver, javaArgs); + return javaReceiver; } diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 9e9c33caa8..646de757e0 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -457,6 +457,64 @@ void InvokeWithArgArray(const ScopedObjectAccessAlreadyRunnable& soa, method->Invoke(soa.Self(), args, arg_array->GetNumBytes(), result, shorty); } +ALWAYS_INLINE +bool CheckArgsForInvokeMethod(ArtMethod* np_method, + ObjPtr<mirror::ObjectArray<mirror::Object>> objects) + REQUIRES_SHARED(Locks::mutator_lock_) { + const DexFile::TypeList* classes = np_method->GetParameterTypeList(); + uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size(); + uint32_t arg_count = (objects == nullptr) ? 0 : objects->GetLength(); + if (UNLIKELY(arg_count != classes_size)) { + ThrowIllegalArgumentException(StringPrintf("Wrong number of arguments; expected %d, got %d", + classes_size, arg_count).c_str()); + return false; + } + return true; +} + +ALWAYS_INLINE +bool InvokeMethodImpl(const ScopedObjectAccessAlreadyRunnable& soa, + ArtMethod* m, + ArtMethod* np_method, + ObjPtr<mirror::Object> receiver, + ObjPtr<mirror::ObjectArray<mirror::Object>> objects, + const char** shorty, + JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) { + // Invoke the method. + uint32_t shorty_len = 0; + *shorty = np_method->GetShorty(&shorty_len); + ArgArray arg_array(*shorty, shorty_len); + if (!arg_array.BuildArgArrayFromObjectArray(receiver, objects, np_method, soa.Self())) { + CHECK(soa.Self()->IsExceptionPending()); + return false; + } + + InvokeWithArgArray(soa, m, &arg_array, result, *shorty); + + // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early. + if (soa.Self()->IsExceptionPending()) { + // If we get another exception when we are trying to wrap, then just use that instead. + ScopedLocalRef<jthrowable> th(soa.Env(), soa.Env()->ExceptionOccurred()); + soa.Self()->ClearException(); + jclass exception_class = soa.Env()->FindClass("java/lang/reflect/InvocationTargetException"); + if (exception_class == nullptr) { + soa.Self()->AssertPendingException(); + return false; + } + jmethodID mid = soa.Env()->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V"); + CHECK(mid != nullptr); + jobject exception_instance = soa.Env()->NewObject(exception_class, mid, th.get()); + if (exception_instance == nullptr) { + soa.Self()->AssertPendingException(); + return false; + } + soa.Env()->Throw(reinterpret_cast<jthrowable>(exception_instance)); + return false; + } + + return true; +} + } // anonymous namespace JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid, @@ -632,12 +690,7 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM ObjPtr<mirror::ObjectArray<mirror::Object>> objects = soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs); auto* np_method = m->GetInterfaceMethodIfProxy(kRuntimePointerSize); - const DexFile::TypeList* classes = np_method->GetParameterTypeList(); - uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size(); - uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0; - if (arg_count != classes_size) { - ThrowIllegalArgumentException(StringPrintf("Wrong number of arguments; expected %d, got %d", - classes_size, arg_count).c_str()); + if (!CheckArgsForInvokeMethod(np_method, objects)) { return nullptr; } @@ -661,39 +714,54 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM // Invoke the method. JValue result; - uint32_t shorty_len = 0; - const char* shorty = np_method->GetShorty(&shorty_len); - ArgArray arg_array(shorty, shorty_len); - if (!arg_array.BuildArgArrayFromObjectArray(receiver, objects, np_method, soa.Self())) { - CHECK(soa.Self()->IsExceptionPending()); + const char* shorty; + if (!InvokeMethodImpl(soa, m, np_method, receiver, objects, &shorty, &result)) { return nullptr; } + return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result)); +} - InvokeWithArgArray(soa, m, &arg_array, &result, shorty); +void InvokeConstructor(const ScopedObjectAccessAlreadyRunnable& soa, + ArtMethod* constructor, + ObjPtr<mirror::Object> receiver, + jobject javaArgs) { + // We want to make sure that the stack is not within a small distance from the + // protected region in case we are calling into a leaf function whose stack + // check has been elided. + if (UNLIKELY(__builtin_frame_address(0) < soa.Self()->GetStackEndForInterpreter(true))) { + ThrowStackOverflowError(soa.Self()); + return; + } - // Wrap any exception with "Ljava/lang/reflect/InvocationTargetException;" and return early. - if (soa.Self()->IsExceptionPending()) { - // If we get another exception when we are trying to wrap, then just use that instead. - ScopedLocalRef<jthrowable> th(soa.Env(), soa.Env()->ExceptionOccurred()); - soa.Self()->ClearException(); - jclass exception_class = soa.Env()->FindClass("java/lang/reflect/InvocationTargetException"); - if (exception_class == nullptr) { - soa.Self()->AssertPendingException(); - return nullptr; - } - jmethodID mid = soa.Env()->GetMethodID(exception_class, "<init>", "(Ljava/lang/Throwable;)V"); - CHECK(mid != nullptr); - jobject exception_instance = soa.Env()->NewObject(exception_class, mid, th.get()); - if (exception_instance == nullptr) { - soa.Self()->AssertPendingException(); - return nullptr; - } - soa.Env()->Throw(reinterpret_cast<jthrowable>(exception_instance)); - return nullptr; + if (kIsDebugBuild) { + CHECK(constructor->IsConstructor()); + + ObjPtr<mirror::Class> declaring_class = constructor->GetDeclaringClass(); + CHECK(declaring_class->IsInitialized()); + + // Calls to String.<init> should have been repplaced with with equivalent StringFactory calls. + CHECK(!declaring_class->IsStringClass()); + + // Check that the receiver is non-null and an instance of the field's declaring class. + CHECK(receiver != nullptr); + CHECK(VerifyObjectIsClass(receiver, declaring_class)); + CHECK_EQ(constructor, + receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(constructor, + kRuntimePointerSize)); } - // Box if necessary and return. - return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result)); + // Get our arrays of arguments and their types, and check they're the same size. + ObjPtr<mirror::ObjectArray<mirror::Object>> objects = + soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs); + ArtMethod* np_method = constructor->GetInterfaceMethodIfProxy(kRuntimePointerSize); + if (!CheckArgsForInvokeMethod(np_method, objects)) { + return; + } + + // Invoke the constructor. + JValue result; + const char* shorty; + InvokeMethodImpl(soa, constructor, np_method, receiver, objects, &shorty, &result); } ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) { diff --git a/runtime/reflection.h b/runtime/reflection.h index 4391bcd60b..74580a21e0 100644 --- a/runtime/reflection.h +++ b/runtime/reflection.h @@ -92,6 +92,14 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, size_t num_frames = 1) REQUIRES_SHARED(Locks::mutator_lock_); +// Special-casing of the above. Assumes that the method is the correct constructor, the class is +// initialized, and that the receiver is an instance of the class. +void InvokeConstructor(const ScopedObjectAccessAlreadyRunnable& soa, + ArtMethod* constructor, + ObjPtr<mirror::Object> receiver, + jobject args) + REQUIRES_SHARED(Locks::mutator_lock_); + ALWAYS_INLINE bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index f7674c89d3..a81c4d0518 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -713,6 +713,23 @@ std::string Runtime::GetCompilerExecutable() const { return compiler_executable; } +void Runtime::RunRootClinits(Thread* self) { + class_linker_->RunRootClinits(self); + + GcRoot<mirror::Throwable>* exceptions[] = { + &pre_allocated_OutOfMemoryError_when_throwing_exception_, + // &pre_allocated_OutOfMemoryError_when_throwing_oome_, // Same class as above. + // &pre_allocated_OutOfMemoryError_when_handling_stack_overflow_, // Same class as above. + &pre_allocated_NoClassDefFoundError_, + }; + for (GcRoot<mirror::Throwable>* exception : exceptions) { + StackHandleScope<1> hs(self); + Handle<mirror::Class> klass = hs.NewHandle<mirror::Class>(exception->Read()->GetClass()); + class_linker_->EnsureInitialized(self, klass, true, true); + self->AssertNoPendingException(); + } +} + bool Runtime::Start() { VLOG(startup) << "Runtime::Start entering"; @@ -742,8 +759,10 @@ bool Runtime::Start() { auto field_class(hs.NewHandle<mirror::Class>(GetClassRoot<mirror::Field>(class_roots))); class_linker_->EnsureInitialized(soa.Self(), class_class, true, true); + self->AssertNoPendingException(); // Field class is needed for register_java_net_InetAddress in libcore, b/28153851. class_linker_->EnsureInitialized(soa.Self(), field_class, true, true); + self->AssertNoPendingException(); } // InitNativeMethods needs to be after started_ so that the classes @@ -1090,15 +1109,30 @@ void Runtime::SetSentinel(mirror::Object* sentinel) { sentinel_ = GcRoot<mirror::Object>(sentinel); } -static inline void InitPreAllocatedException(Thread* self, - GcRoot<mirror::Throwable>* exception, - const char* exception_class_descriptor, - const char* msg) +static inline void CreatePreAllocatedException(Thread* self, + Runtime* runtime, + GcRoot<mirror::Throwable>* exception, + const char* exception_class_descriptor, + const char* msg) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK_EQ(self, Thread::Current()); - self->ThrowNewException(exception_class_descriptor, msg); - *exception = GcRoot<mirror::Throwable>(self->GetException()); - self->ClearException(); + ClassLinker* class_linker = runtime->GetClassLinker(); + // Allocate an object without initializing the class to allow non-trivial Throwable.<clinit>(). + ObjPtr<mirror::Class> klass = class_linker->FindSystemClass(self, exception_class_descriptor); + CHECK(klass != nullptr); + gc::AllocatorType allocator_type = runtime->GetHeap()->GetCurrentAllocator(); + ObjPtr<mirror::Throwable> exception_object = ObjPtr<mirror::Throwable>::DownCast( + klass->Alloc</* kIsInstrumented */ true>(self, allocator_type)); + CHECK(exception_object != nullptr); + *exception = GcRoot<mirror::Throwable>(exception_object); + // Initialize the "detailMessage" field. + ObjPtr<mirror::String> message = mirror::String::AllocFromModifiedUtf8(self, msg); + CHECK(message != nullptr); + ObjPtr<mirror::Class> throwable = GetClassRoot<mirror::Throwable>(class_linker); + ArtField* detailMessageField = + throwable->FindDeclaredInstanceField("detailMessage", "Ljava/lang/String;"); + CHECK(detailMessageField != nullptr); + detailMessageField->SetObject</* kTransactionActive */ false>(exception->Read(), message); } bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { @@ -1543,32 +1577,36 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { } else { // Pre-allocate an OutOfMemoryError for the case when we fail to // allocate the exception to be thrown. - InitPreAllocatedException(self, - &pre_allocated_OutOfMemoryError_when_throwing_exception_, - "Ljava/lang/OutOfMemoryError;", - "OutOfMemoryError thrown while trying to throw an exception; " - "no stack trace available"); + CreatePreAllocatedException(self, + this, + &pre_allocated_OutOfMemoryError_when_throwing_exception_, + "Ljava/lang/OutOfMemoryError;", + "OutOfMemoryError thrown while trying to throw an exception; " + "no stack trace available"); // Pre-allocate an OutOfMemoryError for the double-OOME case. - InitPreAllocatedException(self, - &pre_allocated_OutOfMemoryError_when_throwing_oome_, - "Ljava/lang/OutOfMemoryError;", - "OutOfMemoryError thrown while trying to throw OutOfMemoryError; " - "no stack trace available"); + CreatePreAllocatedException(self, + this, + &pre_allocated_OutOfMemoryError_when_throwing_oome_, + "Ljava/lang/OutOfMemoryError;", + "OutOfMemoryError thrown while trying to throw OutOfMemoryError; " + "no stack trace available"); // Pre-allocate an OutOfMemoryError for the case when we fail to // allocate while handling a stack overflow. - InitPreAllocatedException(self, - &pre_allocated_OutOfMemoryError_when_handling_stack_overflow_, - "Ljava/lang/OutOfMemoryError;", - "OutOfMemoryError thrown while trying to handle a stack overflow; " - "no stack trace available"); + CreatePreAllocatedException(self, + this, + &pre_allocated_OutOfMemoryError_when_handling_stack_overflow_, + "Ljava/lang/OutOfMemoryError;", + "OutOfMemoryError thrown while trying to handle a stack overflow; " + "no stack trace available"); // Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class // ahead of checking the application's class loader. - InitPreAllocatedException(self, - &pre_allocated_NoClassDefFoundError_, - "Ljava/lang/NoClassDefFoundError;", - "Class not found using the boot class loader; " - "no stack trace available"); + CreatePreAllocatedException(self, + this, + &pre_allocated_NoClassDefFoundError_, + "Ljava/lang/NoClassDefFoundError;", + "Class not found using the boot class loader; " + "no stack trace available"); } // Runtime initialization is largely done now. diff --git a/runtime/runtime.h b/runtime/runtime.h index d85490c0a6..f413733804 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -212,6 +212,8 @@ class Runtime { return finished_starting_; } + void RunRootClinits(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); + static Runtime* Current() { return instance_; } diff --git a/runtime/thread.cc b/runtime/thread.cc index 1a078d5fe6..19d9485f5e 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -2045,15 +2045,15 @@ void Thread::FinishStartup() { // Finish attaching the main thread. ScopedObjectAccess soa(Thread::Current()); - Thread::Current()->CreatePeer("main", false, runtime->GetMainThreadGroup()); - Thread::Current()->AssertNoPendingException(); + soa.Self()->CreatePeer("main", false, runtime->GetMainThreadGroup()); + soa.Self()->AssertNoPendingException(); - Runtime::Current()->GetClassLinker()->RunRootClinits(); + runtime->RunRootClinits(soa.Self()); // The thread counts as started from now on. We need to add it to the ThreadGroup. For regular // threads, this is done in Thread.start() on the Java side. - Thread::Current()->NotifyThreadGroup(soa, runtime->GetMainThreadGroup()); - Thread::Current()->AssertNoPendingException(); + soa.Self()->NotifyThreadGroup(soa, runtime->GetMainThreadGroup()); + soa.Self()->AssertNoPendingException(); } void Thread::Shutdown() { diff --git a/test/etc/default-build b/test/etc/default-build index 073ae2c796..8542ad0e92 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -321,7 +321,7 @@ function make_dexmerge() { } function make_hiddenapi() { - local args=() + local args=( "encode" ) while [[ $# -gt 0 ]]; do args+=("--dex=$1") shift diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc index 97e7f4cf3c..2e1ec5a541 100644 --- a/tools/hiddenapi/hiddenapi.cc +++ b/tools/hiddenapi/hiddenapi.cc @@ -61,18 +61,16 @@ NO_RETURN static void Usage(const char* fmt, ...) { va_end(ap); UsageError("Command: %s", CommandLine().c_str()); - UsageError("Usage: hiddenapi [options]..."); + UsageError("Usage: hiddenapi [command_name] [options]..."); UsageError(""); - UsageError(" --dex=<filename>: specify dex file whose members' access flags are to be set."); - UsageError(" At least one --dex parameter must be specified."); + UsageError(" Command \"encode\": encode API list membership in boot dex files"); + UsageError(" --dex=<filename>: dex file which belongs to boot class path,"); + UsageError(" the file will be overwritten"); UsageError(""); - UsageError(" --light-greylist=<filename>:"); - UsageError(" --dark-greylist=<filename>:"); - UsageError(" --blacklist=<filename>: text files with signatures of methods/fields to be marked"); - UsageError(" greylisted/blacklisted respectively. At least one list must be provided."); - UsageError(""); - UsageError(" --print-hidden-api: dump a list of marked methods/fields to the standard output."); - UsageError(" There is no indication which API category they belong to."); + UsageError(" --light-greylist=<filename>:"); + UsageError(" --dark-greylist=<filename>:"); + UsageError(" --blacklist=<filename>:"); + UsageError(" text files with signatures of methods/fields to be annotated"); UsageError(""); exit(EXIT_FAILURE); @@ -128,11 +126,6 @@ class DexMember { UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags); } - // Returns true if this member's API entry is in `list`. - bool IsOnApiList(const std::unordered_set<std::string>& list) const { - return list.find(GetApiEntry()) != list.end(); - } - // Constructs a string with a unique signature of this class member. std::string GetApiEntry() const { std::stringstream ss; @@ -164,112 +157,44 @@ class DexMember { const ClassDataItemIterator& it_; }; -class HiddenApi FINAL { +class ClassPath FINAL { public: - HiddenApi() : print_hidden_api_(false) {} - - void ParseArgs(int argc, char** argv) { - original_argc = argc; - original_argv = argv; - - android::base::InitLogging(argv); - - // Skip over the command name. - argv++; - argc--; - - if (argc == 0) { - Usage("No arguments specified"); - } + explicit ClassPath(const std::vector<std::string>& dex_paths) { + OpenDexFiles(dex_paths); + } - for (int i = 0; i < argc; ++i) { - const StringPiece option(argv[i]); - const bool log_options = false; - if (log_options) { - LOG(INFO) << "hiddenapi: option[" << i << "]=" << argv[i]; - } - if (option == "--print-hidden-api") { - print_hidden_api_ = true; - } else if (option.starts_with("--dex=")) { - dex_paths_.push_back(option.substr(strlen("--dex=")).ToString()); - } else if (option.starts_with("--light-greylist=")) { - light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString(); - } else if (option.starts_with("--dark-greylist=")) { - dark_greylist_path_ = option.substr(strlen("--dark-greylist=")).ToString(); - } else if (option.starts_with("--blacklist=")) { - blacklist_path_ = option.substr(strlen("--blacklist=")).ToString(); - } else { - Usage("Unknown argument '%s'", option.data()); + template<typename Fn> + void ForEachDexMember(Fn fn) { + for (auto& dex_file : dex_files_) { + for (uint32_t class_idx = 0; class_idx < dex_file->NumClassDefs(); ++class_idx) { + DexClass klass(*dex_file, class_idx); + const uint8_t* klass_data = klass.GetData(); + if (klass_data != nullptr) { + for (ClassDataItemIterator it(*dex_file, klass_data); it.HasNext(); it.Next()) { + DexMember member(klass, it); + fn(member); + } + } } } } - bool ProcessDexFiles() { - if (dex_paths_.empty()) { - Usage("No DEX files specified"); - } - - if (light_greylist_path_.empty() && dark_greylist_path_.empty() && blacklist_path_.empty()) { - Usage("No API file specified"); - } - - if (!light_greylist_path_.empty() && !OpenApiFile(light_greylist_path_, &light_greylist_)) { - return false; - } - - if (!dark_greylist_path_.empty() && !OpenApiFile(dark_greylist_path_, &dark_greylist_)) { - return false; - } - - if (!blacklist_path_.empty() && !OpenApiFile(blacklist_path_, &blacklist_)) { - return false; - } - - MemMap::Init(); - if (!OpenDexFiles()) { - return false; - } - - DCHECK(!dex_files_.empty()); + void UpdateDexChecksums() { for (auto& dex_file : dex_files_) { - CategorizeAllClasses(*dex_file.get()); + // Obtain a writeable pointer to the dex header. + DexFile::Header* header = const_cast<DexFile::Header*>(&dex_file->GetHeader()); + // Recalculate checksum and overwrite the value in the header. + header->checksum_ = dex_file->CalculateChecksum(); } - - UpdateDexChecksums(); - return true; } private: - bool OpenApiFile(const std::string& path, std::unordered_set<std::string>* list) { - DCHECK(list->empty()); - DCHECK(!path.empty()); - - std::ifstream api_file(path, std::ifstream::in); - if (api_file.fail()) { - LOG(ERROR) << "Unable to open file '" << path << "' " << strerror(errno); - return false; - } - - for (std::string line; std::getline(api_file, line);) { - list->insert(line); - } - - api_file.close(); - return true; - } - - bool OpenDexFiles() { + void OpenDexFiles(const std::vector<std::string>& dex_paths) { ArtDexFileLoader dex_loader; - DCHECK(dex_files_.empty()); - - for (const std::string& filename : dex_paths_) { - std::string error_msg; - + std::string error_msg; + for (const std::string& filename : dex_paths) { File fd(filename.c_str(), O_RDWR, /* check_usage */ false); - if (fd.Fd() == -1) { - LOG(ERROR) << "Unable to open file '" << filename << "': " << strerror(errno); - return false; - } + CHECK_NE(fd.Fd(), -1) << "Unable to open file '" << filename << "': " << strerror(errno); // Memory-map the dex file with MAP_SHARED flag so that changes in memory // propagate to the underlying file. We run dex file verification as if @@ -283,96 +208,127 @@ class HiddenApi FINAL { /* verify_checksum */ true, /* mmap_shared */ true, &error_msg)); - if (dex_file.get() == nullptr) { - LOG(ERROR) << "Open failed for '" << filename << "' " << error_msg; - return false; - } + CHECK(dex_file.get() != nullptr) << "Open failed for '" << filename << "' " << error_msg; + CHECK(dex_file->IsStandardDexFile()) << "Expected a standard dex file '" << filename << "'"; + CHECK(dex_file->EnableWrite()) + << "Failed to enable write permission for '" << filename << "'"; + dex_files_.push_back(std::move(dex_file)); + } + } - if (!dex_file->IsStandardDexFile()) { - LOG(ERROR) << "Expected a standard dex file '" << filename << "'"; - return false; - } + // Opened DEX files. Note that these are opened as `const` but may be written into. + std::vector<std::unique_ptr<const DexFile>> dex_files_; +}; - // Change the protection of the memory mapping to read-write. - if (!dex_file->EnableWrite()) { - LOG(ERROR) << "Failed to enable write permission for '" << filename << "'"; - return false; - } +class HiddenApi FINAL { + public: + HiddenApi() {} - dex_files_.push_back(std::move(dex_file)); + void Run(int argc, char** argv) { + switch (ParseArgs(argc, argv)) { + case Command::kEncode: + EncodeAccessFlags(); + break; } - return true; } - void CategorizeAllClasses(const DexFile& dex_file) { - for (uint32_t class_idx = 0; class_idx < dex_file.NumClassDefs(); ++class_idx) { - DexClass klass(dex_file, class_idx); - const uint8_t* klass_data = klass.GetData(); - if (klass_data == nullptr) { - continue; - } - - for (ClassDataItemIterator it(klass.GetDexFile(), klass_data); it.HasNext(); it.Next()) { - DexMember member(klass, it); - - // Catagorize member and overwrite its access flags. - // Note that if a member appears on multiple API lists, it will be categorized - // as the strictest. - bool is_hidden = true; - if (member.IsOnApiList(blacklist_)) { - member.SetHidden(HiddenApiAccessFlags::kBlacklist); - } else if (member.IsOnApiList(dark_greylist_)) { - member.SetHidden(HiddenApiAccessFlags::kDarkGreylist); - } else if (member.IsOnApiList(light_greylist_)) { - member.SetHidden(HiddenApiAccessFlags::kLightGreylist); - } else { - member.SetHidden(HiddenApiAccessFlags::kWhitelist); - is_hidden = false; - } + private: + enum class Command { + // Currently just one command. A "list" command will be added for generating + // a full list of boot class members. + kEncode, + }; + + Command ParseArgs(int argc, char** argv) { + // Skip over the binary's path. + argv++; + argc--; - if (print_hidden_api_ && is_hidden) { - std::cout << member.GetApiEntry() << std::endl; + if (argc > 0) { + const StringPiece command(argv[0]); + if (command == "encode") { + for (int i = 1; i < argc; ++i) { + const StringPiece option(argv[i]); + if (option.starts_with("--dex=")) { + boot_dex_paths_.push_back(option.substr(strlen("--dex=")).ToString()); + } else if (option.starts_with("--light-greylist=")) { + light_greylist_path_ = option.substr(strlen("--light-greylist=")).ToString(); + } else if (option.starts_with("--dark-greylist=")) { + dark_greylist_path_ = option.substr(strlen("--dark-greylist=")).ToString(); + } else if (option.starts_with("--blacklist=")) { + blacklist_path_ = option.substr(strlen("--blacklist=")).ToString(); + } else { + Usage("Unknown argument '%s'", option.data()); + } } + return Command::kEncode; + } else { + Usage("Unknown command '%s'", command.data()); } + } else { + Usage("No command specified"); } } - void UpdateDexChecksums() { - for (auto& dex_file : dex_files_) { - // Obtain a writeable pointer to the dex header. - DexFile::Header* header = const_cast<DexFile::Header*>(&dex_file->GetHeader()); - // Recalculate checksum and overwrite the value in the header. - header->checksum_ = dex_file->CalculateChecksum(); + void EncodeAccessFlags() { + if (boot_dex_paths_.empty()) { + Usage("No boot DEX files specified"); } + + // Load dex signatures. + std::map<std::string, HiddenApiAccessFlags::ApiList> api_list; + OpenApiFile(light_greylist_path_, api_list, HiddenApiAccessFlags::kLightGreylist); + OpenApiFile(dark_greylist_path_, api_list, HiddenApiAccessFlags::kDarkGreylist); + OpenApiFile(blacklist_path_, api_list, HiddenApiAccessFlags::kBlacklist); + + // Open all dex files. + ClassPath boot_class_path(boot_dex_paths_); + + // Set access flags of all members. + boot_class_path.ForEachDexMember([&api_list](DexMember& boot_member) { + auto it = api_list.find(boot_member.GetApiEntry()); + if (it == api_list.end()) { + boot_member.SetHidden(HiddenApiAccessFlags::kWhitelist); + } else { + boot_member.SetHidden(it->second); + } + }); + + boot_class_path.UpdateDexChecksums(); } - // Print signatures of APIs which have been grey-/blacklisted. - bool print_hidden_api_; + void OpenApiFile(const std::string& path, + std::map<std::string, HiddenApiAccessFlags::ApiList>& api_list, + HiddenApiAccessFlags::ApiList membership) { + if (path.empty()) { + return; + } + + std::ifstream api_file(path, std::ifstream::in); + CHECK(!api_file.fail()) << "Unable to open file '" << path << "' " << strerror(errno); + + for (std::string line; std::getline(api_file, line);) { + CHECK(api_list.find(line) == api_list.end()) + << "Duplicate entry: " << line << " (" << api_list[line] << " and " << membership << ")"; + api_list.emplace(line, membership); + } + api_file.close(); + } // Paths to DEX files which should be processed. - std::vector<std::string> dex_paths_; + std::vector<std::string> boot_dex_paths_; // Paths to text files which contain the lists of API members. std::string light_greylist_path_; std::string dark_greylist_path_; std::string blacklist_path_; - - // Opened DEX files. Note that these are opened as `const` but eventually will be written into. - std::vector<std::unique_ptr<const DexFile>> dex_files_; - - // Signatures of DEX members loaded from `light_greylist_path_`, `dark_greylist_path_`, - // `blacklist_path_`. - std::unordered_set<std::string> light_greylist_; - std::unordered_set<std::string> dark_greylist_; - std::unordered_set<std::string> blacklist_; }; } // namespace art int main(int argc, char** argv) { - art::HiddenApi hiddenapi; - - // Parse arguments. Argument mistakes will lead to exit(EXIT_FAILURE) in UsageError. - hiddenapi.ParseArgs(argc, argv); - return hiddenapi.ProcessDexFiles() ? EXIT_SUCCESS : EXIT_FAILURE; + android::base::InitLogging(argv); + art::MemMap::Init(); + art::HiddenApi().Run(argc, argv); + return EXIT_SUCCESS; } diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc index ed880e0e92..aa87f21e7f 100644 --- a/tools/hiddenapi/hiddenapi_test.cc +++ b/tools/hiddenapi/hiddenapi_test.cc @@ -66,15 +66,18 @@ class HiddenApiTest : public CommonRuntimeTest { std::vector<std::string> argv_str; argv_str.push_back(GetHiddenApiCmd()); argv_str.insert(argv_str.end(), extra_args.begin(), extra_args.end()); + argv_str.push_back("encode"); argv_str.push_back("--dex=" + out_dex->GetFilename()); argv_str.push_back("--light-greylist=" + light_greylist.GetFilename()); argv_str.push_back("--dark-greylist=" + dark_greylist.GetFilename()); argv_str.push_back("--blacklist=" + blacklist.GetFilename()); int return_code = ExecAndReturnCode(argv_str, &error); - if (return_code != 0) { - LOG(FATAL) << "HiddenApi binary exited with unexpected return code " << return_code; + if (return_code == 0) { + return OpenDex(*out_dex); + } else { + LOG(ERROR) << "HiddenApi binary exited with unexpected return code " << return_code; + return nullptr; } - return OpenDex(*out_dex); } std::unique_ptr<const DexFile> OpenDex(const ScratchFile& file) { @@ -226,6 +229,7 @@ TEST_F(HiddenApiTest, InstanceFieldNoMatch) { OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetIFieldHiddenFlags(*dex_file)); } @@ -235,6 +239,7 @@ TEST_F(HiddenApiTest, InstanceFieldLightGreylistMatch) { OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetIFieldHiddenFlags(*dex_file)); } @@ -244,6 +249,7 @@ TEST_F(HiddenApiTest, InstanceFieldDarkGreylistMatch) { OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl; OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIFieldHiddenFlags(*dex_file)); } @@ -253,6 +259,7 @@ TEST_F(HiddenApiTest, InstanceFieldBlacklistMatch) { OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->ifield:I" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIFieldHiddenFlags(*dex_file)); } @@ -262,7 +269,7 @@ TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch1) { OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl; OpenStream(blacklist) << "LMain;->ifield:I" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIFieldHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch2) { @@ -271,7 +278,7 @@ TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch2) { OpenStream(dark_greylist) << "LMain;->ifield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->ifield:I" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIFieldHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch3) { @@ -280,7 +287,7 @@ TEST_F(HiddenApiTest, InstanceFieldTwoListsMatch3) { OpenStream(dark_greylist) << "LMain;->ifield:I" << std::endl; OpenStream(blacklist) << "LMain;->ifield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIFieldHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticFieldNoMatch) { @@ -289,6 +296,7 @@ TEST_F(HiddenApiTest, StaticFieldNoMatch) { OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSFieldHiddenFlags(*dex_file)); } @@ -298,6 +306,7 @@ TEST_F(HiddenApiTest, StaticFieldLightGreylistMatch) { OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSFieldHiddenFlags(*dex_file)); } @@ -307,6 +316,7 @@ TEST_F(HiddenApiTest, StaticFieldDarkGreylistMatch) { OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSFieldHiddenFlags(*dex_file)); } @@ -316,6 +326,7 @@ TEST_F(HiddenApiTest, StaticFieldBlacklistMatch) { OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSFieldHiddenFlags(*dex_file)); } @@ -325,7 +336,7 @@ TEST_F(HiddenApiTest, StaticFieldTwoListsMatch1) { OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSFieldHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticFieldTwoListsMatch2) { @@ -334,7 +345,7 @@ TEST_F(HiddenApiTest, StaticFieldTwoListsMatch2) { OpenStream(dark_greylist) << "LMain;->sfield:LBadType2;" << std::endl; OpenStream(blacklist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSFieldHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticFieldTwoListsMatch3) { @@ -343,7 +354,7 @@ TEST_F(HiddenApiTest, StaticFieldTwoListsMatch3) { OpenStream(dark_greylist) << "LMain;->sfield:Ljava/lang/Object;" << std::endl; OpenStream(blacklist) << "LMain;->sfield:LBadType3;" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSFieldHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceMethodNoMatch) { @@ -352,6 +363,7 @@ TEST_F(HiddenApiTest, InstanceMethodNoMatch) { OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetIMethodHiddenFlags(*dex_file)); } @@ -361,6 +373,7 @@ TEST_F(HiddenApiTest, InstanceMethodLightGreylistMatch) { OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetIMethodHiddenFlags(*dex_file)); } @@ -370,6 +383,7 @@ TEST_F(HiddenApiTest, InstanceMethodDarkGreylistMatch) { OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl; OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIMethodHiddenFlags(*dex_file)); } @@ -379,6 +393,7 @@ TEST_F(HiddenApiTest, InstanceMethodBlacklistMatch) { OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIMethodHiddenFlags(*dex_file)); } @@ -388,7 +403,7 @@ TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch1) { OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl; OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch2) { @@ -397,7 +412,7 @@ TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch2) { OpenStream(dark_greylist) << "LMain;->imethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->imethod(J)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetIMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch3) { @@ -406,7 +421,7 @@ TEST_F(HiddenApiTest, InstanceMethodTwoListsMatch3) { OpenStream(dark_greylist) << "LMain;->imethod(J)V" << std::endl; OpenStream(blacklist) << "LMain;->imethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetIMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticMethodNoMatch) { @@ -415,6 +430,7 @@ TEST_F(HiddenApiTest, StaticMethodNoMatch) { OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSMethodHiddenFlags(*dex_file)); } @@ -424,6 +440,7 @@ TEST_F(HiddenApiTest, StaticMethodLightGreylistMatch) { OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSMethodHiddenFlags(*dex_file)); } @@ -433,6 +450,7 @@ TEST_F(HiddenApiTest, StaticMethodDarkGreylistMatch) { OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSMethodHiddenFlags(*dex_file)); } @@ -442,6 +460,7 @@ TEST_F(HiddenApiTest, StaticMethodBlacklistMatch) { OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSMethodHiddenFlags(*dex_file)); } @@ -451,7 +470,7 @@ TEST_F(HiddenApiTest, StaticMethodTwoListsMatch1) { OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticMethodTwoListsMatch2) { @@ -460,7 +479,7 @@ TEST_F(HiddenApiTest, StaticMethodTwoListsMatch2) { OpenStream(dark_greylist) << "LMain;->smethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticMethodTwoListsMatch3) { @@ -469,7 +488,7 @@ TEST_F(HiddenApiTest, StaticMethodTwoListsMatch3) { OpenStream(dark_greylist) << "LMain;->smethod(Ljava/lang/Object;)V" << std::endl; OpenStream(blacklist) << "LMain;->smethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceNativeMethodNoMatch) { @@ -478,6 +497,7 @@ TEST_F(HiddenApiTest, InstanceNativeMethodNoMatch) { OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetINMethodHiddenFlags(*dex_file)); } @@ -487,6 +507,7 @@ TEST_F(HiddenApiTest, InstanceNativeMethodLightGreylistMatch) { OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetINMethodHiddenFlags(*dex_file)); } @@ -496,6 +517,7 @@ TEST_F(HiddenApiTest, InstanceNativeMethodDarkGreylistMatch) { OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl; OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetINMethodHiddenFlags(*dex_file)); } @@ -505,6 +527,7 @@ TEST_F(HiddenApiTest, InstanceNativeMethodBlacklistMatch) { OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetINMethodHiddenFlags(*dex_file)); } @@ -514,7 +537,7 @@ TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch1) { OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl; OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetINMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch2) { @@ -523,7 +546,7 @@ TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch2) { OpenStream(dark_greylist) << "LMain;->inmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->inmethod(C)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetINMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch3) { @@ -532,7 +555,7 @@ TEST_F(HiddenApiTest, InstanceNativeMethodTwoListsMatch3) { OpenStream(dark_greylist) << "LMain;->inmethod(C)V" << std::endl; OpenStream(blacklist) << "LMain;->inmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetINMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticNativeMethodNoMatch) { @@ -541,6 +564,7 @@ TEST_F(HiddenApiTest, StaticNativeMethodNoMatch) { OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kWhitelist, GetSNMethodHiddenFlags(*dex_file)); } @@ -550,6 +574,7 @@ TEST_F(HiddenApiTest, StaticNativeMethodLightGreylistMatch) { OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kLightGreylist, GetSNMethodHiddenFlags(*dex_file)); } @@ -559,6 +584,7 @@ TEST_F(HiddenApiTest, StaticNativeMethodDarkGreylistMatch) { OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSNMethodHiddenFlags(*dex_file)); } @@ -568,6 +594,7 @@ TEST_F(HiddenApiTest, StaticNativeMethodBlacklistMatch) { OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); + ASSERT_NE(dex_file.get(), nullptr); ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSNMethodHiddenFlags(*dex_file)); } @@ -577,7 +604,7 @@ TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch1) { OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSNMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch2) { @@ -586,7 +613,7 @@ TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch2) { OpenStream(dark_greylist) << "LMain;->snmethod(LBadType2;)V" << std::endl; OpenStream(blacklist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kBlacklist, GetSNMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch3) { @@ -595,7 +622,7 @@ TEST_F(HiddenApiTest, StaticNativeMethodTwoListsMatch3) { OpenStream(dark_greylist) << "LMain;->snmethod(Ljava/lang/Integer;)V" << std::endl; OpenStream(blacklist) << "LMain;->snmethod(LBadType3;)V" << std::endl; auto dex_file = RunHiddenApi(light_greylist, dark_greylist, blacklist, {}, &dex); - ASSERT_EQ(HiddenApiAccessFlags::kDarkGreylist, GetSNMethodHiddenFlags(*dex_file)); + ASSERT_EQ(dex_file.get(), nullptr); } } // namespace art |