diff options
author | 2019-08-13 10:50:38 -0700 | |
---|---|---|
committer | 2019-09-17 23:52:12 +0000 | |
commit | c971eafeff43e4e26959a6e86b62ab0a8f1a6e1c (patch) | |
tree | f8647487e7465712fd73118ceb89e13167a12648 /runtime/class_linker.h | |
parent | 1ba7e8c10af4e270864a417044244d63db53ccf5 (diff) |
Basic structural redefinition support
This adds basic support for adding methods and fields to already
loaded classes using redefinition. This 'structural class
redefinition' is currently limited to classes without any virtual
methods or instance fields. One cannot currently structurally redefine
multiple classes at once nor will structural redefinition trigger the
standard redefinition events.
After structural redefinition all references to the old class, and its
fields and methods are atomically updated. Any memory associated with
the static fields of the old class is zeroed. Offsets for field access
might change. If there are any active stack frames for methods from
the redefined class the original (obsolete method) code will continue
to execute. The identity hash code of the redefined class will not
change. Any locks being held, waited or blocked on by the old class
will be transferred to the new class.
To use this feature the process must be debuggable and running with
-Xopaque-jni-ids:true.
For device testing use a wrap.sh that adds the following flags:
'-Xopaque-jni-ids:true -Xcompiler-option --debuggable -XjdwpProvider:adbconnection'
Structural redefinition only available using the
"com.android.art.UNSAFE.class.structurally_redefine_class_direct"
extension. This will not trigger the normal class-redefinition events.
Only one class may be redefined at a time.
NB There are still some holes in this potentially allowing obsolete
methods/fields to be visible. Most notably during jni-id, MethodHandle
and VarHandle creation as well as potentially other places in the
runtime. These holes will be closed by later CLs. Until then the
extension to access structural class redefinition will remain tagged
as UNSAFE.
Test: ./test.py --host --all-compiler
Bug: 134162467
Change-Id: I825d3a4bdb9594c0147223ae69f433ce9bbfc307
Diffstat (limited to 'runtime/class_linker.h')
-rw-r--r-- | runtime/class_linker.h | 62 |
1 files changed, 33 insertions, 29 deletions
diff --git a/runtime/class_linker.h b/runtime/class_linker.h index dd9f56fd90..792f7b798a 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -20,6 +20,7 @@ #include <list> #include <set> #include <string> +#include <type_traits> #include <unordered_map> #include <unordered_set> #include <utility> @@ -479,6 +480,38 @@ class ClassLinker { LinearAlloc* allocator, size_t length); + // Convenience AllocClass() overload that uses mirror::Class::InitializeClassVisitor + // for the class initialization and uses the `java_lang_Class` from class roots + // instead of an explicit argument. + ObjPtr<mirror::Class> AllocClass(Thread* self, uint32_t class_size) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!Roles::uninterruptible_); + + // Setup the classloader, class def index, type idx so that we can insert this class in the class + // table. + void SetupClass(const DexFile& dex_file, + const dex::ClassDef& dex_class_def, + Handle<mirror::Class> klass, + ObjPtr<mirror::ClassLoader> class_loader) + REQUIRES_SHARED(Locks::mutator_lock_); + + void LoadClass(Thread* self, + const DexFile& dex_file, + const dex::ClassDef& dex_class_def, + Handle<mirror::Class> klass) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Link the class and place it into the class-table using the given descriptor. NB if the + // descriptor is null the class will not be placed in any class-table. This is useful implementing + // obsolete classes and should not be used otherwise. + bool LinkClass(Thread* self, + const char* descriptor, + Handle<mirror::Class> klass, + Handle<mirror::ObjectArray<mirror::Class>> interfaces, + MutableHandle<mirror::Class>* h_new_class_out) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!Locks::classlinker_classes_lock_); + ObjPtr<mirror::PointerArray> AllocPointerArray(Thread* self, size_t length) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); @@ -829,13 +862,6 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); - // Convenience AllocClass() overload that uses mirror::Class::InitializeClassVisitor - // for the class initialization and uses the `java_lang_Class` from class roots - // instead of an explicit argument. - ObjPtr<mirror::Class> AllocClass(Thread* self, uint32_t class_size) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Roles::uninterruptible_); - // Allocate a primitive array class and store it in appropriate class root. void AllocPrimitiveArrayClass(Thread* self, ClassRoot primitive_root, @@ -889,20 +915,6 @@ class ClassLinker { uint32_t SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, const dex::ClassDef& dex_class_def); - // Setup the classloader, class def index, type idx so that we can insert this class in the class - // table. - void SetupClass(const DexFile& dex_file, - const dex::ClassDef& dex_class_def, - Handle<mirror::Class> klass, - ObjPtr<mirror::ClassLoader> class_loader) - REQUIRES_SHARED(Locks::mutator_lock_); - - void LoadClass(Thread* self, - const DexFile& dex_file, - const dex::ClassDef& dex_class_def, - Handle<mirror::Class> klass) - REQUIRES_SHARED(Locks::mutator_lock_); - void LoadField(const ClassAccessor::Field& field, Handle<mirror::Class> klass, ArtField* dst) REQUIRES_SHARED(Locks::mutator_lock_); @@ -1049,14 +1061,6 @@ class ClassLinker { ObjPtr<mirror::Class> klass2) REQUIRES_SHARED(Locks::mutator_lock_); - bool LinkClass(Thread* self, - const char* descriptor, - Handle<mirror::Class> klass, - Handle<mirror::ObjectArray<mirror::Class>> interfaces, - MutableHandle<mirror::Class>* h_new_class_out) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::classlinker_classes_lock_); - bool LinkSuperClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); |