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/macros.h"
23#include "base/mutex.h"
24#include "base/value_object.h"
25#include "thread_state.h"
26
27namespace art {
28
29class JavaVMExt;
30struct JNIEnvExt;
31template<class MirrorType> class ObjPtr;
32class Thread;
33
34namespace mirror {
35class 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.
42class 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
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*.
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.
69class ScopedObjectAccessAlreadyRunnable : public ValueObject {
70 public:
71  Thread* Self() const {
72    return self_;
73  }
74
75  JNIEnvExt* Env() const {
76    return env_;
77  }
78
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.
114  explicit ScopedObjectAccessAlreadyRunnable(JavaVM* vm)
115      : self_(nullptr), env_(nullptr), vm_(reinterpret_cast<JavaVMExt*>(vm)) {}
116
117  // Here purely to force inlining.
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.
145class 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
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_.
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.
169class 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.
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.
194class 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