summaryrefslogtreecommitdiff
path: root/runtime/hidden_api.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/hidden_api.cc')
-rw-r--r--runtime/hidden_api.cc143
1 files changed, 101 insertions, 42 deletions
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index 6cdba73c30..e0939ddbdb 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -21,7 +21,10 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "base/dumpable.h"
+#include "class_root.h"
#include "dex/class_accessor-inl.h"
+#include "dex/dex_file_loader.h"
+#include "mirror/class_ext.h"
#include "scoped_thread_state_change.h"
#include "thread-inl.h"
#include "well_known_classes.h"
@@ -93,6 +96,24 @@ MemberSignature::MemberSignature(ArtMethod* method) {
type_ = kMethod;
}
+MemberSignature::MemberSignature(const ClassAccessor::Field& field) {
+ const DexFile& dex_file = field.GetDexFile();
+ const DexFile::FieldId& field_id = dex_file.GetFieldId(field.GetIndex());
+ class_name_ = dex_file.GetFieldDeclaringClassDescriptor(field_id);
+ member_name_ = dex_file.GetFieldName(field_id);
+ type_signature_ = dex_file.GetFieldTypeDescriptor(field_id);
+ type_ = kField;
+}
+
+MemberSignature::MemberSignature(const ClassAccessor::Method& method) {
+ const DexFile& dex_file = method.GetDexFile();
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(method.GetIndex());
+ class_name_ = dex_file.GetMethodDeclaringClassDescriptor(method_id);
+ member_name_ = dex_file.GetMethodName(method_id);
+ type_signature_ = dex_file.GetMethodSignature(method_id).ToString();
+ type_ = kMethod;
+}
+
inline std::vector<const char*> MemberSignature::GetSignatureParts() const {
if (type_ == kField) {
return { class_name_.c_str(), "->", member_name_.c_str(), ":", type_signature_.c_str() };
@@ -137,6 +158,17 @@ void MemberSignature::WarnAboutAccess(AccessMethod access_method, hiddenapi::Api
<< Dumpable<MemberSignature>(*this) << " (" << list << ", " << access_method << ")";
}
+bool MemberSignature::Equals(const MemberSignature& other) {
+ return type_ == other.type_ &&
+ class_name_ == other.class_name_ &&
+ member_name_ == other.member_name_ &&
+ type_signature_ == other.type_signature_;
+}
+
+bool MemberSignature::MemberNameAndTypeMatch(const MemberSignature& other) {
+ return member_name_ == other.member_name_ && type_signature_ == other.type_signature_;
+}
+
#ifdef ART_TARGET_ANDROID
// Convert an AccessMethod enum to a value for logging from the proto enum.
// This method may look odd (the enum values are current the same), but it
@@ -238,63 +270,88 @@ static ALWAYS_INLINE void MaybeWhitelistMember(Runtime* runtime, T* member)
static constexpr uint32_t kNoDexFlags = 0u;
static constexpr uint32_t kInvalidDexFlags = static_cast<uint32_t>(-1);
-uint32_t GetDexFlags(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> declaring_class = field->GetDeclaringClass();
- DCHECK(declaring_class != nullptr) << "Fields always have a declaring class";
-
- const DexFile::ClassDef* class_def = declaring_class->GetClassDef();
- if (class_def == nullptr) {
- return kNoDexFlags;
- }
+static ALWAYS_INLINE uint32_t GetMemberDexIndex(ArtField* field) {
+ return field->GetDexFieldIndex();
+}
- uint32_t flags = kInvalidDexFlags;
- DCHECK(!AreValidDexFlags(flags));
+static ALWAYS_INLINE uint32_t GetMemberDexIndex(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Use the non-obsolete method to avoid DexFile mismatch between
+ // the method index and the declaring class.
+ return method->GetNonObsoleteMethod()->GetDexMethodIndex();
+}
- ClassAccessor accessor(declaring_class->GetDexFile(),
- *class_def,
- /* parse_hiddenapi_class_data= */ true);
- auto fn_visit = [&](const ClassAccessor::Field& dex_field) {
- if (dex_field.GetIndex() == field->GetDexFieldIndex()) {
- flags = dex_field.GetHiddenapiFlags();
- }
- };
+static void VisitMembers(const DexFile& dex_file,
+ const DexFile::ClassDef& class_def,
+ const std::function<void(const ClassAccessor::Field&)>& fn_visit) {
+ ClassAccessor accessor(dex_file, class_def, /* parse_hiddenapi_class_data= */ true);
accessor.VisitFields(fn_visit, fn_visit);
+}
- CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for field " << field->PrettyField();
- DCHECK(AreValidDexFlags(flags));
- return flags;
+static void VisitMembers(const DexFile& dex_file,
+ const DexFile::ClassDef& class_def,
+ const std::function<void(const ClassAccessor::Method&)>& fn_visit) {
+ ClassAccessor accessor(dex_file, class_def, /* parse_hiddenapi_class_data= */ true);
+ accessor.VisitMethods(fn_visit, fn_visit);
}
-uint32_t GetDexFlags(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> declaring_class = method->GetDeclaringClass();
- if (declaring_class.IsNull()) {
- DCHECK(method->IsRuntimeMethod());
- return kNoDexFlags;
- }
+template<typename T>
+uint32_t GetDexFlags(T* member) REQUIRES_SHARED(Locks::mutator_lock_) {
+ static_assert(std::is_same<T, ArtField>::value || std::is_same<T, ArtMethod>::value);
+ using AccessorType = typename std::conditional<std::is_same<T, ArtField>::value,
+ ClassAccessor::Field, ClassAccessor::Method>::type;
- const DexFile::ClassDef* class_def = declaring_class->GetClassDef();
- if (class_def == nullptr) {
+ ObjPtr<mirror::Class> declaring_class = member->GetDeclaringClass();
+ if (declaring_class.IsNull()) {
return kNoDexFlags;
}
uint32_t flags = kInvalidDexFlags;
DCHECK(!AreValidDexFlags(flags));
- // Use the non-obsolete method to avoid DexFile mismatch between
- // the method index and the declaring class.
- uint32_t method_index = method->GetNonObsoleteMethod()->GetDexMethodIndex();
-
- ClassAccessor accessor(declaring_class->GetDexFile(),
- *class_def,
- /* parse_hiddenapi_class_data= */ true);
- auto fn_visit = [&](const ClassAccessor::Method& dex_method) {
- if (dex_method.GetIndex() == method_index) {
- flags = dex_method.GetHiddenapiFlags();
+ // Check if the declaring class has ClassExt allocated. If it does, check if
+ // the pre-JVMTI redefine dex file has been set to determine if the declaring
+ // class has been JVMTI-redefined.
+ ObjPtr<mirror::ClassExt> ext(declaring_class->GetExtData());
+ const DexFile* original_dex = ext.IsNull() ? nullptr : ext->GetPreRedefineDexFile();
+ if (LIKELY(original_dex == nullptr)) {
+ // Class is not redefined. Find the class def, iterate over its members and
+ // find the entry corresponding to this `member`.
+ const DexFile::ClassDef* class_def = declaring_class->GetClassDef();
+ if (class_def == nullptr) {
+ flags = kNoDexFlags;
+ } else {
+ uint32_t member_index = GetMemberDexIndex(member);
+ auto fn_visit = [&](const AccessorType& dex_member) {
+ if (dex_member.GetIndex() == member_index) {
+ flags = dex_member.GetHiddenapiFlags();
+ }
+ };
+ VisitMembers(declaring_class->GetDexFile(), *class_def, fn_visit);
}
- };
- accessor.VisitMethods(fn_visit, fn_visit);
+ } else {
+ // Class was redefined using JVMTI. We have a pointer to the original dex file
+ // and the class def index of this class in that dex file, but the field/method
+ // indices are lost. Iterate over all members of the class def and find the one
+ // corresponding to this `member` by name and type string comparison.
+ // This is obviously very slow, but it is only used when non-exempt code tries
+ // to access a hidden member of a JVMTI-redefined class.
+ uint16_t class_def_idx = ext->GetPreRedefineClassDefIndex();
+ DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
+ const DexFile::ClassDef& original_class_def = original_dex->GetClassDef(class_def_idx);
+ MemberSignature member_signature(member);
+ auto fn_visit = [&](const AccessorType& dex_member) {
+ MemberSignature cur_signature(dex_member);
+ if (member_signature.MemberNameAndTypeMatch(cur_signature)) {
+ DCHECK(member_signature.Equals(cur_signature));
+ flags = dex_member.GetHiddenapiFlags();
+ }
+ };
+ VisitMembers(*original_dex, original_class_def, fn_visit);
+ }
- CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for method " << method->PrettyMethod();
+ CHECK_NE(flags, kInvalidDexFlags) << "Could not find hiddenapi flags for "
+ << Dumpable<MemberSignature>(MemberSignature(member));
DCHECK(AreValidDexFlags(flags));
return flags;
}
@@ -356,6 +413,8 @@ bool ShouldDenyAccessToMemberImpl(T* member,
}
// Need to instantiate this.
+template uint32_t GetDexFlags<ArtField>(ArtField* member);
+template uint32_t GetDexFlags<ArtMethod>(ArtMethod* member);
template bool ShouldDenyAccessToMemberImpl<ArtField>(ArtField* member,
hiddenapi::ApiList api_list,
AccessMethod access_method);