diff options
Diffstat (limited to 'runtime/hidden_api.cc')
| -rw-r--r-- | runtime/hidden_api.cc | 143 |
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); |