1782 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			1782 lines
		
	
	
		
			70 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * 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-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_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()) {
 | |
|           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));
 | |
|   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 = (pointer_size == PointerSize::k64)
 | |
|       ? mirror::Method::CreateFromArtMethod<PointerSize::k64>(self, annotation_method)
 | |
|       : mirror::Method::CreateFromArtMethod<PointerSize::k32>(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 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 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) {
 | |
|   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;
 | |
|   }
 | |
|   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);
 | |
| }
 | |
| 
 | |
| 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;
 | |
| 
 | |
| }  // namespace annotations
 | |
| 
 | |
| }  // namespace art
 |