summaryrefslogtreecommitdiffstats
path: root/libdexfile
diff options
context:
space:
mode:
authorDavid Brazdil <dbrazdil@google.com>2018-10-27 21:45:15 +0000
committerDavid Brazdil <dbrazdil@google.com>2018-10-28 20:00:03 +0000
commit20c765f645fa9be77e045463c5064d41211a2815 (patch)
treedcb9dfb6bf5363d1e933589f22339dc999b96703 /libdexfile
parentce2a00daa92670a4fc01ef59fdbc3769a846f69c (diff)
downloadart-20c765f645fa9be77e045463c5064d41211a2815.tar.gz
art-20c765f645fa9be77e045463c5064d41211a2815.tar.bz2
art-20c765f645fa9be77e045463c5064d41211a2815.zip
Revert^4: Add dex item for hiddenapi flags
Move hiddenapi access flags to own data section so as to: (a) increase amount of information stored per method/field (b) use encoding which can be supported long-term. The dex item is implemented as: - array of offsets indexed by class def index - streams of uleb-128 encoded flags. Offsets in array point to the beginning of the flags stream for the given class def. Flags are encoded in the same order as fields and methods are encoded in class data. Zero offset means that the class either does not have class data, or all of its flags are zero. The patch updates: (a) libdexfile with data structure declarations and accessor methods, (b) hiddenapi tool to create the new item from hiddenapi lists and insert it into the given dex file, (c) dexlayout to copy the flags into compact dex, (d) dex file verifier to verify the item. It also removes skipping of verification for boot class path dex files as those now pass DexFileVerifier, and removes the need for removing the flags for JVMTI. The size increase is 450 KB. This reverts commit d33d318685ec4a1c9e7995c914c104ab6487513b. Change-Id: Id00e0efb38ee1eab8d7ed5c645a7778b6b94b849 Test: phone boots Test: m test-art
Diffstat (limited to 'libdexfile')
-rw-r--r--libdexfile/dex/class_accessor-inl.h80
-rw-r--r--libdexfile/dex/class_accessor.h60
-rw-r--r--libdexfile/dex/dex_file.cc31
-rw-r--r--libdexfile/dex/dex_file.h44
-rw-r--r--libdexfile/dex/dex_file_verifier.cc118
-rw-r--r--libdexfile/dex/dex_file_verifier.h1
-rw-r--r--libdexfile/dex/hidden_api_access_flags.h93
-rw-r--r--libdexfile/dex/modifiers.h5
8 files changed, 261 insertions, 171 deletions
diff --git a/libdexfile/dex/class_accessor-inl.h b/libdexfile/dex/class_accessor-inl.h
index 21db2cf2be..40bca564ae 100644
--- a/libdexfile/dex/class_accessor-inl.h
+++ b/libdexfile/dex/class_accessor-inl.h
@@ -28,34 +28,54 @@ namespace art {
inline ClassAccessor::ClassAccessor(const ClassIteratorData& data)
: ClassAccessor(data.dex_file_, data.class_def_idx_) {}
-inline ClassAccessor::ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def)
- : ClassAccessor(dex_file, dex_file.GetIndexForClassDef(class_def)) {}
+inline ClassAccessor::ClassAccessor(const DexFile& dex_file,
+ const DexFile::ClassDef& class_def,
+ bool parse_hiddenapi_class_data)
+ : ClassAccessor(dex_file,
+ dex_file.GetClassData(class_def),
+ dex_file.GetIndexForClassDef(class_def),
+ parse_hiddenapi_class_data) {}
inline ClassAccessor::ClassAccessor(const DexFile& dex_file, uint32_t class_def_index)
- : ClassAccessor(dex_file,
- dex_file.GetClassData(dex_file.GetClassDef(class_def_index)),
- class_def_index) {}
+ : ClassAccessor(dex_file, dex_file.GetClassDef(class_def_index)) {}
inline ClassAccessor::ClassAccessor(const DexFile& dex_file,
const uint8_t* class_data,
- uint32_t class_def_index)
+ uint32_t class_def_index,
+ bool parse_hiddenapi_class_data)
: dex_file_(dex_file),
class_def_index_(class_def_index),
ptr_pos_(class_data),
+ hiddenapi_ptr_pos_(nullptr),
num_static_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
num_instance_fields_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
num_direct_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u),
- num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {}
+ num_virtual_methods_(ptr_pos_ != nullptr ? DecodeUnsignedLeb128(&ptr_pos_) : 0u) {
+ if (parse_hiddenapi_class_data && class_def_index != DexFile::kDexNoIndex32) {
+ const DexFile::HiddenapiClassData* hiddenapi_class_data = dex_file.GetHiddenapiClassData();
+ if (hiddenapi_class_data != nullptr) {
+ hiddenapi_ptr_pos_ = hiddenapi_class_data->GetFlagsPointer(class_def_index);
+ }
+ }
+}
inline void ClassAccessor::Method::Read() {
index_ += DecodeUnsignedLeb128(&ptr_pos_);
access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
code_off_ = DecodeUnsignedLeb128(&ptr_pos_);
+ if (hiddenapi_ptr_pos_ != nullptr) {
+ hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
+ DCHECK(HiddenApiAccessFlags::AreValidFlags(hiddenapi_flags_));
+ }
}
inline void ClassAccessor::Field::Read() {
index_ += DecodeUnsignedLeb128(&ptr_pos_);
access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
+ if (hiddenapi_ptr_pos_ != nullptr) {
+ hiddenapi_flags_ = DecodeUnsignedLeb128(&hiddenapi_ptr_pos_);
+ DCHECK(HiddenApiAccessFlags::AreValidFlags(hiddenapi_flags_));
+ }
}
template <typename DataType, typename Visitor>
@@ -78,12 +98,12 @@ inline void ClassAccessor::VisitFieldsAndMethods(
const InstanceFieldVisitor& instance_field_visitor,
const DirectMethodVisitor& direct_method_visitor,
const VirtualMethodVisitor& virtual_method_visitor) const {
- Field field(dex_file_, ptr_pos_);
+ Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_);
VisitMembers(num_static_fields_, static_field_visitor, &field);
field.NextSection();
VisitMembers(num_instance_fields_, instance_field_visitor, &field);
- Method method(dex_file_, field.ptr_pos_, /*is_static_or_direct*/ true);
+ Method method(dex_file_, field.ptr_pos_, field.hiddenapi_ptr_pos_, /*is_static_or_direct*/ true);
VisitMembers(num_direct_methods_, direct_method_visitor, &method);
method.NextSection();
VisitMembers(num_virtual_methods_, virtual_method_visitor, &method);
@@ -131,19 +151,43 @@ inline const DexFile::CodeItem* ClassAccessor::Method::GetCodeItem() const {
inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>>
ClassAccessor::GetFieldsInternal(size_t count) const {
- return { DataIterator<Field>(dex_file_, 0u, num_static_fields_, count, ptr_pos_),
- DataIterator<Field>(dex_file_, count, num_static_fields_, count, ptr_pos_) };
+ return {
+ DataIterator<Field>(dex_file_,
+ 0u,
+ num_static_fields_,
+ count,
+ ptr_pos_,
+ hiddenapi_ptr_pos_),
+ DataIterator<Field>(dex_file_,
+ count,
+ num_static_fields_,
+ count,
+ // The following pointers are bogus but unused in the `end` iterator.
+ ptr_pos_,
+ hiddenapi_ptr_pos_) };
}
// Return an iteration range for the first <count> methods.
inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
ClassAccessor::GetMethodsInternal(size_t count) const {
// Skip over the fields.
- Field field(dex_file_, ptr_pos_);
+ Field field(dex_file_, ptr_pos_, hiddenapi_ptr_pos_);
VisitMembers(NumFields(), VoidFunctor(), &field);
// Return the iterator pair.
- return { DataIterator<Method>(dex_file_, 0u, num_direct_methods_, count, field.ptr_pos_),
- DataIterator<Method>(dex_file_, count, num_direct_methods_, count, field.ptr_pos_) };
+ return {
+ DataIterator<Method>(dex_file_,
+ 0u,
+ num_direct_methods_,
+ count,
+ field.ptr_pos_,
+ field.hiddenapi_ptr_pos_),
+ DataIterator<Method>(dex_file_,
+ count,
+ num_direct_methods_,
+ count,
+ // The following pointers are bogus but unused in the `end` iterator.
+ field.ptr_pos_,
+ field.hiddenapi_ptr_pos_) };
}
inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Field>> ClassAccessor::GetFields()
@@ -181,14 +225,6 @@ inline IterationRange<ClassAccessor::DataIterator<ClassAccessor::Method>>
return { std::next(methods.begin(), NumDirectMethods()), methods.end() };
}
-inline void ClassAccessor::Field::UnHideAccessFlags() const {
- DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ false);
-}
-
-inline void ClassAccessor::Method::UnHideAccessFlags() const {
- DexFile::UnHideAccessFlags(const_cast<uint8_t*>(ptr_pos_), GetAccessFlags(), /*is_method*/ true);
-}
-
inline dex::TypeIndex ClassAccessor::GetClassIdx() const {
return dex_file_.GetClassDef(class_def_index_).class_idx_;
}
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index d40577f31f..e9c1a82c54 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -20,7 +20,6 @@
#include "base/utils.h"
#include "code_item_accessors.h"
#include "dex_file.h"
-#include "hidden_api_access_flags.h"
#include "invoke_type.h"
#include "method_reference.h"
#include "modifiers.h"
@@ -35,22 +34,20 @@ class ClassAccessor {
class BaseItem {
public:
explicit BaseItem(const DexFile& dex_file,
- const uint8_t* ptr_pos) : dex_file_(dex_file), ptr_pos_(ptr_pos) {}
+ const uint8_t* ptr_pos,
+ const uint8_t* hiddenapi_ptr_pos)
+ : dex_file_(dex_file), ptr_pos_(ptr_pos), hiddenapi_ptr_pos_(hiddenapi_ptr_pos) {}
uint32_t GetIndex() const {
return index_;
}
- uint32_t GetRawAccessFlags() const {
- return access_flags_;
- }
-
uint32_t GetAccessFlags() const {
- return HiddenApiAccessFlags::RemoveFromDex(access_flags_);
+ return access_flags_;
}
- HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const {
- return HiddenApiAccessFlags::DecodeFromDex(access_flags_);
+ uint32_t GetHiddenapiFlags() const {
+ return hiddenapi_flags_;
}
bool IsFinal() const {
@@ -66,19 +63,21 @@ class ClassAccessor {
}
bool MemberIsNative() const {
- return GetRawAccessFlags() & kAccNative;
+ return GetAccessFlags() & kAccNative;
}
bool MemberIsFinal() const {
- return GetRawAccessFlags() & kAccFinal;
+ return GetAccessFlags() & kAccFinal;
}
protected:
// Internal data pointer for reading.
const DexFile& dex_file_;
const uint8_t* ptr_pos_ = nullptr;
+ const uint8_t* hiddenapi_ptr_pos_ = nullptr;
uint32_t index_ = 0u;
uint32_t access_flags_ = 0u;
+ uint32_t hiddenapi_flags_ = 0u;
};
// A decoded version of the method of a class_data_item.
@@ -107,14 +106,13 @@ class ClassAccessor {
return is_static_or_direct_;
}
- // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
- void UnHideAccessFlags() const;
-
private:
- explicit Method(const DexFile& dex_file,
- const uint8_t* ptr_pos,
- bool is_static_or_direct = true)
- : BaseItem(dex_file, ptr_pos), is_static_or_direct_(is_static_or_direct) {}
+ Method(const DexFile& dex_file,
+ const uint8_t* ptr_pos,
+ const uint8_t* hiddenapi_ptr_pos = nullptr,
+ bool is_static_or_direct = true)
+ : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos),
+ is_static_or_direct_(is_static_or_direct) {}
void Read();
@@ -150,16 +148,15 @@ class ClassAccessor {
// A decoded version of the field of a class_data_item.
class Field : public BaseItem {
public:
- explicit Field(const DexFile& dex_file,
- const uint8_t* ptr_pos) : BaseItem(dex_file, ptr_pos) {}
+ Field(const DexFile& dex_file,
+ const uint8_t* ptr_pos,
+ const uint8_t* hiddenapi_ptr_pos = nullptr)
+ : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos) {}
bool IsStatic() const {
return is_static_;
}
- // Unhide the hidden API access flags at the iterator position. TODO: Deprecate.
- void UnHideAccessFlags() const;
-
private:
void Read();
@@ -185,8 +182,9 @@ class ClassAccessor {
uint32_t position,
uint32_t partition_pos,
uint32_t iterator_end,
- const uint8_t* ptr_pos)
- : data_(dex_file, ptr_pos),
+ const uint8_t* ptr_pos,
+ const uint8_t* hiddenapi_ptr_pos)
+ : data_(dex_file, ptr_pos, hiddenapi_ptr_pos),
position_(position),
partition_pos_(partition_pos),
iterator_end_(iterator_end) {
@@ -268,13 +266,16 @@ class ClassAccessor {
// Not explicit specifically for range-based loops.
ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data);
- ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def);
+ ALWAYS_INLINE ClassAccessor(const DexFile& dex_file,
+ const DexFile::ClassDef& class_def,
+ bool parse_hiddenapi_class_data = false);
ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, uint32_t class_def_index);
ClassAccessor(const DexFile& dex_file,
const uint8_t* class_data,
- uint32_t class_def_index = DexFile::kDexNoIndex32);
+ uint32_t class_def_index = DexFile::kDexNoIndex32,
+ bool parse_hiddenapi_class_data = false);
// Return the code item for a method.
const DexFile::CodeItem* GetCodeItem(const Method& method) const;
@@ -353,6 +354,10 @@ class ClassAccessor {
return ptr_pos_ != nullptr;
}
+ bool HasHiddenapiClassData() const {
+ return hiddenapi_ptr_pos_ != nullptr;
+ }
+
uint32_t GetClassDefIndex() const {
return class_def_index_;
}
@@ -377,6 +382,7 @@ class ClassAccessor {
const DexFile& dex_file_;
const uint32_t class_def_index_;
const uint8_t* ptr_pos_ = nullptr; // Pointer into stream of class_data_item.
+ const uint8_t* hiddenapi_ptr_pos_ = nullptr; // Pointer into stream of hiddenapi_metadata.
const uint32_t num_static_fields_ = 0u;
const uint32_t num_instance_fields_ = 0u;
const uint32_t num_direct_methods_ = 0u;
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 48f38ca8a1..7ccb9c0bad 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -46,31 +46,6 @@ static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex
static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
-void DexFile::UnHideAccessFlags(uint8_t* data_ptr,
- uint32_t new_access_flags,
- bool is_method) {
- // Go back 1 uleb to start.
- data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
- if (is_method) {
- // Methods have another uleb field before the access flags
- data_ptr = ReverseSearchUnsignedLeb128(data_ptr);
- }
- DCHECK_EQ(HiddenApiAccessFlags::RemoveFromDex(DecodeUnsignedLeb128WithoutMovingCursor(data_ptr)),
- new_access_flags);
- UpdateUnsignedLeb128(data_ptr, new_access_flags);
-}
-
-void DexFile::UnhideApis() const {
- for (ClassAccessor accessor : GetClasses()) {
- for (const ClassAccessor::Field& field : accessor.GetFields()) {
- field.UnHideAccessFlags();
- }
- for (const ClassAccessor::Method& method : accessor.GetMethods()) {
- method.UnHideAccessFlags();
- }
- }
-}
-
uint32_t DexFile::CalculateChecksum() const {
return CalculateChecksum(Begin(), Size());
}
@@ -130,6 +105,7 @@ DexFile::DexFile(const uint8_t* base,
num_method_handles_(0),
call_site_ids_(nullptr),
num_call_site_ids_(0),
+ hiddenapi_class_data_(nullptr),
oat_dex_file_(oat_dex_file),
container_(std::move(container)),
is_compact_dex_(is_compact_dex),
@@ -205,6 +181,11 @@ void DexFile::InitializeSectionsFromMapList() {
} else if (map_item.type_ == kDexTypeCallSiteIdItem) {
call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(Begin() + map_item.offset_);
num_call_site_ids_ = map_item.size_;
+ } else if (map_item.type_ == kDexTypeHiddenapiClassData) {
+ hiddenapi_class_data_ = GetHiddenapiClassDataAtOffset(map_item.offset_);
+ } else {
+ // Pointers to other sections are not necessary to retain in the DexFile struct.
+ // Other items have pointers directly into their data.
}
}
}
diff --git a/libdexfile/dex/dex_file.h b/libdexfile/dex/dex_file.h
index 30d8b6d9bf..6a52f67646 100644
--- a/libdexfile/dex/dex_file.h
+++ b/libdexfile/dex/dex_file.h
@@ -92,7 +92,7 @@ class DexFile {
uint32_t endian_tag_ = 0;
uint32_t link_size_ = 0; // unused
uint32_t link_off_ = 0; // unused
- uint32_t map_off_ = 0; // unused
+ uint32_t map_off_ = 0; // map list offset from data_off_
uint32_t string_ids_size_ = 0; // number of StringIds
uint32_t string_ids_off_ = 0; // file offset of StringIds array
uint32_t type_ids_size_ = 0; // number of TypeIds, we don't support more than 65535
@@ -134,6 +134,7 @@ class DexFile {
kDexTypeAnnotationItem = 0x2004,
kDexTypeEncodedArrayItem = 0x2005,
kDexTypeAnnotationsDirectoryItem = 0x2006,
+ kDexTypeHiddenapiClassData = 0xF000,
};
struct MapItem {
@@ -147,6 +148,8 @@ class DexFile {
uint32_t size_;
MapItem list_[1];
+ size_t Size() const { return sizeof(uint32_t) + (size_ * sizeof(MapItem)); }
+
private:
DISALLOW_COPY_AND_ASSIGN(MapList);
};
@@ -419,6 +422,27 @@ class DexFile {
DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
};
+ struct HiddenapiClassData {
+ uint32_t size_; // total size of the item
+ uint32_t flags_offset_[1]; // array of offsets from the beginning of this item,
+ // indexed by class def index
+
+ // Returns a pointer to the beginning of a uleb128-stream of hiddenapi
+ // flags for a class def of given index. Values are in the same order
+ // as fields/methods in the class data. Returns null if the class does
+ // not have class data.
+ const uint8_t* GetFlagsPointer(uint32_t class_def_idx) const {
+ if (flags_offset_[class_def_idx] == 0) {
+ return nullptr;
+ } else {
+ return reinterpret_cast<const uint8_t*>(this) + flags_offset_[class_def_idx];
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HiddenapiClassData);
+ };
+
enum AnnotationResultStyle { // private
kAllObjects,
kPrimitivesOrObjects,
@@ -837,6 +861,14 @@ class DexFile {
return DataPointer<AnnotationItem>(offset);
}
+ ALWAYS_INLINE const HiddenapiClassData* GetHiddenapiClassDataAtOffset(uint32_t offset) const {
+ return DataPointer<HiddenapiClassData>(offset);
+ }
+
+ ALWAYS_INLINE const HiddenapiClassData* GetHiddenapiClassData() const {
+ return hiddenapi_class_data_;
+ }
+
const AnnotationItem* GetAnnotationItem(const AnnotationSetItem* set_item, uint32_t index) const {
DCHECK_LE(index, set_item->size_);
return GetAnnotationItemAtOffset(set_item->entries_[index]);
@@ -992,12 +1024,6 @@ class DexFile {
return container_.get();
}
- // Changes the dex class data pointed to by data_ptr it to not have any hiddenapi flags.
- static void UnHideAccessFlags(uint8_t* data_ptr, uint32_t new_access_flags, bool is_method);
-
- // Iterate dex classes and remove hiddenapi flags in fields and methods.
- void UnhideApis() const;
-
IterationRange<ClassIterator> GetClasses() const;
template <typename Visitor>
@@ -1080,6 +1106,10 @@ class DexFile {
// Number of elements in the call sites list.
size_t num_call_site_ids_;
+ // Points to the base of the hiddenapi class data item_, or nullptr if the dex
+ // file does not have one.
+ const HiddenapiClassData* hiddenapi_class_data_;
+
// If this dex file was loaded from an oat file, oat_dex_file_ contains a
// pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is
// null.
diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc
index 499a89b2ab..43471c3116 100644
--- a/libdexfile/dex/dex_file_verifier.cc
+++ b/libdexfile/dex/dex_file_verifier.cc
@@ -67,6 +67,7 @@ static uint32_t MapTypeToBitMask(DexFile::MapItemType map_item_type) {
case DexFile::kDexTypeAnnotationItem: return 1 << 17;
case DexFile::kDexTypeEncodedArrayItem: return 1 << 18;
case DexFile::kDexTypeAnnotationsDirectoryItem: return 1 << 19;
+ case DexFile::kDexTypeHiddenapiClassData: return 1 << 20;
}
return 0;
}
@@ -94,6 +95,7 @@ static bool IsDataSectionType(DexFile::MapItemType map_item_type) {
case DexFile::kDexTypeAnnotationItem:
case DexFile::kDexTypeEncodedArrayItem:
case DexFile::kDexTypeAnnotationsDirectoryItem:
+ case DexFile::kDexTypeHiddenapiClassData:
return true;
}
return true;
@@ -1096,7 +1098,7 @@ bool DexFileVerifier::CheckIntraClassDataItemFields(size_t count,
return false;
}
if (!CheckClassDataItemField(curr_index,
- field->GetRawAccessFlags(),
+ field->GetAccessFlags(),
(*class_def)->access_flags_,
*class_type_index,
kStatic)) {
@@ -1147,7 +1149,7 @@ bool DexFileVerifier::CheckIntraClassDataItemMethods(ClassAccessor::Method* meth
return false;
}
if (!CheckClassDataItemMethod(curr_index,
- method->GetRawAccessFlags(),
+ method->GetAccessFlags(),
(*class_def)->access_flags_,
*class_type_index,
method->GetCodeItemOffset(),
@@ -1555,6 +1557,107 @@ bool DexFileVerifier::CheckIntraAnnotationItem() {
return true;
}
+bool DexFileVerifier::CheckIntraHiddenapiClassData() {
+ const DexFile::HiddenapiClassData* item =
+ reinterpret_cast<const DexFile::HiddenapiClassData*>(ptr_);
+
+ // Check expected header size.
+ uint32_t num_header_elems = dex_file_->NumClassDefs() + 1;
+ uint32_t elem_size = sizeof(uint32_t);
+ uint32_t header_size = num_header_elems * elem_size;
+ if (!CheckListSize(item, num_header_elems, elem_size, "hiddenapi class data section header")) {
+ return false;
+ }
+
+ // Check total size.
+ if (!CheckListSize(item, item->size_, 1u, "hiddenapi class data section")) {
+ return false;
+ }
+
+ // Check that total size can fit header.
+ if (item->size_ < header_size) {
+ ErrorStringPrintf(
+ "Hiddenapi class data too short to store header (%u < %u)", item->size_, header_size);
+ return false;
+ }
+
+ const uint8_t* data_end = ptr_ + item->size_;
+ ptr_ += header_size;
+
+ // Check offsets for each class def.
+ for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file_->GetClassDef(i);
+ const uint8_t* class_data = dex_file_->GetClassData(class_def);
+ uint32_t offset = item->flags_offset_[i];
+
+ if (offset == 0) {
+ continue;
+ }
+
+ // Check that class defs with no class data do not have any hiddenapi class data.
+ if (class_data == nullptr) {
+ ErrorStringPrintf(
+ "Hiddenapi class data offset not zero for class def %u with no class data", i);
+ return false;
+ }
+
+ // Check that the offset is within the section.
+ if (offset > item->size_) {
+ ErrorStringPrintf(
+ "Hiddenapi class data offset out of section bounds (%u > %u) for class def %u",
+ offset, item->size_, i);
+ return false;
+ }
+
+ // Check that the offset matches current pointer position. We do not allow
+ // offsets into already parsed data, or gaps between class def data.
+ uint32_t ptr_offset = ptr_ - reinterpret_cast<const uint8_t*>(item);
+ if (offset != ptr_offset) {
+ ErrorStringPrintf(
+ "Hiddenapi class data unexpected offset (%u != %u) for class def %u",
+ offset, ptr_offset, i);
+ return false;
+ }
+
+ // Parse a uleb128 value for each field and method of this class.
+ bool failure = false;
+ auto fn_member = [&](const ClassAccessor::BaseItem& member, const char* member_type) {
+ if (failure) {
+ return;
+ }
+ uint32_t decoded_flags;
+ if (!DecodeUnsignedLeb128Checked(&ptr_, data_end, &decoded_flags)) {
+ ErrorStringPrintf("Hiddenapi class data value out of bounds (%p > %p) for %s %i",
+ ptr_, data_end, member_type, member.GetIndex());
+ failure = true;
+ return;
+ }
+ if (!HiddenApiAccessFlags::AreValidFlags(decoded_flags)) {
+ ErrorStringPrintf("Hiddenapi class data flags invalid (%u) for %s %i",
+ decoded_flags, member_type, member.GetIndex());
+ failure = true;
+ return;
+ }
+ };
+ auto fn_field = [&](const ClassAccessor::Field& field) { fn_member(field, "field"); };
+ auto fn_method = [&](const ClassAccessor::Method& method) { fn_member(method, "method"); };
+ ClassAccessor accessor(*dex_file_, class_data);
+ accessor.VisitFieldsAndMethods(fn_field, fn_field, fn_method, fn_method);
+ if (failure) {
+ return false;
+ }
+ }
+
+ if (ptr_ != data_end) {
+ ErrorStringPrintf("Hiddenapi class data wrong reported size (%u != %u)",
+ static_cast<uint32_t>(ptr_ - reinterpret_cast<const uint8_t*>(item)),
+ item->size_);
+ return false;
+ }
+
+ return true;
+}
+
bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() {
const DexFile::AnnotationsDirectoryItem* item =
reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
@@ -1769,6 +1872,12 @@ bool DexFileVerifier::CheckIntraSectionIterate(size_t offset, uint32_t section_c
}
break;
}
+ case DexFile::kDexTypeHiddenapiClassData: {
+ if (!CheckIntraHiddenapiClassData()) {
+ return false;
+ }
+ break;
+ }
case DexFile::kDexTypeHeaderItem:
case DexFile::kDexTypeMapList:
break;
@@ -1973,6 +2082,7 @@ bool DexFileVerifier::CheckIntraSection() {
CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationItem)
CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeEncodedArrayItem)
CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeAnnotationsDirectoryItem)
+ CHECK_INTRA_DATA_SECTION_CASE(DexFile::kDexTypeHiddenapiClassData)
#undef CHECK_INTRA_DATA_SECTION_CASE
}
@@ -2736,6 +2846,7 @@ bool DexFileVerifier::CheckInterSectionIterate(size_t offset,
case DexFile::kDexTypeDebugInfoItem:
case DexFile::kDexTypeAnnotationItem:
case DexFile::kDexTypeEncodedArrayItem:
+ case DexFile::kDexTypeHiddenapiClassData:
break;
case DexFile::kDexTypeStringIdItem: {
if (!CheckInterStringIdItem()) {
@@ -2868,7 +2979,8 @@ bool DexFileVerifier::CheckInterSection() {
case DexFile::kDexTypeAnnotationSetRefList:
case DexFile::kDexTypeAnnotationSetItem:
case DexFile::kDexTypeClassDataItem:
- case DexFile::kDexTypeAnnotationsDirectoryItem: {
+ case DexFile::kDexTypeAnnotationsDirectoryItem:
+ case DexFile::kDexTypeHiddenapiClassData: {
if (!CheckInterSectionIterate(section_offset, section_count, type)) {
return false;
}
diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h
index 79ddea43d4..a81df48398 100644
--- a/libdexfile/dex/dex_file_verifier.h
+++ b/libdexfile/dex/dex_file_verifier.h
@@ -126,6 +126,7 @@ class DexFileVerifier {
bool CheckIntraDebugInfoItem();
bool CheckIntraAnnotationItem();
bool CheckIntraAnnotationsDirectoryItem();
+ bool CheckIntraHiddenapiClassData();
template <DexFile::MapItemType kType>
bool CheckIntraSectionIterate(size_t offset, uint32_t count);
diff --git a/libdexfile/dex/hidden_api_access_flags.h b/libdexfile/dex/hidden_api_access_flags.h
index 369615d678..837056be80 100644
--- a/libdexfile/dex/hidden_api_access_flags.h
+++ b/libdexfile/dex/hidden_api_access_flags.h
@@ -28,31 +28,14 @@ namespace art {
* of information on whether the given class member should be hidden from apps
* and under what circumstances.
*
- * The encoding is different inside DexFile, where we are concerned with size,
- * and at runtime where we want to optimize for speed of access. The class
- * provides helper functions to decode/encode both of them.
+ * Two bits are encoded for each class member in the HiddenapiClassData item,
+ * stored in a stream of uleb128-encoded values for each ClassDef item.
+ * The two bits correspond to values in the ApiList enum below.
*
- * Encoding in DexFile
- * ===================
- *
- * First bit is encoded as inversion of visibility flags (public/private/protected).
- * At most one can be set for any given class member. If two or three are set,
- * this is interpreted as the first bit being set and actual visibility flags
- * being the complement of the encoded flags.
- *
- * Second bit is either encoded as bit 5 for fields and non-native methods, where
- * it carries no other meaning. If a method is native (bit 8 set), bit 9 is used.
- *
- * Bits were selected so that they never increase the length of unsigned LEB-128
- * encoding of the access flags.
- *
- * Encoding at runtime
- * ===================
- *
- * Two bits are set aside in the uint32_t access flags in the intrinsics ordinal
- * space (thus intrinsics need to be special-cased). These are two consecutive
- * bits and they are directly used to store the integer value of the ApiList
- * enum values.
+ * At runtime, two bits are set aside in the uint32_t access flags in the
+ * intrinsics ordinal space (thus intrinsics need to be special-cased). These are
+ * two consecutive bits and they are directly used to store the integer value of
+ * the ApiList enum values.
*
*/
class HiddenApiAccessFlags {
@@ -65,27 +48,6 @@ class HiddenApiAccessFlags {
kNoList,
};
- static ALWAYS_INLINE ApiList DecodeFromDex(uint32_t dex_access_flags) {
- DexHiddenAccessFlags flags(dex_access_flags);
- uint32_t int_value = (flags.IsFirstBitSet() ? 1 : 0) + (flags.IsSecondBitSet() ? 2 : 0);
- return static_cast<ApiList>(int_value);
- }
-
- static ALWAYS_INLINE uint32_t RemoveFromDex(uint32_t dex_access_flags) {
- DexHiddenAccessFlags flags(dex_access_flags);
- flags.SetFirstBit(false);
- flags.SetSecondBit(false);
- return flags.GetEncoding();
- }
-
- static ALWAYS_INLINE uint32_t EncodeForDex(uint32_t dex_access_flags, ApiList value) {
- DexHiddenAccessFlags flags(RemoveFromDex(dex_access_flags));
- uint32_t int_value = static_cast<uint32_t>(value);
- flags.SetFirstBit((int_value & 1) != 0);
- flags.SetSecondBit((int_value & 2) != 0);
- return flags.GetEncoding();
- }
-
static ALWAYS_INLINE ApiList DecodeFromRuntime(uint32_t runtime_access_flags) {
// This is used in the fast path, only DCHECK here.
DCHECK_EQ(runtime_access_flags & kAccIntrinsic, 0u);
@@ -103,47 +65,14 @@ class HiddenApiAccessFlags {
return runtime_access_flags | hidden_api_flags;
}
+ static ALWAYS_INLINE bool AreValidFlags(uint32_t flags) {
+ return flags <= static_cast<uint32_t>(kBlacklist);
+ }
+
private:
static const int kAccFlagsShift = CTZ(kAccHiddenApiBits);
static_assert(IsPowerOfTwo((kAccHiddenApiBits >> kAccFlagsShift) + 1),
"kAccHiddenApiBits are not continuous");
-
- struct DexHiddenAccessFlags {
- explicit DexHiddenAccessFlags(uint32_t access_flags) : access_flags_(access_flags) {}
-
- ALWAYS_INLINE uint32_t GetSecondFlag() {
- return ((access_flags_ & kAccNative) != 0) ? kAccDexHiddenBitNative : kAccDexHiddenBit;
- }
-
- ALWAYS_INLINE bool IsFirstBitSet() {
- static_assert(IsPowerOfTwo(0u), "Following statement checks if *at most* one bit is set");
- return !IsPowerOfTwo(access_flags_ & kAccVisibilityFlags);
- }
-
- ALWAYS_INLINE void SetFirstBit(bool value) {
- if (IsFirstBitSet() != value) {
- access_flags_ ^= kAccVisibilityFlags;
- }
- }
-
- ALWAYS_INLINE bool IsSecondBitSet() {
- return (access_flags_ & GetSecondFlag()) != 0;
- }
-
- ALWAYS_INLINE void SetSecondBit(bool value) {
- if (value) {
- access_flags_ |= GetSecondFlag();
- } else {
- access_flags_ &= ~GetSecondFlag();
- }
- }
-
- ALWAYS_INLINE uint32_t GetEncoding() const {
- return access_flags_;
- }
-
- uint32_t access_flags_;
- };
};
inline std::ostream& operator<<(std::ostream& os, HiddenApiAccessFlags::ApiList value) {
diff --git a/libdexfile/dex/modifiers.h b/libdexfile/dex/modifiers.h
index 38f8455b64..018b1419b1 100644
--- a/libdexfile/dex/modifiers.h
+++ b/libdexfile/dex/modifiers.h
@@ -42,11 +42,6 @@ static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
static constexpr uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16)
-// The following flags are used to insert hidden API access flags into boot class path dex files.
-// They are decoded by ClassAccessor and removed from the access flags before used by the runtime.
-static constexpr uint32_t kAccDexHiddenBit = 0x00000020; // field, method (not native)
-static constexpr uint32_t kAccDexHiddenBitNative = 0x00000200; // method (native)
-
static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init>
static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)