Move hiddenapi to ClassAccessor
Test: test-art-host
Bug: 79758018
Change-Id: Ib0848cc69ffaa7735f43d88e9719cc43953e4a93
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index 8ffeee4..d40577f 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -31,7 +31,7 @@
// Classes to access Dex data.
class ClassAccessor {
- private:
+ public:
class BaseItem {
public:
explicit BaseItem(const DexFile& dex_file,
@@ -65,6 +65,14 @@
return ptr_pos_;
}
+ bool MemberIsNative() const {
+ return GetRawAccessFlags() & kAccNative;
+ }
+
+ bool MemberIsFinal() const {
+ return GetRawAccessFlags() & kAccFinal;
+ }
+
protected:
// Internal data pointer for reading.
const DexFile& dex_file_;
@@ -73,7 +81,6 @@
uint32_t access_flags_ = 0u;
};
- public:
// A decoded version of the method of a class_data_item.
class Method : public BaseItem {
public:
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index e4bec06..bf8a1b7 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -26,6 +26,7 @@
#include "base/os.h"
#include "base/unix_file/fd_file.h"
#include "dex/art_dex_file_loader.h"
+#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "dex/hidden_api_access_flags.h"
@@ -91,32 +92,23 @@
return std::find(vec.begin(), vec.end(), elem) != vec.end();
}
-class DexClass {
+class DexClass : public ClassAccessor {
public:
- DexClass(const DexFile& dex_file, uint32_t idx)
- : dex_file_(dex_file), class_def_(dex_file.GetClassDef(idx)) {}
+ explicit DexClass(const ClassAccessor& accessor) : ClassAccessor(accessor) {}
- const DexFile& GetDexFile() const { return dex_file_; }
- const uint8_t* GetData() const { return dex_file_.GetClassData(class_def_); }
+ const uint8_t* GetData() const { return dex_file_.GetClassData(GetClassDef()); }
- const dex::TypeIndex GetClassIndex() const { return class_def_.class_idx_; }
- const dex::TypeIndex GetSuperclassIndex() const { return class_def_.superclass_idx_; }
+ const dex::TypeIndex GetSuperclassIndex() const { return GetClassDef().superclass_idx_; }
bool HasSuperclass() const { return dex_file_.IsTypeIndexValid(GetSuperclassIndex()); }
- std::string GetDescriptor() const { return dex_file_.GetClassDescriptor(class_def_); }
-
std::string GetSuperclassDescriptor() const {
- if (HasSuperclass()) {
- return dex_file_.StringByTypeIdx(GetSuperclassIndex());
- } else {
- return "";
- }
+ return HasSuperclass() ? dex_file_.StringByTypeIdx(GetSuperclassIndex()) : "";
}
std::set<std::string> GetInterfaceDescriptors() const {
std::set<std::string> list;
- const DexFile::TypeList* ifaces = dex_file_.GetInterfacesList(class_def_);
+ const DexFile::TypeList* ifaces = dex_file_.GetInterfacesList(GetClassDef());
for (uint32_t i = 0; ifaces != nullptr && i < ifaces->Size(); ++i) {
list.insert(dex_file_.StringByTypeIdx(ifaces->GetTypeItem(i).type_idx_));
}
@@ -126,7 +118,7 @@
inline bool IsPublic() const { return HasAccessFlags(kAccPublic); }
inline bool Equals(const DexClass& other) const {
- bool equals = GetDescriptor() == other.GetDescriptor();
+ bool equals = strcmp(GetDescriptor(), other.GetDescriptor()) == 0;
if (equals) {
// TODO(dbrazdil): Check that methods/fields match as well once b/111116543 is fixed.
CHECK_EQ(GetAccessFlags(), other.GetAccessFlags());
@@ -137,39 +129,40 @@
}
private:
- uint32_t GetAccessFlags() const { return class_def_.access_flags_; }
+ uint32_t GetAccessFlags() const { return GetClassDef().access_flags_; }
bool HasAccessFlags(uint32_t mask) const { return (GetAccessFlags() & mask) == mask; }
-
- const DexFile& dex_file_;
- const DexFile::ClassDef& class_def_;
};
class DexMember {
public:
- DexMember(const DexClass& klass, const ClassDataItemIterator& it)
- : klass_(klass), it_(it) {
- DCHECK_EQ(IsMethod() ? GetMethodId().class_idx_ : GetFieldId().class_idx_,
- klass_.GetClassIndex());
+ DexMember(const DexClass& klass, const ClassAccessor::Field& item)
+ : klass_(klass), item_(item), is_method_(false) {
+ DCHECK_EQ(GetFieldId().class_idx_, klass.GetClassIdx());
+ }
+
+ DexMember(const DexClass& klass, const ClassAccessor::Method& item)
+ : klass_(klass), item_(item), is_method_(true) {
+ DCHECK_EQ(GetMethodId().class_idx_, klass.GetClassIdx());
}
inline const DexClass& GetDeclaringClass() const { return klass_; }
// Sets hidden bits in access flags and writes them back into the DEX in memory.
- // Note that this will not update the cached data of ClassDataItemIterator
+ // Note that this will not update the cached data of the class accessor
// until it iterates over this item again and therefore will fail a CHECK if
// it is called multiple times on the same DexMember.
- void SetHidden(HiddenApiAccessFlags::ApiList value) {
- const uint32_t old_flags = it_.GetRawMemberAccessFlags();
+ void SetHidden(HiddenApiAccessFlags::ApiList value) const {
+ const uint32_t old_flags = item_.GetRawAccessFlags();
const uint32_t new_flags = HiddenApiAccessFlags::EncodeForDex(old_flags, value);
CHECK_EQ(UnsignedLeb128Size(new_flags), UnsignedLeb128Size(old_flags));
// Locate the LEB128-encoded access flags in class data.
// `ptr` initially points to the next ClassData item. We iterate backwards
// until we hit the terminating byte of the previous Leb128 value.
- const uint8_t* ptr = it_.DataPointer();
+ const uint8_t* ptr = item_.GetDataPointer();
if (IsMethod()) {
ptr = ReverseSearchUnsignedLeb128(ptr);
- DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), it_.GetMethodCodeItemOffset());
+ DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), GetMethod().GetCodeItemOffset());
}
ptr = ReverseSearchUnsignedLeb128(ptr);
DCHECK_EQ(DecodeUnsignedLeb128WithoutMovingCursor(ptr), old_flags);
@@ -178,8 +171,8 @@
UpdateUnsignedLeb128(const_cast<uint8_t*>(ptr), new_flags);
}
- inline bool IsMethod() const { return it_.IsAtMethod(); }
- inline bool IsVirtualMethod() const { return it_.IsAtVirtualMethod(); }
+ inline bool IsMethod() const { return is_method_; }
+ inline bool IsVirtualMethod() const { return IsMethod() && !GetMethod().IsStaticOrDirect(); }
inline bool IsConstructor() const { return IsMethod() && HasAccessFlags(kAccConstructor); }
inline bool IsPublicOrProtected() const {
@@ -189,11 +182,12 @@
// Constructs a string with a unique signature of this class member.
std::string GetApiEntry() const {
std::stringstream ss;
- ss << klass_.GetDescriptor() << "->" << GetName() << (IsMethod() ? "" : ":") << GetSignature();
+ ss << klass_.GetDescriptor() << "->" << GetName() << (IsMethod() ? "" : ":")
+ << GetSignature();
return ss.str();
}
- inline bool operator==(const DexMember& other) {
+ inline bool operator==(const DexMember& other) const {
// These need to match if they should resolve to one another.
bool equals = IsMethod() == other.IsMethod() &&
GetName() == other.GetName() &&
@@ -208,31 +202,37 @@
}
private:
- inline uint32_t GetAccessFlags() const { return it_.GetMemberAccessFlags(); }
+ inline uint32_t GetAccessFlags() const { return item_.GetAccessFlags(); }
inline uint32_t HasAccessFlags(uint32_t mask) const { return (GetAccessFlags() & mask) == mask; }
inline std::string GetName() const {
- return IsMethod() ? klass_.GetDexFile().GetMethodName(GetMethodId())
- : klass_.GetDexFile().GetFieldName(GetFieldId());
+ return IsMethod() ? item_.GetDexFile().GetMethodName(GetMethodId())
+ : item_.GetDexFile().GetFieldName(GetFieldId());
}
inline std::string GetSignature() const {
- return IsMethod() ? klass_.GetDexFile().GetMethodSignature(GetMethodId()).ToString()
- : klass_.GetDexFile().GetFieldTypeDescriptor(GetFieldId());
+ return IsMethod() ? item_.GetDexFile().GetMethodSignature(GetMethodId()).ToString()
+ : item_.GetDexFile().GetFieldTypeDescriptor(GetFieldId());
+ }
+
+ inline const ClassAccessor::Method& GetMethod() const {
+ DCHECK(IsMethod());
+ return down_cast<const ClassAccessor::Method&>(item_);
}
inline const DexFile::MethodId& GetMethodId() const {
DCHECK(IsMethod());
- return klass_.GetDexFile().GetMethodId(it_.GetMemberIndex());
+ return item_.GetDexFile().GetMethodId(item_.GetIndex());
}
inline const DexFile::FieldId& GetFieldId() const {
DCHECK(!IsMethod());
- return klass_.GetDexFile().GetFieldId(it_.GetMemberIndex());
+ return item_.GetDexFile().GetFieldId(item_.GetIndex());
}
const DexClass& klass_;
- const ClassDataItemIterator& it_;
+ const ClassAccessor::BaseItem& item_;
+ const bool is_method_;
};
class ClassPath FINAL {
@@ -244,22 +244,20 @@
template<typename Fn>
void ForEachDexClass(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);
- fn(klass);
+ for (ClassAccessor accessor : dex_file->GetClasses()) {
+ fn(DexClass(accessor));
}
}
}
template<typename Fn>
void ForEachDexMember(Fn fn) {
- ForEachDexClass([&fn](DexClass& klass) {
- const uint8_t* klass_data = klass.GetData();
- if (klass_data != nullptr) {
- for (ClassDataItemIterator it(klass.GetDexFile(), klass_data); it.HasNext(); it.Next()) {
- DexMember member(klass, it);
- fn(member);
- }
+ ForEachDexClass([&fn](const DexClass& klass) {
+ for (const ClassAccessor::Field& field : klass.GetFields()) {
+ fn(DexMember(klass, field));
+ }
+ for (const ClassAccessor::Method& method : klass.GetMethods()) {
+ fn(DexMember(klass, method));
}
});
}
@@ -416,16 +414,18 @@
template<typename Fn>
ResolutionResult ForEachMatchingMember(const DexMember& other, Fn fn) {
ResolutionResult found = ResolutionResult::kNotFound;
+ auto compare_member = [&](const DexMember& member) {
+ if (member == other) {
+ found = Accumulate(found, fn(member) ? ResolutionResult::kFoundNew
+ : ResolutionResult::kFoundOld);
+ }
+ };
for (const DexClass& dex_class : dex_classes_) {
- const uint8_t* data = dex_class.GetData();
- if (data != nullptr) {
- for (ClassDataItemIterator it(dex_class.GetDexFile(), data); it.HasNext(); it.Next()) {
- DexMember member(dex_class, it);
- if (member == other) {
- found = Accumulate(found, fn(member) ? ResolutionResult::kFoundNew
- : ResolutionResult::kFoundOld);
- }
- }
+ for (const ClassAccessor::Field& field : dex_class.GetFields()) {
+ compare_member(DexMember(dex_class, field));
+ }
+ for (const ClassAccessor::Method& method : dex_class.GetMethods()) {
+ compare_member(DexMember(dex_class, method));
}
}
return found;
@@ -528,7 +528,7 @@
void BuildClassHierarchy() {
// Create one HierarchyClass entry in `classes_` per class descriptor
// and add all DexClass objects with the same descriptor to that entry.
- classpath_.ForEachDexClass([this](DexClass& klass) {
+ classpath_.ForEachDexClass([this](const DexClass& klass) {
classes_[klass.GetDescriptor()].AddDexClass(klass);
});
@@ -643,13 +643,9 @@
ClassPath boot_classpath(boot_dex_paths_, /* open_writable */ true);
// Set access flags of all members.
- boot_classpath.ForEachDexMember([&api_list](DexMember& boot_member) {
+ boot_classpath.ForEachDexMember([&api_list](const 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_member.SetHidden(it == api_list.end() ? HiddenApiAccessFlags::kWhitelist : it->second);
});
boot_classpath.UpdateDexChecksums();
@@ -696,7 +692,7 @@
Hierarchy boot_hierarchy(boot_classpath);
// Mark all boot dex members private.
- boot_classpath.ForEachDexMember([&boot_members](DexMember& boot_member) {
+ boot_classpath.ForEachDexMember([&boot_members](const DexMember& boot_member) {
boot_members[boot_member.GetApiEntry()] = false;
});
@@ -705,14 +701,15 @@
ClassPath stub_classpath(stub_classpath_dex, /* open_writable */ false);
Hierarchy stub_hierarchy(stub_classpath);
stub_classpath.ForEachDexMember(
- [&stub_hierarchy, &boot_hierarchy, &boot_members, &unresolved](DexMember& stub_member) {
+ [&stub_hierarchy, &boot_hierarchy, &boot_members, &unresolved](
+ const DexMember& stub_member) {
if (!stub_hierarchy.IsMemberVisible(stub_member)) {
// Typically fake constructors and inner-class `this` fields.
return;
}
bool resolved = boot_hierarchy.ForEachResolvableMember(
stub_member,
- [&boot_members](DexMember& boot_member) {
+ [&boot_members](const DexMember& boot_member) {
std::string entry = boot_member.GetApiEntry();
auto it = boot_members.find(entry);
CHECK(it != boot_members.end());
diff --git a/tools/hiddenapi/hiddenapi_test.cc b/tools/hiddenapi/hiddenapi_test.cc
index aa87f21..b50f684 100644
--- a/tools/hiddenapi/hiddenapi_test.cc
+++ b/tools/hiddenapi/hiddenapi_test.cc
@@ -20,6 +20,7 @@
#include "base/zip_archive.h"
#include "common_runtime_test.h"
#include "dex/art_dex_file_loader.h"
+#include "dex/class_accessor-inl.h"
#include "dex/dex_file-inl.h"
#include "exec_utils.h"
@@ -114,40 +115,27 @@
}
const DexFile::ClassDef& FindClass(const char* desc, const DexFile& dex_file) {
- for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
- const DexFile::ClassDef& class_def = dex_file.GetClassDef(i);
- if (strcmp(desc, dex_file.GetClassDescriptor(class_def)) == 0) {
- return class_def;
- }
- }
- LOG(FATAL) << "Could not find class " << desc;
- UNREACHABLE();
+ const DexFile::TypeId* type_id = dex_file.FindTypeId(desc);
+ CHECK(type_id != nullptr) << "Could not find class " << desc;
+ const DexFile::ClassDef* found = dex_file.FindClassDef(dex_file.GetIndexForTypeId(*type_id));
+ CHECK(found != nullptr) << "Could not find class " << desc;
+ return *found;
}
HiddenApiAccessFlags::ApiList GetFieldHiddenFlags(const char* name,
uint32_t expected_visibility,
const DexFile::ClassDef& class_def,
const DexFile& dex_file) {
- const uint8_t* class_data = dex_file.GetClassData(class_def);
- if (class_data == nullptr) {
- LOG(FATAL) << "Class " << dex_file.GetClassDescriptor(class_def) << " has no data";
- UNREACHABLE();
- }
+ ClassAccessor accessor(dex_file, class_def);
+ CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
- for (ClassDataItemIterator it(dex_file, class_data); it.HasNext(); it.Next()) {
- if (it.IsAtMethod()) {
- break;
- }
- const DexFile::FieldId& fid = dex_file.GetFieldId(it.GetMemberIndex());
+ for (const ClassAccessor::Field& field : accessor.GetFields()) {
+ const DexFile::FieldId& fid = dex_file.GetFieldId(field.GetIndex());
if (strcmp(name, dex_file.GetFieldName(fid)) == 0) {
- uint32_t actual_visibility = it.GetFieldAccessFlags() & kAccVisibilityFlags;
- if (actual_visibility != expected_visibility) {
- LOG(FATAL) << "Field " << name << " in class " << dex_file.GetClassDescriptor(class_def)
- << " does not have the expected visibility flags (" << expected_visibility
- << " != " << actual_visibility << ")";
- UNREACHABLE();
- }
- return it.DecodeHiddenAccessFlags();
+ const uint32_t actual_visibility = field.GetAccessFlags() & kAccVisibilityFlags;
+ CHECK_EQ(actual_visibility, expected_visibility)
+ << "Field " << name << " in class " << accessor.GetDescriptor();
+ return field.DecodeHiddenAccessFlags();
}
}
@@ -161,31 +149,18 @@
bool expected_native,
const DexFile::ClassDef& class_def,
const DexFile& dex_file) {
- const uint8_t* class_data = dex_file.GetClassData(class_def);
- if (class_data == nullptr) {
- LOG(FATAL) << "Class " << dex_file.GetClassDescriptor(class_def) << " has no data";
- UNREACHABLE();
- }
+ ClassAccessor accessor(dex_file, class_def);
+ CHECK(accessor.HasClassData()) << "Class " << accessor.GetDescriptor() << " has no data";
- for (ClassDataItemIterator it(dex_file, class_data); it.HasNext(); it.Next()) {
- if (!it.IsAtMethod()) {
- continue;
- }
- const DexFile::MethodId& mid = dex_file.GetMethodId(it.GetMemberIndex());
+ for (const ClassAccessor::Method& method : accessor.GetMethods()) {
+ const DexFile::MethodId& mid = dex_file.GetMethodId(method.GetIndex());
if (strcmp(name, dex_file.GetMethodName(mid)) == 0) {
- if (expected_native != it.MemberIsNative()) {
- LOG(FATAL) << "Expected native=" << expected_native << " for method " << name
- << " in class " << dex_file.GetClassDescriptor(class_def);
- UNREACHABLE();
- }
- uint32_t actual_visibility = it.GetMethodAccessFlags() & kAccVisibilityFlags;
- if (actual_visibility != expected_visibility) {
- LOG(FATAL) << "Method " << name << " in class " << dex_file.GetClassDescriptor(class_def)
- << " does not have the expected visibility flags (" << expected_visibility
- << " != " << actual_visibility << ")";
- UNREACHABLE();
- }
- return it.DecodeHiddenAccessFlags();
+ CHECK_EQ(expected_native, method.MemberIsNative())
+ << "Method " << name << " in class " << accessor.GetDescriptor();
+ const uint32_t actual_visibility = method.GetAccessFlags() & kAccVisibilityFlags;
+ CHECK_EQ(actual_visibility, expected_visibility)
+ << "Method " << name << " in class " << accessor.GetDescriptor();
+ return method.DecodeHiddenAccessFlags();
}
}