1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ 18 #define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ 19 20 #include "jni.h" 21 22 #include "base/locks.h" 23 #include "base/macros.h" 24 #include "base/value_object.h" 25 #include "thread_state.h" 26 27 namespace art { 28 29 class JavaVMExt; 30 class JNIEnvExt; 31 template<class MirrorType> class ObjPtr; 32 class Thread; 33 34 namespace mirror { 35 class Object; 36 } // namespace mirror 37 38 // Scoped change into and out of a particular state. Handles Runnable transitions that require 39 // more complicated suspension checking. The subclasses ScopedObjectAccessUnchecked and 40 // ScopedObjectAccess are used to handle the change into Runnable to Get direct access to objects, 41 // the unchecked variant doesn't aid annotalysis. 42 class ScopedThreadStateChange : public ValueObject { 43 public: 44 ALWAYS_INLINE ScopedThreadStateChange(Thread* self, ThreadState new_thread_state) 45 REQUIRES(!Locks::thread_suspend_count_lock_); 46 47 ALWAYS_INLINE ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_); 48 Self()49 ALWAYS_INLINE Thread* Self() const { 50 return self_; 51 } 52 53 protected: 54 // Constructor used by ScopedJniThreadState for an unattached thread that has access to the VM*. ScopedThreadStateChange()55 ScopedThreadStateChange() {} 56 57 Thread* const self_ = nullptr; 58 const ThreadState thread_state_ = kTerminated; 59 60 private: 61 ThreadState old_thread_state_ = kTerminated; 62 const bool expected_has_no_thread_ = true; 63 64 friend class ScopedObjectAccessUnchecked; 65 DISALLOW_COPY_AND_ASSIGN(ScopedThreadStateChange); 66 }; 67 68 // Assumes we are already runnable. 69 class ScopedObjectAccessAlreadyRunnable : public ValueObject { 70 public: Self()71 Thread* Self() const { 72 return self_; 73 } 74 Env()75 JNIEnvExt* Env() const { 76 return env_; 77 } 78 Vm()79 JavaVMExt* Vm() const { 80 return vm_; 81 } 82 83 bool ForceCopy() const; 84 85 /* 86 * Add a local reference for an object to the indirect reference table associated with the 87 * current stack frame. When the native function returns, the reference will be discarded. 88 * 89 * We need to allow the same reference to be added multiple times, and cope with nullptr. 90 * 91 * This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and 92 * it's best if we don't grab a mutex. 93 */ 94 template<typename T> 95 T AddLocalReference(ObjPtr<mirror::Object> obj) const 96 REQUIRES_SHARED(Locks::mutator_lock_); 97 98 template<typename T> 99 ObjPtr<T> Decode(jobject obj) const REQUIRES_SHARED(Locks::mutator_lock_); 100 101 ALWAYS_INLINE bool IsRunnable() const; 102 103 protected: 104 ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env) 105 REQUIRES(!Locks::thread_suspend_count_lock_); 106 107 ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(Thread* self) 108 REQUIRES(!Locks::thread_suspend_count_lock_); 109 110 // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't 111 // change into Runnable or acquire a share on the mutator_lock_. 112 // Note: The reinterpret_cast is backed by a static_assert in the cc file. Avoid a down_cast, 113 // as it prevents forward declaration of JavaVMExt. ScopedObjectAccessAlreadyRunnable(JavaVM * vm)114 explicit ScopedObjectAccessAlreadyRunnable(JavaVM* vm) 115 : self_(nullptr), env_(nullptr), vm_(reinterpret_cast<JavaVMExt*>(vm)) {} 116 117 // Here purely to force inlining. ~ScopedObjectAccessAlreadyRunnable()118 ALWAYS_INLINE ~ScopedObjectAccessAlreadyRunnable() {} 119 120 static void DCheckObjIsNotClearedJniWeakGlobal(ObjPtr<mirror::Object> obj) 121 REQUIRES_SHARED(Locks::mutator_lock_); 122 123 // Self thread, can be null. 124 Thread* const self_; 125 // The full JNIEnv. 126 JNIEnvExt* const env_; 127 // The full JavaVM. 128 JavaVMExt* const vm_; 129 }; 130 131 // Entry/exit processing for transitions from Native to Runnable (ie within JNI functions). 132 // 133 // This class performs the necessary thread state switching to and from Runnable and lets us 134 // amortize the cost of working out the current thread. Additionally it lets us check (and repair) 135 // apps that are using a JNIEnv on the wrong thread. The class also decodes and encodes Objects 136 // into jobjects via methods of this class. Performing this here enforces the Runnable thread state 137 // for use of Object, thereby inhibiting the Object being modified by GC whilst native or VM code 138 // is also manipulating the Object. 139 // 140 // The destructor transitions back to the previous thread state, typically Native. In this state 141 // GC and thread suspension may occur. 142 // 143 // For annotalysis the subclass ScopedObjectAccess (below) makes it explicit that a shared of 144 // the mutator_lock_ will be acquired on construction. 145 class ScopedObjectAccessUnchecked : public ScopedObjectAccessAlreadyRunnable { 146 public: 147 ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(JNIEnv* env) 148 REQUIRES(!Locks::thread_suspend_count_lock_); 149 150 ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(Thread* self) 151 REQUIRES(!Locks::thread_suspend_count_lock_); 152 ~ScopedObjectAccessUnchecked()153 ALWAYS_INLINE ~ScopedObjectAccessUnchecked() REQUIRES(!Locks::thread_suspend_count_lock_) {} 154 155 // Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't 156 // change into Runnable or acquire a share on the mutator_lock_. ScopedObjectAccessUnchecked(JavaVM * vm)157 explicit ScopedObjectAccessUnchecked(JavaVM* vm) ALWAYS_INLINE 158 : ScopedObjectAccessAlreadyRunnable(vm), tsc_() {} 159 160 private: 161 // The scoped thread state change makes sure that we are runnable and restores the thread state 162 // in the destructor. 163 const ScopedThreadStateChange tsc_; 164 165 DISALLOW_COPY_AND_ASSIGN(ScopedObjectAccessUnchecked); 166 }; 167 168 // Annotalysis helping variant of the above. 169 class ScopedObjectAccess : public ScopedObjectAccessUnchecked { 170 public: 171 ALWAYS_INLINE explicit ScopedObjectAccess(JNIEnv* env) 172 REQUIRES(!Locks::thread_suspend_count_lock_) 173 SHARED_LOCK_FUNCTION(Locks::mutator_lock_); 174 175 ALWAYS_INLINE explicit ScopedObjectAccess(Thread* self) 176 REQUIRES(!Locks::thread_suspend_count_lock_) 177 SHARED_LOCK_FUNCTION(Locks::mutator_lock_); 178 179 // Base class will release share of lock. Invoked after this destructor. 180 ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE; 181 182 private: 183 // TODO: remove this constructor. It is used by check JNI's ScopedCheck to make it believe that 184 // routines operating with just a VM are sound, they are not, but when you have just a VM 185 // you cannot call the unsound routines. ScopedObjectAccess(JavaVM * vm)186 explicit ScopedObjectAccess(JavaVM* vm) SHARED_LOCK_FUNCTION(Locks::mutator_lock_) 187 : ScopedObjectAccessUnchecked(vm) {} 188 189 friend class ScopedCheck; 190 DISALLOW_COPY_AND_ASSIGN(ScopedObjectAccess); 191 }; 192 193 // Annotalysis helper for going to a suspended state from runnable. 194 class ScopedThreadSuspension : public ValueObject { 195 public: 196 ALWAYS_INLINE explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state) 197 REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_) 198 UNLOCK_FUNCTION(Locks::mutator_lock_); 199 200 ALWAYS_INLINE ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_); 201 202 private: 203 Thread* const self_; 204 const ThreadState suspended_state_; 205 DISALLOW_COPY_AND_ASSIGN(ScopedThreadSuspension); 206 }; 207 208 209 } // namespace art 210 211 #endif // ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_ 212