| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "dex_file_annotations.h" |
| |
| #include <stdlib.h> |
| |
| #include "android-base/macros.h" |
| #include "android-base/stringprintf.h" |
| #include "art_field-inl.h" |
| #include "art_method-alloc-inl.h" |
| #include "base/sdk_version.h" |
| #include "class_linker-inl.h" |
| #include "class_root-inl.h" |
| #include "dex/dex_file-inl.h" |
| #include "dex/dex_instruction-inl.h" |
| #include "jni/jni_internal.h" |
| #include "jvalue-inl.h" |
| #include "mirror/array-alloc-inl.h" |
| #include "mirror/class-alloc-inl.h" |
| #include "mirror/field.h" |
| #include "mirror/method.h" |
| #include "mirror/object_array-alloc-inl.h" |
| #include "mirror/object_array-inl.h" |
| #include "oat/oat_file.h" |
| #include "obj_ptr-inl.h" |
| #include "reflection.h" |
| #include "thread.h" |
| #include "well_known_classes.h" |
| |
| namespace art HIDDEN { |
| |
| using android::base::StringPrintf; |
| |
| using dex::AnnotationItem; |
| using dex::AnnotationSetItem; |
| using dex::AnnotationSetRefItem; |
| using dex::AnnotationSetRefList; |
| using dex::AnnotationsDirectoryItem; |
| using dex::FieldAnnotationsItem; |
| using dex::MethodAnnotationsItem; |
| using dex::ParameterAnnotationsItem; |
| |
| struct DexFile::AnnotationValue { |
| JValue value_; |
| uint8_t type_; |
| }; |
| |
| namespace { |
| |
| // A helper class that contains all the data needed to do annotation lookup. |
| class ClassData { |
| public: |
| explicit ClassData(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) |
| : ClassData(ScopedNullHandle<mirror::Class>(), // klass |
| method, |
| *method->GetDexFile(), |
| &method->GetClassDef()) {} |
| |
| // Requires Scope to be able to create at least 1 handles. |
| template <typename Scope> |
| ClassData(Scope& hs, ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) |
| : ClassData(hs.NewHandle(field->GetDeclaringClass())) { } |
| |
| explicit ClassData(Handle<mirror::Class> klass) REQUIRES_SHARED(art::Locks::mutator_lock_) |
| : ClassData(klass, // klass |
| nullptr, // method |
| klass->GetDexFile(), |
| klass->GetClassDef()) {} |
| |
| const DexFile& GetDexFile() const REQUIRES_SHARED(Locks::mutator_lock_) { |
| return dex_file_; |
| } |
| |
| const dex::ClassDef* GetClassDef() const REQUIRES_SHARED(Locks::mutator_lock_) { |
| return class_def_; |
| } |
| |
| ObjPtr<mirror::DexCache> GetDexCache() const REQUIRES_SHARED(Locks::mutator_lock_) { |
| if (method_ != nullptr) { |
| return method_->GetDexCache(); |
| } else { |
| return real_klass_->GetDexCache(); |
| } |
| } |
| |
| ObjPtr<mirror::ClassLoader> GetClassLoader() const REQUIRES_SHARED(Locks::mutator_lock_) { |
| if (method_ != nullptr) { |
| return method_->GetDeclaringClass()->GetClassLoader(); |
| } else { |
| return real_klass_->GetClassLoader(); |
| } |
| } |
| |
| ObjPtr<mirror::Class> GetRealClass() const REQUIRES_SHARED(Locks::mutator_lock_) { |
| if (method_ != nullptr) { |
| return method_->GetDeclaringClass(); |
| } else { |
| return real_klass_.Get(); |
| } |
| } |
| |
| private: |
| ClassData(Handle<mirror::Class> klass, |
| ArtMethod* method, |
| const DexFile& dex_file, |
| const dex::ClassDef* class_def) REQUIRES_SHARED(Locks::mutator_lock_) |
| : real_klass_(klass), |
| method_(method), |
| dex_file_(dex_file), |
| class_def_(class_def) { |
| DCHECK((method_ == nullptr) || real_klass_.IsNull()); |
| } |
| |
| Handle<mirror::Class> real_klass_; |
| ArtMethod* method_; |
| const DexFile& dex_file_; |
| const dex::ClassDef* class_def_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ClassData); |
| }; |
| |
| ObjPtr<mirror::Object> CreateAnnotationMember(const ClassData& klass, |
| Handle<mirror::Class> annotation_class, |
| const uint8_t** annotation) |
| REQUIRES_SHARED(Locks::mutator_lock_); |
| |
| bool IsVisibilityCompatible(uint32_t actual, uint32_t expected) { |
| if (expected == DexFile::kDexVisibilityRuntime) { |
| if (IsSdkVersionSetAndAtMost(Runtime::Current()->GetTargetSdkVersion(), SdkVersion::kM)) { |
| return actual == DexFile::kDexVisibilityRuntime || actual == DexFile::kDexVisibilityBuild; |
| } |
| } |
| return actual == expected; |
| } |
| |
| static const AnnotationSetItem* FindAnnotationSetForField(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t field_index) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const AnnotationsDirectoryItem* annotations_dir = dex_file.GetAnnotationsDirectory(class_def); |
| if (annotations_dir == nullptr) { |
| return nullptr; |
| } |
| const FieldAnnotationsItem* field_annotations = dex_file.GetFieldAnnotations(annotations_dir); |
| if (field_annotations == nullptr) { |
| return nullptr; |
| } |
| uint32_t field_count = annotations_dir->fields_size_; |
| for (uint32_t i = 0; i < field_count; ++i) { |
| if (field_annotations[i].field_idx_ == field_index) { |
| return dex_file.GetFieldAnnotationSetItem(field_annotations[i]); |
| } |
| } |
| return nullptr; |
| } |
| |
| static const AnnotationSetItem* FindAnnotationSetForField(ArtField* field) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| ObjPtr<mirror::Class> klass = field->GetDeclaringClass(); |
| const dex::ClassDef* class_def = klass->GetClassDef(); |
| if (class_def == nullptr) { |
| DCHECK(klass->IsProxyClass()); |
| return nullptr; |
| } |
| return FindAnnotationSetForField(*field->GetDexFile(), *class_def, field->GetDexFieldIndex()); |
| } |
| |
| const AnnotationItem* SearchAnnotationSet(const DexFile& dex_file, |
| const AnnotationSetItem* annotation_set, |
| const char* descriptor, |
| uint32_t visibility) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const AnnotationItem* result = nullptr; |
| for (uint32_t i = 0; i < annotation_set->size_; ++i) { |
| const AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i); |
| if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) { |
| continue; |
| } |
| const uint8_t* annotation = annotation_item->annotation_; |
| uint32_t type_index = DecodeUnsignedLeb128(&annotation); |
| |
| if (strcmp(descriptor, dex_file.StringByTypeIdx(dex::TypeIndex(type_index))) == 0) { |
| result = annotation_item; |
| break; |
| } |
| } |
| return result; |
| } |
| |
| inline static void SkipEncodedValueHeaderByte(const uint8_t** annotation_ptr) { |
| (*annotation_ptr)++; |
| } |
| |
| bool SkipAnnotationValue(const DexFile& dex_file, const uint8_t** annotation_ptr) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const uint8_t* annotation = *annotation_ptr; |
| uint8_t header_byte = *(annotation++); |
| uint8_t value_type = header_byte & DexFile::kDexAnnotationValueTypeMask; |
| uint8_t value_arg = header_byte >> DexFile::kDexAnnotationValueArgShift; |
| int32_t width = value_arg + 1; |
| |
| switch (value_type) { |
| case DexFile::kDexAnnotationByte: |
| case DexFile::kDexAnnotationShort: |
| case DexFile::kDexAnnotationChar: |
| case DexFile::kDexAnnotationInt: |
| case DexFile::kDexAnnotationLong: |
| case DexFile::kDexAnnotationFloat: |
| case DexFile::kDexAnnotationDouble: |
| case DexFile::kDexAnnotationString: |
| case DexFile::kDexAnnotationType: |
| case DexFile::kDexAnnotationMethod: |
| case DexFile::kDexAnnotationField: |
| case DexFile::kDexAnnotationEnum: |
| break; |
| case DexFile::kDexAnnotationArray: |
| { |
| uint32_t size = DecodeUnsignedLeb128(&annotation); |
| for (; size != 0u; --size) { |
| if (!SkipAnnotationValue(dex_file, &annotation)) { |
| return false; |
| } |
| } |
| width = 0; |
| break; |
| } |
| case DexFile::kDexAnnotationAnnotation: |
| { |
| DecodeUnsignedLeb128(&annotation); // unused type_index |
| uint32_t size = DecodeUnsignedLeb128(&annotation); |
| for (; size != 0u; --size) { |
| DecodeUnsignedLeb128(&annotation); // unused element_name_index |
| if (!SkipAnnotationValue(dex_file, &annotation)) { |
| return false; |
| } |
| } |
| width = 0; |
| break; |
| } |
| case DexFile::kDexAnnotationBoolean: |
| case DexFile::kDexAnnotationNull: |
| width = 0; |
| break; |
| default: |
| LOG(FATAL) << StringPrintf("Bad annotation element value byte 0x%02x", value_type); |
| UNREACHABLE(); |
| } |
| |
| annotation += width; |
| *annotation_ptr = annotation; |
| return true; |
| } |
| |
| const uint8_t* SearchEncodedAnnotation(const DexFile& dex_file, |
| const uint8_t* annotation, |
| const char* name) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| DecodeUnsignedLeb128(&annotation); // unused type_index |
| uint32_t size = DecodeUnsignedLeb128(&annotation); |
| |
| while (size != 0) { |
| uint32_t element_name_index = DecodeUnsignedLeb128(&annotation); |
| const char* element_name = |
| dex_file.GetStringData(dex_file.GetStringId(dex::StringIndex(element_name_index))); |
| if (strcmp(name, element_name) == 0) { |
| return annotation; |
| } |
| SkipAnnotationValue(dex_file, &annotation); |
| size--; |
| } |
| return nullptr; |
| } |
| |
| static const AnnotationSetItem* FindAnnotationSetForMethod(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t method_index) { |
| const AnnotationsDirectoryItem* annotations_dir = dex_file.GetAnnotationsDirectory(class_def); |
| if (annotations_dir == nullptr) { |
| return nullptr; |
| } |
| const MethodAnnotationsItem* method_annotations = dex_file.GetMethodAnnotations(annotations_dir); |
| if (method_annotations == nullptr) { |
| return nullptr; |
| } |
| uint32_t method_count = annotations_dir->methods_size_; |
| for (uint32_t i = 0; i < method_count; ++i) { |
| if (method_annotations[i].method_idx_ == method_index) { |
| return dex_file.GetMethodAnnotationSetItem(method_annotations[i]); |
| } |
| } |
| return nullptr; |
| } |
| |
| inline const AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| if (method->IsProxyMethod()) { |
| return nullptr; |
| } |
| return FindAnnotationSetForMethod(*method->GetDexFile(), |
| method->GetClassDef(), |
| method->GetDexMethodIndex()); |
| } |
| |
| const ParameterAnnotationsItem* FindAnnotationsItemForMethod(ArtMethod* method) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile* dex_file = method->GetDexFile(); |
| const AnnotationsDirectoryItem* annotations_dir = |
| dex_file->GetAnnotationsDirectory(method->GetClassDef()); |
| if (annotations_dir == nullptr) { |
| return nullptr; |
| } |
| const ParameterAnnotationsItem* parameter_annotations = |
| dex_file->GetParameterAnnotations(annotations_dir); |
| if (parameter_annotations == nullptr) { |
| return nullptr; |
| } |
| uint32_t method_index = method->GetDexMethodIndex(); |
| uint32_t parameter_count = annotations_dir->parameters_size_; |
| for (uint32_t i = 0; i < parameter_count; ++i) { |
| if (parameter_annotations[i].method_idx_ == method_index) { |
| return ¶meter_annotations[i]; |
| } |
| } |
| return nullptr; |
| } |
| |
| static const AnnotationSetItem* FindAnnotationSetForClass(const ClassData& klass) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| const dex::ClassDef* class_def = klass.GetClassDef(); |
| if (class_def == nullptr) { |
| DCHECK(klass.GetRealClass()->IsProxyClass()); |
| return nullptr; |
| } |
| const AnnotationsDirectoryItem* annotations_dir = dex_file.GetAnnotationsDirectory(*class_def); |
| if (annotations_dir == nullptr) { |
| return nullptr; |
| } |
| return dex_file.GetClassAnnotationSet(annotations_dir); |
| } |
| |
| ObjPtr<mirror::Object> ProcessEncodedAnnotation(const ClassData& klass, const uint8_t** annotation) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| uint32_t type_index = DecodeUnsignedLeb128(annotation); |
| uint32_t size = DecodeUnsignedLeb128(annotation); |
| |
| Thread* self = Thread::Current(); |
| StackHandleScope<4> hs(self); |
| ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| Handle<mirror::Class> annotation_class(hs.NewHandle( |
| class_linker->ResolveType(dex::TypeIndex(type_index), |
| hs.NewHandle(klass.GetDexCache()), |
| hs.NewHandle(klass.GetClassLoader())))); |
| if (annotation_class == nullptr) { |
| LOG(INFO) << "Unable to resolve " << klass.GetRealClass()->PrettyClass() |
| << " annotation class " << type_index; |
| DCHECK(Thread::Current()->IsExceptionPending()); |
| Thread::Current()->ClearException(); |
| return nullptr; |
| } |
| |
| ObjPtr<mirror::Class> annotation_member_array_class = |
| WellKnownClasses::ToClass(WellKnownClasses::libcore_reflect_AnnotationMember__array); |
| if (annotation_member_array_class == nullptr) { |
| return nullptr; |
| } |
| ObjPtr<mirror::ObjectArray<mirror::Object>> element_array = nullptr; |
| if (size > 0) { |
| element_array = |
| mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_member_array_class, size); |
| if (element_array == nullptr) { |
| LOG(ERROR) << "Failed to allocate annotation member array (" << size << " elements)"; |
| return nullptr; |
| } |
| } |
| |
| Handle<mirror::ObjectArray<mirror::Object>> h_element_array(hs.NewHandle(element_array)); |
| for (uint32_t i = 0; i < size; ++i) { |
| ObjPtr<mirror::Object> new_member = CreateAnnotationMember(klass, annotation_class, annotation); |
| if (new_member == nullptr) { |
| return nullptr; |
| } |
| h_element_array->SetWithoutChecks<false>(i, new_member); |
| } |
| |
| ArtMethod* create_annotation_method = |
| WellKnownClasses::libcore_reflect_AnnotationFactory_createAnnotation; |
| ObjPtr<mirror::Object> result = create_annotation_method->InvokeStatic<'L', 'L', 'L'>( |
| self, annotation_class.Get(), h_element_array.Get()); |
| if (self->IsExceptionPending()) { |
| LOG(INFO) << "Exception in AnnotationFactory.createAnnotation"; |
| return nullptr; |
| } |
| |
| return result; |
| } |
| |
| template <bool kTransactionActive> |
| bool ProcessAnnotationValue(const ClassData& klass, |
| const uint8_t** annotation_ptr, |
| DexFile::AnnotationValue* annotation_value, |
| Handle<mirror::Class> array_class, |
| DexFile::AnnotationResultStyle result_style) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| Thread* self = Thread::Current(); |
| ObjPtr<mirror::Object> element_object = nullptr; |
| bool set_object = false; |
| Primitive::Type primitive_type = Primitive::kPrimVoid; |
| const uint8_t* annotation = *annotation_ptr; |
| uint8_t header_byte = *(annotation++); |
| uint8_t value_type = header_byte & DexFile::kDexAnnotationValueTypeMask; |
| uint8_t value_arg = header_byte >> DexFile::kDexAnnotationValueArgShift; |
| int32_t width = value_arg + 1; |
| annotation_value->type_ = value_type; |
| |
| switch (value_type) { |
| case DexFile::kDexAnnotationByte: |
| annotation_value->value_.SetB( |
| static_cast<int8_t>(DexFile::ReadSignedInt(annotation, value_arg))); |
| primitive_type = Primitive::kPrimByte; |
| break; |
| case DexFile::kDexAnnotationShort: |
| annotation_value->value_.SetS( |
| static_cast<int16_t>(DexFile::ReadSignedInt(annotation, value_arg))); |
| primitive_type = Primitive::kPrimShort; |
| break; |
| case DexFile::kDexAnnotationChar: |
| annotation_value->value_.SetC( |
| static_cast<uint16_t>(DexFile::ReadUnsignedInt(annotation, value_arg, false))); |
| primitive_type = Primitive::kPrimChar; |
| break; |
| case DexFile::kDexAnnotationInt: |
| annotation_value->value_.SetI(DexFile::ReadSignedInt(annotation, value_arg)); |
| primitive_type = Primitive::kPrimInt; |
| break; |
| case DexFile::kDexAnnotationLong: |
| annotation_value->value_.SetJ(DexFile::ReadSignedLong(annotation, value_arg)); |
| primitive_type = Primitive::kPrimLong; |
| break; |
| case DexFile::kDexAnnotationFloat: |
| annotation_value->value_.SetI(DexFile::ReadUnsignedInt(annotation, value_arg, true)); |
| primitive_type = Primitive::kPrimFloat; |
| break; |
| case DexFile::kDexAnnotationDouble: |
| annotation_value->value_.SetJ(DexFile::ReadUnsignedLong(annotation, value_arg, true)); |
| primitive_type = Primitive::kPrimDouble; |
| break; |
| case DexFile::kDexAnnotationBoolean: |
| annotation_value->value_.SetZ(value_arg != 0); |
| primitive_type = Primitive::kPrimBoolean; |
| width = 0; |
| break; |
| case DexFile::kDexAnnotationString: { |
| uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false); |
| if (result_style == DexFile::kAllRaw) { |
| annotation_value->value_.SetI(index); |
| } else { |
| StackHandleScope<1> hs(self); |
| element_object = Runtime::Current()->GetClassLinker()->ResolveString( |
| dex::StringIndex(index), hs.NewHandle(klass.GetDexCache())); |
| set_object = true; |
| if (element_object == nullptr) { |
| return false; |
| } |
| } |
| break; |
| } |
| case DexFile::kDexAnnotationType: { |
| uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false); |
| if (result_style == DexFile::kAllRaw) { |
| annotation_value->value_.SetI(index); |
| } else { |
| dex::TypeIndex type_index(index); |
| StackHandleScope<2> hs(self); |
| element_object = Runtime::Current()->GetClassLinker()->ResolveType( |
| type_index, |
| hs.NewHandle(klass.GetDexCache()), |
| hs.NewHandle(klass.GetClassLoader())); |
| set_object = true; |
| if (element_object == nullptr) { |
| CHECK(self->IsExceptionPending()); |
| if (result_style == DexFile::kAllObjects) { |
| const char* msg = dex_file.StringByTypeIdx(type_index); |
| self->ThrowNewWrappedException("Ljava/lang/TypeNotPresentException;", msg); |
| element_object = self->GetException(); |
| self->ClearException(); |
| } else { |
| return false; |
| } |
| } |
| } |
| break; |
| } |
| case DexFile::kDexAnnotationMethod: { |
| uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false); |
| if (result_style == DexFile::kAllRaw) { |
| annotation_value->value_.SetI(index); |
| } else { |
| ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| StackHandleScope<2> hs(self); |
| ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType( |
| index, |
| hs.NewHandle(klass.GetDexCache()), |
| hs.NewHandle(klass.GetClassLoader())); |
| if (method == nullptr) { |
| return false; |
| } |
| PointerSize pointer_size = class_linker->GetImagePointerSize(); |
| set_object = true; |
| if (method->IsConstructor()) { |
| element_object = (pointer_size == PointerSize::k64) |
| ? mirror::Constructor::CreateFromArtMethod<PointerSize::k64>(self, method) |
| : mirror::Constructor::CreateFromArtMethod<PointerSize::k32>(self, method); |
| } else { |
| element_object = (pointer_size == PointerSize::k64) |
| ? mirror::Method::CreateFromArtMethod<PointerSize::k64>(self, method) |
| : mirror::Method::CreateFromArtMethod<PointerSize::k32>(self, method); |
| } |
| if (element_object == nullptr) { |
| return false; |
| } |
| } |
| break; |
| } |
| case DexFile::kDexAnnotationField: { |
| uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false); |
| if (result_style == DexFile::kAllRaw) { |
| annotation_value->value_.SetI(index); |
| } else { |
| StackHandleScope<2> hs(self); |
| ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS( |
| index, |
| hs.NewHandle(klass.GetDexCache()), |
| hs.NewHandle(klass.GetClassLoader())); |
| if (field == nullptr) { |
| return false; |
| } |
| set_object = true; |
| element_object = mirror::Field::CreateFromArtField(self, field, true); |
| if (element_object == nullptr) { |
| return false; |
| } |
| } |
| break; |
| } |
| case DexFile::kDexAnnotationEnum: { |
| uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false); |
| if (result_style == DexFile::kAllRaw) { |
| annotation_value->value_.SetI(index); |
| } else { |
| StackHandleScope<3> hs(self); |
| ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField( |
| index, |
| hs.NewHandle(klass.GetDexCache()), |
| hs.NewHandle(klass.GetClassLoader()), |
| true); |
| if (enum_field == nullptr) { |
| return false; |
| } else { |
| Handle<mirror::Class> field_class(hs.NewHandle(enum_field->GetDeclaringClass())); |
| Runtime::Current()->GetClassLinker()->EnsureInitialized(self, field_class, true, true); |
| element_object = enum_field->GetObject(field_class.Get()); |
| set_object = true; |
| } |
| } |
| break; |
| } |
| case DexFile::kDexAnnotationArray: |
| if (result_style == DexFile::kAllRaw || array_class == nullptr) { |
| return false; |
| } else { |
| ScopedObjectAccessUnchecked soa(self); |
| StackHandleScope<2> hs(self); |
| uint32_t size = DecodeUnsignedLeb128(&annotation); |
| Handle<mirror::Class> component_type(hs.NewHandle(array_class->GetComponentType())); |
| Handle<mirror::Array> new_array(hs.NewHandle(mirror::Array::Alloc( |
| self, array_class.Get(), size, array_class->GetComponentSizeShift(), |
| Runtime::Current()->GetHeap()->GetCurrentAllocator()))); |
| if (new_array == nullptr) { |
| LOG(ERROR) << "Annotation element array allocation failed with size " << size; |
| return false; |
| } |
| DexFile::AnnotationValue new_annotation_value; |
| for (uint32_t i = 0; i < size; ++i) { |
| if (!ProcessAnnotationValue<kTransactionActive>(klass, |
| &annotation, |
| &new_annotation_value, |
| component_type, |
| DexFile::kPrimitivesOrObjects)) { |
| return false; |
| } |
| if (!component_type->IsPrimitive()) { |
| ObjPtr<mirror::Object> obj = new_annotation_value.value_.GetL(); |
| new_array->AsObjectArray<mirror::Object>()-> |
| SetWithoutChecks<kTransactionActive>(i, obj); |
| } else { |
| switch (new_annotation_value.type_) { |
| case DexFile::kDexAnnotationByte: |
| new_array->AsByteArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetB()); |
| break; |
| case DexFile::kDexAnnotationShort: |
| new_array->AsShortArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetS()); |
| break; |
| case DexFile::kDexAnnotationChar: |
| new_array->AsCharArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetC()); |
| break; |
| case DexFile::kDexAnnotationInt: |
| new_array->AsIntArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetI()); |
| break; |
| case DexFile::kDexAnnotationLong: |
| new_array->AsLongArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetJ()); |
| break; |
| case DexFile::kDexAnnotationFloat: |
| new_array->AsFloatArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetF()); |
| break; |
| case DexFile::kDexAnnotationDouble: |
| new_array->AsDoubleArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetD()); |
| break; |
| case DexFile::kDexAnnotationBoolean: |
| new_array->AsBooleanArray()->SetWithoutChecks<kTransactionActive>( |
| i, new_annotation_value.value_.GetZ()); |
| break; |
| default: |
| LOG(FATAL) << "Found invalid annotation value type while building annotation array"; |
| return false; |
| } |
| } |
| } |
| element_object = new_array.Get(); |
| set_object = true; |
| width = 0; |
| } |
| break; |
| case DexFile::kDexAnnotationAnnotation: |
| if (result_style == DexFile::kAllRaw) { |
| return false; |
| } |
| element_object = ProcessEncodedAnnotation(klass, &annotation); |
| if (element_object == nullptr) { |
| return false; |
| } |
| set_object = true; |
| width = 0; |
| break; |
| case DexFile::kDexAnnotationNull: |
| if (result_style == DexFile::kAllRaw) { |
| annotation_value->value_.SetI(0); |
| } else { |
| CHECK(element_object == nullptr); |
| set_object = true; |
| } |
| width = 0; |
| break; |
| default: |
| LOG(ERROR) << StringPrintf("Bad annotation element value type 0x%02x", value_type); |
| return false; |
| } |
| |
| annotation += width; |
| *annotation_ptr = annotation; |
| |
| if (result_style == DexFile::kAllObjects && primitive_type != Primitive::kPrimVoid) { |
| element_object = BoxPrimitive(primitive_type, annotation_value->value_); |
| set_object = true; |
| } |
| |
| if (set_object) { |
| annotation_value->value_.SetL(element_object); |
| } |
| |
| return true; |
| } |
| |
| ObjPtr<mirror::Object> CreateAnnotationMember(const ClassData& klass, |
| Handle<mirror::Class> annotation_class, |
| const uint8_t** annotation) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| Thread* self = Thread::Current(); |
| ScopedObjectAccessUnchecked soa(self); |
| StackHandleScope<5> hs(self); |
| uint32_t element_name_index = DecodeUnsignedLeb128(annotation); |
| const char* name = dex_file.StringDataByIdx(dex::StringIndex(element_name_index)); |
| |
| PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); |
| ArtMethod* annotation_method = |
| annotation_class->FindDeclaredVirtualMethodByName(name, pointer_size); |
| if (annotation_method == nullptr) { |
| return nullptr; |
| } |
| |
| Handle<mirror::String> string_name = |
| hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, name)); |
| if (UNLIKELY(string_name == nullptr)) { |
| LOG(ERROR) << "Failed to allocate name for annotation member"; |
| return nullptr; |
| } |
| |
| Handle<mirror::Class> method_return = hs.NewHandle(annotation_method->ResolveReturnType()); |
| if (UNLIKELY(method_return == nullptr)) { |
| LOG(ERROR) << "Failed to resolve method return type for annotation member"; |
| return nullptr; |
| } |
| |
| DexFile::AnnotationValue annotation_value; |
| if (!ProcessAnnotationValue<false>(klass, |
| annotation, |
| &annotation_value, |
| method_return, |
| DexFile::kAllObjects)) { |
| // TODO: Logging the error breaks run-test 005-annotations. |
| // LOG(ERROR) << "Failed to process annotation value for annotation member"; |
| return nullptr; |
| } |
| Handle<mirror::Object> value_object = hs.NewHandle(annotation_value.value_.GetL()); |
| |
| Handle<mirror::Method> method_object = hs.NewHandle((pointer_size == PointerSize::k64) |
| ? mirror::Method::CreateFromArtMethod<PointerSize::k64>(self, annotation_method) |
| : mirror::Method::CreateFromArtMethod<PointerSize::k32>(self, annotation_method)); |
| if (UNLIKELY(method_object == nullptr)) { |
| LOG(ERROR) << "Failed to create method object for annotation member"; |
| return nullptr; |
| } |
| |
| Handle<mirror::Object> new_member = |
| WellKnownClasses::libcore_reflect_AnnotationMember_init->NewObject<'L', 'L', 'L', 'L'>( |
| hs, self, string_name, value_object, method_return, method_object); |
| if (new_member == nullptr) { |
| DCHECK(self->IsExceptionPending()); |
| LOG(ERROR) << "Failed to create annotation member"; |
| return nullptr; |
| } |
| |
| return new_member.Get(); |
| } |
| |
| const AnnotationItem* GetAnnotationItemFromAnnotationSet(const ClassData& klass, |
| const AnnotationSetItem* annotation_set, |
| uint32_t visibility, |
| Handle<mirror::Class> annotation_class) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| for (uint32_t i = 0; i < annotation_set->size_; ++i) { |
| const AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i); |
| if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) { |
| continue; |
| } |
| const uint8_t* annotation = annotation_item->annotation_; |
| uint32_t type_index = DecodeUnsignedLeb128(&annotation); |
| ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| Thread* self = Thread::Current(); |
| StackHandleScope<2> hs(self); |
| ObjPtr<mirror::Class> resolved_class = class_linker->ResolveType( |
| dex::TypeIndex(type_index), |
| hs.NewHandle(klass.GetDexCache()), |
| hs.NewHandle(klass.GetClassLoader())); |
| if (resolved_class == nullptr) { |
| std::string temp; |
| LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d", |
| klass.GetRealClass()->GetDescriptor(&temp), type_index); |
| CHECK(self->IsExceptionPending()); |
| self->ClearException(); |
| continue; |
| } |
| if (resolved_class == annotation_class.Get()) { |
| return annotation_item; |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| ObjPtr<mirror::Object> GetAnnotationObjectFromAnnotationSet(const ClassData& klass, |
| const AnnotationSetItem* annotation_set, |
| uint32_t visibility, |
| Handle<mirror::Class> annotation_class) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet( |
| klass, annotation_set, visibility, annotation_class); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| const uint8_t* annotation = annotation_item->annotation_; |
| return ProcessEncodedAnnotation(klass, &annotation); |
| } |
| |
| ObjPtr<mirror::Object> GetAnnotationValue(const ClassData& klass, |
| const AnnotationItem* annotation_item, |
| const char* annotation_name, |
| Handle<mirror::Class> array_class, |
| uint32_t expected_type) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| const uint8_t* annotation = |
| SearchEncodedAnnotation(dex_file, annotation_item->annotation_, annotation_name); |
| if (annotation == nullptr) { |
| return nullptr; |
| } |
| DexFile::AnnotationValue annotation_value; |
| bool result = Runtime::Current()->IsActiveTransaction() |
| ? ProcessAnnotationValue<true>(klass, |
| &annotation, |
| &annotation_value, |
| array_class, |
| DexFile::kAllObjects) |
| : ProcessAnnotationValue<false>(klass, |
| &annotation, |
| &annotation_value, |
| array_class, |
| DexFile::kAllObjects); |
| if (!result) { |
| return nullptr; |
| } |
| if (annotation_value.type_ != expected_type) { |
| return nullptr; |
| } |
| return annotation_value.value_.GetL(); |
| } |
| |
| template<typename T> |
| static inline ObjPtr<mirror::ObjectArray<T>> GetAnnotationArrayValue( |
| Handle<mirror::Class> klass, |
| const char* annotation_name, |
| const char* value_name) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(data.GetDexFile(), annotation_set, annotation_name, |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| StackHandleScope<1> hs(Thread::Current()); |
| Handle<mirror::Class> class_array_class = |
| hs.NewHandle(GetClassRoot<mirror::ObjectArray<T>>()); |
| DCHECK(class_array_class != nullptr); |
| ObjPtr<mirror::Object> obj = GetAnnotationValue(data, |
| annotation_item, |
| value_name, |
| class_array_class, |
| DexFile::kDexAnnotationArray); |
| if (obj == nullptr) { |
| return nullptr; |
| } |
| return obj->AsObjectArray<T>(); |
| } |
| |
| static ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureValue( |
| const ClassData& klass, |
| const AnnotationSetItem* annotation_set) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| StackHandleScope<1> hs(Thread::Current()); |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Signature;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| Handle<mirror::Class> string_array_class = |
| hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>()); |
| DCHECK(string_array_class != nullptr); |
| ObjPtr<mirror::Object> obj = |
| GetAnnotationValue(klass, annotation_item, "value", string_array_class, |
| DexFile::kDexAnnotationArray); |
| if (obj == nullptr) { |
| return nullptr; |
| } |
| return obj->AsObjectArray<mirror::String>(); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Class>> GetThrowsValue(const ClassData& klass, |
| const AnnotationSetItem* annotation_set) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Throws;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| StackHandleScope<1> hs(Thread::Current()); |
| Handle<mirror::Class> class_array_class = |
| hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::Class>>()); |
| DCHECK(class_array_class != nullptr); |
| ObjPtr<mirror::Object> obj = |
| GetAnnotationValue(klass, annotation_item, "value", class_array_class, |
| DexFile::kDexAnnotationArray); |
| if (obj == nullptr) { |
| return nullptr; |
| } |
| return obj->AsObjectArray<mirror::Class>(); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Object>> ProcessAnnotationSet( |
| const ClassData& klass, |
| const AnnotationSetItem* annotation_set, |
| uint32_t visibility) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| Thread* self = Thread::Current(); |
| StackHandleScope<2> hs(self); |
| Handle<mirror::Class> annotation_array_class(hs.NewHandle( |
| WellKnownClasses::ToClass(WellKnownClasses::java_lang_annotation_Annotation__array))); |
| if (annotation_set == nullptr) { |
| return mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), 0); |
| } |
| |
| uint32_t size = annotation_set->size_; |
| Handle<mirror::ObjectArray<mirror::Object>> result(hs.NewHandle( |
| mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), size))); |
| if (result == nullptr) { |
| return nullptr; |
| } |
| |
| uint32_t dest_index = 0; |
| for (uint32_t i = 0; i < size; ++i) { |
| const AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i); |
| // Note that we do not use IsVisibilityCompatible here because older code |
| // was correct for this case. |
| if (annotation_item->visibility_ != visibility) { |
| continue; |
| } |
| const uint8_t* annotation = annotation_item->annotation_; |
| ObjPtr<mirror::Object> annotation_obj = ProcessEncodedAnnotation(klass, &annotation); |
| if (annotation_obj != nullptr) { |
| result->SetWithoutChecks<false>(dest_index, annotation_obj); |
| ++dest_index; |
| } else if (self->IsExceptionPending()) { |
| return nullptr; |
| } |
| } |
| |
| if (dest_index == size) { |
| return result.Get(); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Object>> trimmed_result = |
| mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), dest_index); |
| if (trimmed_result == nullptr) { |
| return nullptr; |
| } |
| |
| for (uint32_t i = 0; i < dest_index; ++i) { |
| ObjPtr<mirror::Object> obj = result->GetWithoutChecks(i); |
| trimmed_result->SetWithoutChecks<false>(i, obj); |
| } |
| |
| return trimmed_result; |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Object>> ProcessAnnotationSetRefList( |
| const ClassData& klass, |
| const AnnotationSetRefList* set_ref_list, |
| uint32_t size) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const DexFile& dex_file = klass.GetDexFile(); |
| Thread* self = Thread::Current(); |
| StackHandleScope<1> hs(self); |
| ObjPtr<mirror::Class> annotation_array_class = |
| WellKnownClasses::ToClass(WellKnownClasses::java_lang_annotation_Annotation__array); |
| ObjPtr<mirror::Class> annotation_array_array_class = |
| Runtime::Current()->GetClassLinker()->FindArrayClass(self, annotation_array_class); |
| if (annotation_array_array_class == nullptr) { |
| return nullptr; |
| } |
| Handle<mirror::ObjectArray<mirror::Object>> annotation_array_array(hs.NewHandle( |
| mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_array_class, size))); |
| if (annotation_array_array == nullptr) { |
| LOG(ERROR) << "Annotation set ref array allocation failed"; |
| return nullptr; |
| } |
| for (uint32_t index = 0; index < size; ++index) { |
| const AnnotationSetRefItem* set_ref_item = &set_ref_list->list_[index]; |
| const AnnotationSetItem* set_item = dex_file.GetSetRefItemItem(set_ref_item); |
| ObjPtr<mirror::Object> annotation_set = ProcessAnnotationSet(klass, |
| set_item, |
| DexFile::kDexVisibilityRuntime); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| annotation_array_array->SetWithoutChecks<false>(index, annotation_set); |
| } |
| return annotation_array_array.Get(); |
| } |
| } // namespace |
| |
| namespace annotations { |
| |
| ObjPtr<mirror::Object> GetAnnotationForField(ArtField* field, |
| Handle<mirror::Class> annotation_class) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| StackHandleScope<1> hs(Thread::Current()); |
| const ClassData field_class(hs, field); |
| return GetAnnotationObjectFromAnnotationSet(field_class, |
| annotation_set, |
| DexFile::kDexVisibilityRuntime, |
| annotation_class); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* field) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); |
| StackHandleScope<1> hs(Thread::Current()); |
| const ClassData field_class(hs, field); |
| return ProcessAnnotationSet(field_class, annotation_set, DexFile::kDexVisibilityRuntime); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| StackHandleScope<1> hs(Thread::Current()); |
| const ClassData field_class(hs, field); |
| return GetSignatureValue(field_class, annotation_set); |
| } |
| |
| bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| StackHandleScope<1> hs(Thread::Current()); |
| const ClassData field_class(hs, field); |
| const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet( |
| field_class, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class); |
| return annotation_item != nullptr; |
| } |
| |
| ObjPtr<mirror::Object> GetAnnotationDefaultValue(ArtMethod* method) { |
| const ClassData klass(method); |
| const DexFile* dex_file = &klass.GetDexFile(); |
| const AnnotationsDirectoryItem* annotations_dir = |
| dex_file->GetAnnotationsDirectory(*klass.GetClassDef()); |
| if (annotations_dir == nullptr) { |
| return nullptr; |
| } |
| const AnnotationSetItem* annotation_set = |
| dex_file->GetClassAnnotationSet(annotations_dir); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| const AnnotationItem* annotation_item = SearchAnnotationSet(*dex_file, annotation_set, |
| "Ldalvik/annotation/AnnotationDefault;", DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| const uint8_t* annotation = |
| SearchEncodedAnnotation(*dex_file, annotation_item->annotation_, "value"); |
| if (annotation == nullptr) { |
| return nullptr; |
| } |
| uint8_t header_byte = *(annotation++); |
| if ((header_byte & DexFile::kDexAnnotationValueTypeMask) != DexFile::kDexAnnotationAnnotation) { |
| return nullptr; |
| } |
| annotation = SearchEncodedAnnotation(*dex_file, annotation, method->GetName()); |
| if (annotation == nullptr) { |
| return nullptr; |
| } |
| DexFile::AnnotationValue annotation_value; |
| StackHandleScope<1> hs(Thread::Current()); |
| Handle<mirror::Class> return_type(hs.NewHandle(method->ResolveReturnType())); |
| if (!ProcessAnnotationValue<false>(klass, |
| &annotation, |
| &annotation_value, |
| return_type, |
| DexFile::kAllObjects)) { |
| return nullptr; |
| } |
| return annotation_value.value_.GetL(); |
| } |
| |
| ObjPtr<mirror::Object> GetAnnotationForMethod(ArtMethod* method, |
| Handle<mirror::Class> annotation_class) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| return GetAnnotationObjectFromAnnotationSet(ClassData(method), annotation_set, |
| DexFile::kDexVisibilityRuntime, annotation_class); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForMethod(ArtMethod* method) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); |
| return ProcessAnnotationSet(ClassData(method), |
| annotation_set, |
| DexFile::kDexVisibilityRuntime); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Class>> GetExceptionTypesForMethod(ArtMethod* method) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| return GetThrowsValue(ClassData(method), annotation_set); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Object>> GetParameterAnnotations(ArtMethod* method) { |
| const DexFile* dex_file = method->GetDexFile(); |
| const ParameterAnnotationsItem* parameter_annotations = |
| FindAnnotationsItemForMethod(method); |
| if (parameter_annotations == nullptr) { |
| return nullptr; |
| } |
| const AnnotationSetRefList* set_ref_list = |
| dex_file->GetParameterAnnotationSetRefList(parameter_annotations); |
| if (set_ref_list == nullptr) { |
| return nullptr; |
| } |
| uint32_t size = set_ref_list->size_; |
| return ProcessAnnotationSetRefList(ClassData(method), set_ref_list, size); |
| } |
| |
| uint32_t GetNumberOfAnnotatedMethodParameters(ArtMethod* method) { |
| const DexFile* dex_file = method->GetDexFile(); |
| const ParameterAnnotationsItem* parameter_annotations = |
| FindAnnotationsItemForMethod(method); |
| if (parameter_annotations == nullptr) { |
| return 0u; |
| } |
| const AnnotationSetRefList* set_ref_list = |
| dex_file->GetParameterAnnotationSetRefList(parameter_annotations); |
| if (set_ref_list == nullptr) { |
| return 0u; |
| } |
| return set_ref_list->size_; |
| } |
| |
| ObjPtr<mirror::Object> GetAnnotationForMethodParameter(ArtMethod* method, |
| uint32_t parameter_idx, |
| Handle<mirror::Class> annotation_class) { |
| const DexFile* dex_file = method->GetDexFile(); |
| const ParameterAnnotationsItem* parameter_annotations = FindAnnotationsItemForMethod(method); |
| if (parameter_annotations == nullptr) { |
| return nullptr; |
| } |
| const AnnotationSetRefList* set_ref_list = |
| dex_file->GetParameterAnnotationSetRefList(parameter_annotations); |
| if (set_ref_list == nullptr) { |
| return nullptr; |
| } |
| if (parameter_idx >= set_ref_list->size_) { |
| return nullptr; |
| } |
| const AnnotationSetRefItem* annotation_set_ref = &set_ref_list->list_[parameter_idx]; |
| const AnnotationSetItem* annotation_set = |
| dex_file->GetSetRefItemItem(annotation_set_ref); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| return GetAnnotationObjectFromAnnotationSet(ClassData(method), |
| annotation_set, |
| DexFile::kDexVisibilityRuntime, |
| annotation_class); |
| } |
| |
| bool GetParametersMetadataForMethod( |
| ArtMethod* method, |
| /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, |
| /*out*/ MutableHandle<mirror::IntArray>* access_flags) { |
| const AnnotationSetItem* annotation_set = |
| FindAnnotationSetForMethod(method); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| |
| const DexFile* dex_file = method->GetDexFile(); |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(*dex_file, |
| annotation_set, |
| "Ldalvik/annotation/MethodParameters;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return false; |
| } |
| |
| StackHandleScope<4> hs(Thread::Current()); |
| |
| // Extract the parameters' names String[]. |
| ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); |
| Handle<mirror::Class> string_array_class = |
| hs.NewHandle(GetClassRoot<mirror::ObjectArray<mirror::String>>(class_linker)); |
| DCHECK(string_array_class != nullptr); |
| |
| ClassData data(method); |
| Handle<mirror::Object> names_obj = |
| hs.NewHandle(GetAnnotationValue(data, |
| annotation_item, |
| "names", |
| string_array_class, |
| DexFile::kDexAnnotationArray)); |
| if (names_obj == nullptr) { |
| return false; |
| } |
| |
| // Extract the parameters' access flags int[]. |
| Handle<mirror::Class> int_array_class(hs.NewHandle(GetClassRoot<mirror::IntArray>(class_linker))); |
| DCHECK(int_array_class != nullptr); |
| Handle<mirror::Object> access_flags_obj = |
| hs.NewHandle(GetAnnotationValue(data, |
| annotation_item, |
| "accessFlags", |
| int_array_class, |
| DexFile::kDexAnnotationArray)); |
| if (access_flags_obj == nullptr) { |
| return false; |
| } |
| |
| names->Assign(names_obj->AsObjectArray<mirror::String>()); |
| access_flags->Assign(access_flags_obj->AsIntArray()); |
| return true; |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| return GetSignatureValue(ClassData(method), annotation_set); |
| } |
| |
| bool IsMethodAnnotationPresent(ArtMethod* method, |
| Handle<mirror::Class> annotation_class, |
| uint32_t visibility /* = DexFile::kDexVisibilityRuntime */) { |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet( |
| ClassData(method), annotation_set, visibility, annotation_class); |
| return annotation_item != nullptr; |
| } |
| |
| static void DCheckNativeAnnotation(const char* descriptor, jclass cls) { |
| if (kIsDebugBuild) { |
| ScopedObjectAccess soa(Thread::Current()); |
| ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls); |
| ClassLinker* linker = Runtime::Current()->GetClassLinker(); |
| // WellKnownClasses may not be initialized yet, so `klass` may be null. |
| if (klass != nullptr) { |
| // Lookup using the boot class path loader should yield the annotation class. |
| CHECK_EQ(klass, linker->LookupClass(soa.Self(), descriptor, /* class_loader= */ nullptr)); |
| } |
| } |
| } |
| |
| // Check whether a method from the `dex_file` with the given `annotation_set` |
| // is annotated with `annotation_descriptor` with build visibility. |
| static bool IsMethodBuildAnnotationPresent(const DexFile& dex_file, |
| const AnnotationSetItem& annotation_set, |
| const char* annotation_descriptor, |
| jclass annotation_class) { |
| for (uint32_t i = 0; i < annotation_set.size_; ++i) { |
| const AnnotationItem* annotation_item = dex_file.GetAnnotationItem(&annotation_set, i); |
| if (!IsVisibilityCompatible(annotation_item->visibility_, DexFile::kDexVisibilityBuild)) { |
| continue; |
| } |
| const uint8_t* annotation = annotation_item->annotation_; |
| uint32_t type_index = DecodeUnsignedLeb128(&annotation); |
| const char* descriptor = dex_file.StringByTypeIdx(dex::TypeIndex(type_index)); |
| if (strcmp(descriptor, annotation_descriptor) == 0) { |
| DCheckNativeAnnotation(descriptor, annotation_class); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| uint32_t GetNativeMethodAnnotationAccessFlags(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t method_index) { |
| const dex::AnnotationSetItem* annotation_set = |
| FindAnnotationSetForMethod(dex_file, class_def, method_index); |
| if (annotation_set == nullptr) { |
| return 0u; |
| } |
| uint32_t access_flags = 0u; |
| if (IsMethodBuildAnnotationPresent( |
| dex_file, |
| *annotation_set, |
| "Ldalvik/annotation/optimization/FastNative;", |
| WellKnownClasses::dalvik_annotation_optimization_FastNative)) { |
| access_flags |= kAccFastNative; |
| } |
| if (IsMethodBuildAnnotationPresent( |
| dex_file, |
| *annotation_set, |
| "Ldalvik/annotation/optimization/CriticalNative;", |
| WellKnownClasses::dalvik_annotation_optimization_CriticalNative)) { |
| access_flags |= kAccCriticalNative; |
| } |
| CHECK_NE(access_flags, kAccFastNative | kAccCriticalNative); |
| return access_flags; |
| } |
| |
| bool MethodIsNeverCompile(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t method_index) { |
| const dex::AnnotationSetItem* annotation_set = |
| FindAnnotationSetForMethod(dex_file, class_def, method_index); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| return IsMethodBuildAnnotationPresent( |
| dex_file, |
| *annotation_set, |
| "Ldalvik/annotation/optimization/NeverCompile;", |
| WellKnownClasses::dalvik_annotation_optimization_NeverCompile); |
| } |
| |
| bool MethodIsNeverInline(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t method_index) { |
| const dex::AnnotationSetItem* annotation_set = |
| FindAnnotationSetForMethod(dex_file, class_def, method_index); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| return IsMethodBuildAnnotationPresent( |
| dex_file, |
| *annotation_set, |
| "Ldalvik/annotation/optimization/NeverInline;", |
| WellKnownClasses::dalvik_annotation_optimization_NeverInline); |
| } |
| |
| bool FieldIsReachabilitySensitive(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t field_index) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const AnnotationSetItem* annotation_set = |
| FindAnnotationSetForField(dex_file, class_def, field_index); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set, |
| "Ldalvik/annotation/optimization/ReachabilitySensitive;", DexFile::kDexVisibilityRuntime); |
| // TODO: We're missing the equivalent of DCheckNativeAnnotation (not a DCHECK). Does it matter? |
| return annotation_item != nullptr; |
| } |
| |
| bool MethodIsReachabilitySensitive(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t method_index) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const AnnotationSetItem* annotation_set = |
| FindAnnotationSetForMethod(dex_file, class_def, method_index); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set, |
| "Ldalvik/annotation/optimization/ReachabilitySensitive;", DexFile::kDexVisibilityRuntime); |
| return annotation_item != nullptr; |
| } |
| |
| static bool MethodIsReachabilitySensitive(const DexFile& dex_file, |
| uint32_t method_index) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| DCHECK(method_index < dex_file.NumMethodIds()); |
| const dex::MethodId& method_id = dex_file.GetMethodId(method_index); |
| dex::TypeIndex class_index = method_id.class_idx_; |
| const dex::ClassDef * class_def = dex_file.FindClassDef(class_index); |
| return class_def != nullptr |
| && MethodIsReachabilitySensitive(dex_file, *class_def, method_index); |
| } |
| |
| bool MethodContainsRSensitiveAccess(const DexFile& dex_file, |
| const dex::ClassDef& class_def, |
| uint32_t method_index) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| // TODO: This is too slow to run very regularly. Currently this is only invoked in the |
| // presence of @DeadReferenceSafe, which will be rare. In the long run, we need to quickly |
| // check once whether a class has any @ReachabilitySensitive annotations. If not, we can |
| // immediately return false here for any method in that class. |
| uint32_t code_item_offset = dex_file.FindCodeItemOffset(class_def, method_index); |
| const dex::CodeItem* code_item = dex_file.GetCodeItem(code_item_offset); |
| CodeItemInstructionAccessor accessor(dex_file, code_item); |
| if (!accessor.HasCodeItem()) { |
| return false; |
| } |
| for (DexInstructionIterator iter = accessor.begin(); iter != accessor.end(); ++iter) { |
| switch (iter->Opcode()) { |
| case Instruction::IGET: |
| case Instruction::IGET_WIDE: |
| case Instruction::IGET_OBJECT: |
| case Instruction::IGET_BOOLEAN: |
| case Instruction::IGET_BYTE: |
| case Instruction::IGET_CHAR: |
| case Instruction::IGET_SHORT: |
| case Instruction::IPUT: |
| case Instruction::IPUT_WIDE: |
| case Instruction::IPUT_OBJECT: |
| case Instruction::IPUT_BOOLEAN: |
| case Instruction::IPUT_BYTE: |
| case Instruction::IPUT_CHAR: |
| case Instruction::IPUT_SHORT: |
| { |
| uint32_t field_index = iter->VRegC_22c(); |
| DCHECK(field_index < dex_file.NumFieldIds()); |
| // We only guarantee to pay attention to the annotation if it's in the same class, |
| // or a containing class, but it's OK to do so in other cases. |
| const dex::FieldId& field_id = dex_file.GetFieldId(field_index); |
| dex::TypeIndex class_index = field_id.class_idx_; |
| const dex::ClassDef * field_class_def = dex_file.FindClassDef(class_index); |
| // We do not handle the case in which the field is declared in a superclass, and |
| // don't claim to do so. The annotated field should normally be private. |
| if (field_class_def != nullptr |
| && FieldIsReachabilitySensitive(dex_file, *field_class_def, field_index)) { |
| return true; |
| } |
| } |
| break; |
| case Instruction::INVOKE_SUPER: |
| // Cannot call method in same class. TODO: Try an explicit superclass lookup for |
| // better "best effort"? |
| break; |
| case Instruction::INVOKE_INTERFACE: |
| // We handle an interface call just like a virtual call. We will find annotations |
| // on interface methods/fields visible to us, but not of the annotation is in a |
| // super-interface. Again, we could just ignore it. |
| case Instruction::INVOKE_VIRTUAL: |
| case Instruction::INVOKE_DIRECT: |
| { |
| uint32_t called_method_index = iter->VRegB_35c(); |
| if (MethodIsReachabilitySensitive(dex_file, called_method_index)) { |
| return true; |
| } |
| } |
| break; |
| case Instruction::INVOKE_INTERFACE_RANGE: |
| case Instruction::INVOKE_VIRTUAL_RANGE: |
| case Instruction::INVOKE_DIRECT_RANGE: |
| { |
| uint32_t called_method_index = iter->VRegB_3rc(); |
| if (MethodIsReachabilitySensitive(dex_file, called_method_index)) { |
| return true; |
| } |
| } |
| break; |
| // We explicitly do not handle indirect ReachabilitySensitive accesses through VarHandles, |
| // etc. Thus we ignore INVOKE_CUSTOM / INVOKE_CUSTOM_RANGE / INVOKE_POLYMORPHIC / |
| // INVOKE_POLYMORPHIC_RANGE. |
| default: |
| // There is no way to add an annotation to array elements, and so far we've encountered no |
| // need for that, so we ignore AGET and APUT. |
| // It's impractical or impossible to garbage collect a class while one of its methods is |
| // on the call stack. We allow ReachabilitySensitive annotations on static methods and |
| // fields, but they can be safely ignored. |
| break; |
| } |
| } |
| return false; |
| } |
| |
| bool HasDeadReferenceSafeAnnotation(const DexFile& dex_file, |
| const dex::ClassDef& class_def) |
| // TODO: This should check outer classes as well. |
| // It's conservatively correct not to do so. |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| const AnnotationsDirectoryItem* annotations_dir = |
| dex_file.GetAnnotationsDirectory(class_def); |
| if (annotations_dir == nullptr) { |
| return false; |
| } |
| const AnnotationSetItem* annotation_set = dex_file.GetClassAnnotationSet(annotations_dir); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| const AnnotationItem* annotation_item = SearchAnnotationSet(dex_file, annotation_set, |
| "Ldalvik/annotation/optimization/DeadReferenceSafe;", DexFile::kDexVisibilityRuntime); |
| return annotation_item != nullptr; |
| } |
| |
| ObjPtr<mirror::Object> GetAnnotationForClass(Handle<mirror::Class> klass, |
| Handle<mirror::Class> annotation_class) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| return GetAnnotationObjectFromAnnotationSet(data, |
| annotation_set, |
| DexFile::kDexVisibilityRuntime, |
| annotation_class); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForClass(Handle<mirror::Class> klass) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| return ProcessAnnotationSet(data, annotation_set, DexFile::kDexVisibilityRuntime); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Class>> GetDeclaredClasses(Handle<mirror::Class> klass) { |
| return GetAnnotationArrayValue<mirror::Class>(klass, |
| "Ldalvik/annotation/MemberClasses;", |
| "value"); |
| } |
| |
| ObjPtr<mirror::Class> GetDeclaringClass(Handle<mirror::Class> klass) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/EnclosingClass;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| ObjPtr<mirror::Object> obj = GetAnnotationValue(data, |
| annotation_item, |
| "value", |
| ScopedNullHandle<mirror::Class>(), |
| DexFile::kDexAnnotationType); |
| if (obj == nullptr) { |
| return nullptr; |
| } |
| if (!obj->IsClass()) { |
| // TypeNotPresentException, throw the NoClassDefFoundError. |
| Thread::Current()->SetException(obj->AsThrowable()->GetCause()); |
| return nullptr; |
| } |
| return obj->AsClass(); |
| } |
| |
| ObjPtr<mirror::Class> GetEnclosingClass(Handle<mirror::Class> klass) { |
| ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(klass); |
| if (declaring_class != nullptr || Thread::Current()->IsExceptionPending()) { |
| return declaring_class; |
| } |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(data.GetDexFile(), |
| annotation_set, |
| "Ldalvik/annotation/EnclosingMethod;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| const uint8_t* annotation = |
| SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "value"); |
| if (annotation == nullptr) { |
| return nullptr; |
| } |
| DexFile::AnnotationValue annotation_value; |
| if (!ProcessAnnotationValue<false>(data, |
| &annotation, |
| &annotation_value, |
| ScopedNullHandle<mirror::Class>(), |
| DexFile::kAllRaw)) { |
| return nullptr; |
| } |
| if (annotation_value.type_ != DexFile::kDexAnnotationMethod) { |
| return nullptr; |
| } |
| StackHandleScope<2> hs(Thread::Current()); |
| ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType( |
| annotation_value.value_.GetI(), |
| hs.NewHandle(data.GetDexCache()), |
| hs.NewHandle(data.GetClassLoader())); |
| if (method == nullptr) { |
| return nullptr; |
| } |
| return method->GetDeclaringClass(); |
| } |
| |
| ObjPtr<mirror::Object> GetEnclosingMethod(Handle<mirror::Class> klass) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(data.GetDexFile(), |
| annotation_set, |
| "Ldalvik/annotation/EnclosingMethod;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| return GetAnnotationValue(data, annotation_item, "value", ScopedNullHandle<mirror::Class>(), |
| DexFile::kDexAnnotationMethod); |
| } |
| |
| bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* name) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| const AnnotationItem* annotation_item = SearchAnnotationSet( |
| data.GetDexFile(), |
| annotation_set, |
| "Ldalvik/annotation/InnerClass;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return false; |
| } |
| const uint8_t* annotation = |
| SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "name"); |
| if (annotation == nullptr) { |
| return false; |
| } |
| DexFile::AnnotationValue annotation_value; |
| if (!ProcessAnnotationValue<false>(data, |
| &annotation, |
| &annotation_value, |
| ScopedNullHandle<mirror::Class>(), |
| DexFile::kAllObjects)) { |
| return false; |
| } |
| if (annotation_value.type_ != DexFile::kDexAnnotationNull && |
| annotation_value.type_ != DexFile::kDexAnnotationString) { |
| return false; |
| } |
| *name = down_cast<mirror::String*>(annotation_value.value_.GetL()); |
| return true; |
| } |
| |
| bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/InnerClass;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return false; |
| } |
| const uint8_t* annotation = |
| SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "accessFlags"); |
| if (annotation == nullptr) { |
| return false; |
| } |
| DexFile::AnnotationValue annotation_value; |
| if (!ProcessAnnotationValue<false>(data, |
| &annotation, |
| &annotation_value, |
| ScopedNullHandle<mirror::Class>(), |
| DexFile::kAllRaw)) { |
| return false; |
| } |
| if (annotation_value.type_ != DexFile::kDexAnnotationInt) { |
| return false; |
| } |
| *flags = annotation_value.value_.GetI(); |
| return true; |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( |
| Handle<mirror::Class> klass) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| return GetSignatureValue(data, annotation_set); |
| } |
| |
| const char* GetSourceDebugExtension(Handle<mirror::Class> klass) { |
| // Before instantiating ClassData, check that klass has a DexCache |
| // assigned. The ClassData constructor indirectly dereferences it |
| // when calling klass->GetDexFile(). |
| if (klass->GetDexCache() == nullptr) { |
| DCHECK(klass->IsPrimitive() || klass->IsArrayClass()); |
| return nullptr; |
| } |
| |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| |
| const AnnotationItem* annotation_item = SearchAnnotationSet( |
| data.GetDexFile(), |
| annotation_set, |
| "Ldalvik/annotation/SourceDebugExtension;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| |
| const uint8_t* annotation = |
| SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "value"); |
| if (annotation == nullptr) { |
| return nullptr; |
| } |
| DexFile::AnnotationValue annotation_value; |
| if (!ProcessAnnotationValue<false>(data, |
| &annotation, |
| &annotation_value, |
| ScopedNullHandle<mirror::Class>(), |
| DexFile::kAllRaw)) { |
| return nullptr; |
| } |
| if (annotation_value.type_ != DexFile::kDexAnnotationString) { |
| return nullptr; |
| } |
| dex::StringIndex index(static_cast<uint32_t>(annotation_value.value_.GetI())); |
| return data.GetDexFile().StringDataByIdx(index); |
| } |
| |
| ObjPtr<mirror::Class> GetNestHost(Handle<mirror::Class> klass) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| const AnnotationItem* annotation_item = |
| SearchAnnotationSet(data.GetDexFile(), annotation_set, "Ldalvik/annotation/NestHost;", |
| DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| ObjPtr<mirror::Object> obj = GetAnnotationValue(data, |
| annotation_item, |
| "host", |
| ScopedNullHandle<mirror::Class>(), |
| DexFile::kDexAnnotationType); |
| if (obj == nullptr) { |
| return nullptr; |
| } |
| if (!obj->IsClass()) { |
| // TypeNotPresentException, throw the NoClassDefFoundError. |
| Thread::Current()->SetException(obj->AsThrowable()->GetCause()); |
| return nullptr; |
| } |
| return obj->AsClass(); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Class>> GetNestMembers(Handle<mirror::Class> klass) { |
| return GetAnnotationArrayValue<mirror::Class>(klass, |
| "Ldalvik/annotation/NestMembers;", |
| "classes"); |
| } |
| |
| ObjPtr<mirror::ObjectArray<mirror::Class>> GetPermittedSubclasses(Handle<mirror::Class> klass) { |
| return GetAnnotationArrayValue<mirror::Class>(klass, |
| "Ldalvik/annotation/PermittedSubclasses;", |
| "value"); |
| } |
| |
| ObjPtr<mirror::Object> getRecordAnnotationElement(Handle<mirror::Class> klass, |
| Handle<mirror::Class> array_class, |
| const char* element_name) { |
| ClassData data(klass); |
| const DexFile& dex_file = klass->GetDexFile(); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return nullptr; |
| } |
| const AnnotationItem* annotation_item = SearchAnnotationSet( |
| dex_file, annotation_set, "Ldalvik/annotation/Record;", DexFile::kDexVisibilitySystem); |
| if (annotation_item == nullptr) { |
| return nullptr; |
| } |
| const uint8_t* annotation = |
| SearchEncodedAnnotation(dex_file, annotation_item->annotation_, element_name); |
| if (annotation == nullptr) { |
| return nullptr; |
| } |
| DexFile::AnnotationValue annotation_value; |
| bool result = Runtime::Current()->IsActiveTransaction() |
| ? ProcessAnnotationValue<true>(data, |
| &annotation, |
| &annotation_value, |
| array_class, |
| DexFile::kPrimitivesOrObjects) |
| : ProcessAnnotationValue<false>(data, |
| &annotation, |
| &annotation_value, |
| array_class, |
| DexFile::kPrimitivesOrObjects); |
| if (!result) { |
| return nullptr; |
| } |
| return annotation_value.value_.GetL(); |
| } |
| |
| bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return false; |
| } |
| const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet( |
| data, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class); |
| return annotation_item != nullptr; |
| } |
| |
| int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t rel_pc) { |
| // For native method, lineno should be -2 to indicate it is native. Note that |
| // "line number == -2" is how libcore tells from StackTraceElement. |
| if (!method->HasCodeItem()) { |
| return -2; |
| } |
| |
| CodeItemDebugInfoAccessor accessor(method->DexInstructionDebugInfo()); |
| DCHECK(accessor.HasCodeItem()) << method->PrettyMethod() << " " << dex_file->GetLocation(); |
| |
| // A method with no line number info should return -1 |
| uint32_t line_num = -1; |
| accessor.GetLineNumForPc(rel_pc, &line_num); |
| return line_num; |
| } |
| |
| template<bool kTransactionActive> |
| void RuntimeEncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) const { |
| DCHECK(dex_cache_ != nullptr); |
| switch (type_) { |
| case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z); |
| break; |
| case kByte: field->SetByte<kTransactionActive>(field->GetDeclaringClass(), jval_.b); break; |
| case kShort: field->SetShort<kTransactionActive>(field->GetDeclaringClass(), jval_.s); break; |
| case kChar: field->SetChar<kTransactionActive>(field->GetDeclaringClass(), jval_.c); break; |
| case kInt: field->SetInt<kTransactionActive>(field->GetDeclaringClass(), jval_.i); break; |
| case kLong: field->SetLong<kTransactionActive>(field->GetDeclaringClass(), jval_.j); break; |
| case kFloat: field->SetFloat<kTransactionActive>(field->GetDeclaringClass(), jval_.f); break; |
| case kDouble: field->SetDouble<kTransactionActive>(field->GetDeclaringClass(), jval_.d); break; |
| case kNull: field->SetObject<kTransactionActive>(field->GetDeclaringClass(), nullptr); break; |
| case kString: { |
| ObjPtr<mirror::String> resolved = linker_->ResolveString(dex::StringIndex(jval_.i), |
| dex_cache_); |
| field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved); |
| break; |
| } |
| case kType: { |
| ObjPtr<mirror::Class> resolved = linker_->ResolveType(dex::TypeIndex(jval_.i), |
| dex_cache_, |
| class_loader_); |
| field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved); |
| break; |
| } |
| default: UNIMPLEMENTED(FATAL) << ": type " << type_; |
| } |
| } |
| template |
| void RuntimeEncodedStaticFieldValueIterator::ReadValueToField<true>(ArtField* field) const; |
| template |
| void RuntimeEncodedStaticFieldValueIterator::ReadValueToField<false>(ArtField* field) const; |
| |
| inline static VisitorStatus VisitElement(AnnotationVisitor* visitor, |
| const char* element_name, |
| uint8_t depth, |
| uint32_t element_index, |
| const DexFile::AnnotationValue& annotation_value) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| if (depth == 0) { |
| return visitor->VisitAnnotationElement( |
| element_name, annotation_value.type_, annotation_value.value_); |
| } else { |
| return visitor->VisitArrayElement( |
| depth - 1, element_index, annotation_value.type_, annotation_value.value_); |
| } |
| } |
| |
| static VisitorStatus VisitEncodedValue(const ClassData& klass, |
| const DexFile& dex_file, |
| const uint8_t** annotation_ptr, |
| AnnotationVisitor* visitor, |
| const char* element_name, |
| uint8_t depth, |
| uint32_t element_index) |
| REQUIRES_SHARED(Locks::mutator_lock_) { |
| DexFile::AnnotationValue annotation_value; |
| // kTransactionActive is safe because the result_style is kAllRaw. |
| bool is_consumed = ProcessAnnotationValue<false>(klass, |
| annotation_ptr, |
| &annotation_value, |
| ScopedNullHandle<mirror::Class>(), |
| DexFile::kAllRaw); |
| |
| VisitorStatus status = |
| VisitElement(visitor, element_name, depth, element_index, annotation_value); |
| switch (annotation_value.type_) { |
| case DexFile::kDexAnnotationArray: { |
| DCHECK(!is_consumed) << " unexpected consumption of array-typed element '" << element_name |
| << "' annotating the class " << klass.GetRealClass()->PrettyClass(); |
| SkipEncodedValueHeaderByte(annotation_ptr); |
| uint32_t array_size = DecodeUnsignedLeb128(annotation_ptr); |
| uint8_t next_depth = depth + 1; |
| VisitorStatus element_status = (status == VisitorStatus::kVisitInner) ? |
| VisitorStatus::kVisitNext : |
| VisitorStatus::kVisitBreak; |
| uint32_t i = 0; |
| for (; i < array_size && element_status != VisitorStatus::kVisitBreak; ++i) { |
| element_status = VisitEncodedValue( |
| klass, dex_file, annotation_ptr, visitor, element_name, next_depth, i); |
| } |
| for (; i < array_size; ++i) { |
| SkipAnnotationValue(dex_file, annotation_ptr); |
| } |
| break; |
| } |
| case DexFile::kDexAnnotationAnnotation: { |
| DCHECK(!is_consumed) << " unexpected consumption of annotation-typed element '" |
| << element_name << "' annotating the class " |
| << klass.GetRealClass()->PrettyClass(); |
| SkipEncodedValueHeaderByte(annotation_ptr); |
| DecodeUnsignedLeb128(annotation_ptr); // unused type_index |
| uint32_t size = DecodeUnsignedLeb128(annotation_ptr); |
| for (; size != 0u; --size) { |
| DecodeUnsignedLeb128(annotation_ptr); // unused element_name_index |
| SkipAnnotationValue(dex_file, annotation_ptr); |
| } |
| break; |
| } |
| default: { |
| // kDexAnnotationArray and kDexAnnotationAnnotation are the only 2 known value_types causing |
| // ProcessAnnotationValue return false. For other value_types, we shouldn't need to iterate |
| // over annotation_ptr and skip the value here. |
| DCHECK(is_consumed) << StringPrintf( |
| "consumed annotation element type 0x%02x of %s for the class %s", |
| annotation_value.type_, |
| element_name, |
| klass.GetRealClass()->PrettyClass().c_str()); |
| if (UNLIKELY(!is_consumed)) { |
| SkipAnnotationValue(dex_file, annotation_ptr); |
| } |
| break; |
| } |
| } |
| |
| return status; |
| } |
| |
| void VisitClassAnnotations(Handle<mirror::Class> klass, AnnotationVisitor* visitor) { |
| ClassData data(klass); |
| const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); |
| if (annotation_set == nullptr) { |
| return; |
| } |
| |
| const DexFile& dex_file = data.GetDexFile(); |
| for (uint32_t i = 0; i < annotation_set->size_; ++i) { |
| const AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i); |
| uint8_t visibility = annotation_item->visibility_; |
| const uint8_t* annotation = annotation_item->annotation_; |
| uint32_t type_index = DecodeUnsignedLeb128(&annotation); |
| const char* annotation_descriptor = dex_file.StringByTypeIdx(dex::TypeIndex(type_index)); |
| VisitorStatus status = visitor->VisitAnnotation(annotation_descriptor, visibility); |
| switch (status) { |
| case VisitorStatus::kVisitBreak: |
| return; |
| case VisitorStatus::kVisitNext: |
| continue; |
| case VisitorStatus::kVisitInner: |
| // Visit the annotation elements |
| break; |
| } |
| |
| uint32_t size = DecodeUnsignedLeb128(&annotation); |
| while (size != 0) { |
| uint32_t element_name_index = DecodeUnsignedLeb128(&annotation); |
| const char* element_name = |
| dex_file.GetStringData(dex_file.GetStringId(dex::StringIndex(element_name_index))); |
| |
| status = VisitEncodedValue( |
| data, dex_file, &annotation, visitor, element_name, /*depth=*/0, /*ignored*/ 0); |
| if (status == VisitorStatus::kVisitBreak) { |
| break; |
| } |
| size--; |
| } |
| } |
| } |
| |
| } // namespace annotations |
| |
| } // namespace art |