/* * 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/stringprintf.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/sdk_version.h" #include "class_linker-inl.h" #include "class_root.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_file.h" #include "obj_ptr-inl.h" #include "quicken_info.h" #include "reflection.h" #include "thread.h" #include "well_known_classes.h" namespace art { 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; } 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(); ScopedObjectAccessUnchecked soa(self); 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_class = soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember); ObjPtr<mirror::Class> annotation_member_array_class = class_linker->FindArrayClass(self, annotation_member_class); 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); } JValue result; ArtMethod* create_annotation_method = jni::DecodeArtMethod(WellKnownClasses::libcore_reflect_AnnotationFactory_createAnnotation); uint32_t args[2] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(annotation_class.Get())), static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h_element_array.Get())) }; create_annotation_method->Invoke(self, args, sizeof(args), &result, "LLL"); if (self->IsExceptionPending()) { LOG(INFO) << "Exception in AnnotationFactory.createAnnotation"; return nullptr; } return result.GetL(); } 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()) { if (pointer_size == PointerSize::k64) { element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k64, kTransactionActive>(self, method); } else { element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k32, kTransactionActive>(self, method); } } else { if (pointer_size == PointerSize::k64) { element_object = mirror::Method::CreateFromArtMethod<PointerSize::k64, kTransactionActive>(self, method); } else { element_object = mirror::Method::CreateFromArtMethod<PointerSize::k32, kTransactionActive>(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; PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); if (pointer_size == PointerSize::k64) { element_object = mirror::Field::CreateFromArtField<PointerSize::k64, kTransactionActive>(self, field, true); } else { element_object = mirror::Field::CreateFromArtField<PointerSize::k32, kTransactionActive>(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<true>( 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)); Handle<mirror::String> string_name( hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, name))); PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); ArtMethod* annotation_method = annotation_class->FindDeclaredVirtualMethodByName(name, pointer_size); if (annotation_method == nullptr) { return nullptr; } Handle<mirror::Class> method_return(hs.NewHandle(annotation_method->ResolveReturnType())); DexFile::AnnotationValue annotation_value; if (!ProcessAnnotationValue<false>(klass, annotation, &annotation_value, method_return, DexFile::kAllObjects)) { return nullptr; } Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL())); ObjPtr<mirror::Class> annotation_member_class = WellKnownClasses::ToClass(WellKnownClasses::libcore_reflect_AnnotationMember); Handle<mirror::Object> new_member(hs.NewHandle(annotation_member_class->AllocObject(self))); ObjPtr<mirror::Method> method_obj_ptr; DCHECK(!Runtime::Current()->IsActiveTransaction()); if (pointer_size == PointerSize::k64) { method_obj_ptr = mirror::Method::CreateFromArtMethod<PointerSize::k64, false>( self, annotation_method); } else { method_obj_ptr = mirror::Method::CreateFromArtMethod<PointerSize::k32, false>( self, annotation_method); } Handle<mirror::Method> method_object(hs.NewHandle(method_obj_ptr)); if (new_member == nullptr || string_name == nullptr || method_object == nullptr || method_return == nullptr) { LOG(ERROR) << StringPrintf("Failed creating annotation element (m=%p n=%p a=%p r=%p", new_member.Get(), string_name.Get(), method_object.Get(), method_return.Get()); return nullptr; } JValue result; ArtMethod* annotation_member_init = jni::DecodeArtMethod(WellKnownClasses::libcore_reflect_AnnotationMember_init); uint32_t args[5] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(new_member.Get())), static_cast<uint32_t>(reinterpret_cast<uintptr_t>(string_name.Get())), static_cast<uint32_t>(reinterpret_cast<uintptr_t>(value_object.Get())), static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_return.Get())), static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_object.Get())) }; annotation_member_init->Invoke(self, args, sizeof(args), &result, "VLLLL"); if (self->IsExceptionPending()) { LOG(INFO) << "Exception in AnnotationMember.<init>"; 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(); } 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(); ScopedObjectAccessUnchecked soa(self); StackHandleScope<2> hs(self); Handle<mirror::Class> annotation_array_class(hs.NewHandle( soa.Decode<mirror::Class>(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(); ScopedObjectAccessUnchecked soa(self); StackHandleScope<1> hs(self); ObjPtr<mirror::Class> annotation_array_class = soa.Decode<mirror::Class>(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 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; } ArrayRef<const uint8_t> quicken_data; const OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file != nullptr) { quicken_data = oat_dex_file->GetQuickenedInfoOf(dex_file, method_index); } const QuickenInfoTable quicken_info(quicken_data); uint32_t quicken_index = 0; for (DexInstructionIterator iter = accessor.begin(); iter != accessor.end(); ++iter) { switch (iter->Opcode()) { case Instruction::IGET: case Instruction::IGET_QUICK: case Instruction::IGET_WIDE: case Instruction::IGET_WIDE_QUICK: case Instruction::IGET_OBJECT: case Instruction::IGET_OBJECT_QUICK: case Instruction::IGET_BOOLEAN: case Instruction::IGET_BOOLEAN_QUICK: case Instruction::IGET_BYTE: case Instruction::IGET_BYTE_QUICK: case Instruction::IGET_CHAR: case Instruction::IGET_CHAR_QUICK: case Instruction::IGET_SHORT: case Instruction::IGET_SHORT_QUICK: case Instruction::IPUT: case Instruction::IPUT_QUICK: case Instruction::IPUT_WIDE: case Instruction::IPUT_WIDE_QUICK: case Instruction::IPUT_OBJECT: case Instruction::IPUT_OBJECT_QUICK: case Instruction::IPUT_BOOLEAN: case Instruction::IPUT_BOOLEAN_QUICK: case Instruction::IPUT_BYTE: case Instruction::IPUT_BYTE_QUICK: case Instruction::IPUT_CHAR: case Instruction::IPUT_CHAR_QUICK: case Instruction::IPUT_SHORT: case Instruction::IPUT_SHORT_QUICK: { uint32_t field_index; if (iter->IsQuickened()) { field_index = quicken_info.GetData(quicken_index); } else { 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; case Instruction::INVOKE_VIRTUAL_QUICK: case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: { uint32_t called_method_index = quicken_info.GetData(quicken_index); 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; } if (QuickenInfoTable::NeedsIndexForInstruction(&iter.Inst())) { ++quicken_index; } } 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) { 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/MemberClasses;", 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(data, annotation_item, "value", class_array_class, DexFile::kDexAnnotationArray); if (obj == nullptr) { return nullptr; } return obj->AsObjectArray<mirror::Class>(); } 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; } return obj->AsClass(); } ObjPtr<mirror::Class> GetEnclosingClass(Handle<mirror::Class> klass) { ObjPtr<mirror::Class> declaring_class = GetDeclaringClass(klass); if (declaring_class != nullptr) { 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); } 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->GetCodeItemOffset() == 0) { 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; } // namespace annotations } // namespace art