• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 SRC_ANDROID_SDK_NATIVEHELPER_SCOPED_PRIMITIVE_ARRAY_H_
18 #define SRC_ANDROID_SDK_NATIVEHELPER_SCOPED_PRIMITIVE_ARRAY_H_
19 
20 // Copied from
21 // https://cs.android.com/android/platform/superproject/main/+/main:libnativehelper/header_only_include/nativehelper/scoped_primitive_array.h;drc=4be05051ef76b2c24d8385732a892401eb45d911
22 
23 #include <stddef.h>
24 
25 #include <jni.h>
26 
27 #include "src/android_sdk/nativehelper/nativehelper_utils.h"
28 
29 #ifdef POINTER_TYPE
30 #error POINTER_TYPE is defined.
31 #else
32 #define POINTER_TYPE(T) T* /* NOLINT */
33 #endif
34 
35 #ifdef REFERENCE_TYPE
36 #error REFERENCE_TYPE is defined.
37 #else
38 #define REFERENCE_TYPE(T) T& /* NOLINT */
39 #endif
40 
41 // ScopedBooleanArrayRO, ScopedByteArrayRO, ScopedCharArrayRO,
42 // ScopedDoubleArrayRO, ScopedFloatArrayRO, ScopedIntArrayRO, ScopedLongArrayRO,
43 // and ScopedShortArrayRO provide convenient read-only access to Java arrays
44 // from JNI code. This is cheaper than read-write access and should be used by
45 // default.
46 #define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(PRIMITIVE_TYPE, NAME)           \
47   class Scoped##NAME##ArrayRO {                                               \
48    public:                                                                    \
49     explicit Scoped##NAME##ArrayRO(JNIEnv* env)                               \
50         : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr), mSize(0) {}     \
51     Scoped##NAME##ArrayRO(JNIEnv* env, PRIMITIVE_TYPE##Array javaArray)       \
52         : mEnv(env) {                                                         \
53       if (javaArray == nullptr) {                                             \
54         mJavaArray = nullptr;                                                 \
55         mSize = 0;                                                            \
56         mRawArray = nullptr;                                                  \
57         jniThrowNullPointerException(mEnv);                                   \
58       } else {                                                                \
59         reset(javaArray);                                                     \
60       }                                                                       \
61     }                                                                         \
62     ~Scoped##NAME##ArrayRO() {                                                \
63       if (mRawArray != nullptr && mRawArray != mBuffer) {                     \
64         mEnv->Release##NAME##ArrayElements(mJavaArray, mRawArray, JNI_ABORT); \
65       }                                                                       \
66     }                                                                         \
67     void reset(PRIMITIVE_TYPE##Array javaArray) {                             \
68       mJavaArray = javaArray;                                                 \
69       mSize = mEnv->GetArrayLength(mJavaArray);                               \
70       if (mSize <= buffer_size) {                                             \
71         mEnv->Get##NAME##ArrayRegion(mJavaArray, 0, mSize, mBuffer);          \
72         mRawArray = mBuffer;                                                  \
73       } else {                                                                \
74         mRawArray = mEnv->Get##NAME##ArrayElements(mJavaArray, nullptr);      \
75       }                                                                       \
76     }                                                                         \
77     const PRIMITIVE_TYPE* get() const {                                       \
78       return mRawArray;                                                       \
79     }                                                                         \
80     PRIMITIVE_TYPE##Array getJavaArray() const {                              \
81       return mJavaArray;                                                      \
82     }                                                                         \
83     const PRIMITIVE_TYPE& operator[](size_t n) const {                        \
84       return mRawArray[n];                                                    \
85     }                                                                         \
86     size_t size() const {                                                     \
87       return mSize;                                                           \
88     }                                                                         \
89                                                                               \
90    private:                                                                   \
91     static const jsize buffer_size = 1024;                                    \
92     JNIEnv* const mEnv;                                                       \
93     PRIMITIVE_TYPE##Array mJavaArray;                                         \
94     POINTER_TYPE(PRIMITIVE_TYPE) mRawArray;                                   \
95     jsize mSize;                                                              \
96     PRIMITIVE_TYPE mBuffer[buffer_size];                                      \
97     DISALLOW_COPY_AND_ASSIGN(Scoped##NAME##ArrayRO);                          \
98   }
99 
100 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jboolean, Boolean);
101 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jbyte, Byte);
102 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jchar, Char);
103 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jdouble, Double);
104 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jfloat, Float);
105 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jint, Int);
106 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jlong, Long);
107 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO(jshort, Short);
108 
109 #undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RO
110 
111 // ScopedBooleanArrayRW, ScopedByteArrayRW, ScopedCharArrayRW,
112 // ScopedDoubleArrayRW, ScopedFloatArrayRW, ScopedIntArrayRW, ScopedLongArrayRW,
113 // and ScopedShortArrayRW provide convenient read-write access to Java arrays
114 // from JNI code. These are more expensive, since they entail a copy back onto
115 // the Java heap, and should only be used when necessary.
116 #define INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(PRIMITIVE_TYPE, NAME)      \
117   class Scoped##NAME##ArrayRW {                                          \
118    public:                                                               \
119     explicit Scoped##NAME##ArrayRW(JNIEnv* env)                          \
120         : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr) {}          \
121     Scoped##NAME##ArrayRW(JNIEnv* env, PRIMITIVE_TYPE##Array javaArray)  \
122         : mEnv(env), mJavaArray(javaArray), mRawArray(nullptr) {         \
123       if (mJavaArray == nullptr) {                                       \
124         jniThrowNullPointerException(mEnv);                              \
125       } else {                                                           \
126         mRawArray = mEnv->Get##NAME##ArrayElements(mJavaArray, nullptr); \
127       }                                                                  \
128     }                                                                    \
129     ~Scoped##NAME##ArrayRW() {                                           \
130       if (mRawArray) {                                                   \
131         mEnv->Release##NAME##ArrayElements(mJavaArray, mRawArray, 0);    \
132       }                                                                  \
133     }                                                                    \
134     void reset(PRIMITIVE_TYPE##Array javaArray) {                        \
135       mJavaArray = javaArray;                                            \
136       mRawArray = mEnv->Get##NAME##ArrayElements(mJavaArray, nullptr);   \
137     }                                                                    \
138     const PRIMITIVE_TYPE* get() const {                                  \
139       return mRawArray;                                                  \
140     }                                                                    \
141     PRIMITIVE_TYPE##Array getJavaArray() const {                         \
142       return mJavaArray;                                                 \
143     }                                                                    \
144     const PRIMITIVE_TYPE& operator[](size_t n) const {                   \
145       return mRawArray[n];                                               \
146     }                                                                    \
147     POINTER_TYPE(PRIMITIVE_TYPE) get() {                                 \
148       return mRawArray;                                                  \
149     }                                                                    \
150     REFERENCE_TYPE(PRIMITIVE_TYPE) operator[](size_t n) {                \
151       return mRawArray[n];                                               \
152     }                                                                    \
153     size_t size() const {                                                \
154       return mEnv->GetArrayLength(mJavaArray);                           \
155     }                                                                    \
156                                                                          \
157    private:                                                              \
158     JNIEnv* const mEnv;                                                  \
159     PRIMITIVE_TYPE##Array mJavaArray;                                    \
160     POINTER_TYPE(PRIMITIVE_TYPE) mRawArray;                              \
161     DISALLOW_COPY_AND_ASSIGN(Scoped##NAME##ArrayRW);                     \
162   }
163 
164 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jboolean, Boolean);
165 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jbyte, Byte);
166 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jchar, Char);
167 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jdouble, Double);
168 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jfloat, Float);
169 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jint, Int);
170 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jlong, Long);
171 INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW(jshort, Short);
172 
173 #undef INSTANTIATE_SCOPED_PRIMITIVE_ARRAY_RW
174 
175 template <typename PrimitiveType, typename ArrayType, jint ReleaseMode>
176 class ScopedCriticalArray {
177  public:
ScopedCriticalArray(JNIEnv * env)178   explicit ScopedCriticalArray(JNIEnv* env)
179       : mEnv(env), mJavaArray(nullptr), mRawArray(nullptr) {}
ScopedCriticalArray(JNIEnv * env,ArrayType javaArray)180   ScopedCriticalArray(JNIEnv* env, ArrayType javaArray)
181       : mEnv(env), mJavaArray(javaArray), mRawArray(nullptr) {
182     if (mJavaArray == nullptr) {
183       jniThrowNullPointerException(mEnv);
184     } else {
185       mRawArray = static_cast<PrimitiveType*>(
186           mEnv->GetPrimitiveArrayCritical(mJavaArray, nullptr));
187     }
188   }
~ScopedCriticalArray()189   ~ScopedCriticalArray() {
190     if (mRawArray) {
191       mEnv->ReleasePrimitiveArrayCritical(mJavaArray, mRawArray, ReleaseMode);
192     }
193   }
reset(ArrayType javaArray)194   void reset(ArrayType javaArray) const {
195     mJavaArray = javaArray;
196     mRawArray = static_cast<PrimitiveType*>(
197         mEnv->GetPrimitiveArrayCritical(mJavaArray, nullptr));
198   }
get()199   const PrimitiveType* get() const { return mRawArray; }
getJavaArray()200   ArrayType getJavaArray() const { return mJavaArray; }
201   const PrimitiveType& operator[](size_t n) const { return mRawArray[n]; }
get()202   PrimitiveType* get() { return mRawArray; }
203   PrimitiveType& operator[](size_t n) { return mRawArray[n]; }
size()204   size_t size() const { return mEnv->GetArrayLength(mJavaArray); }
205 
206  private:
207   JNIEnv* const mEnv;
208   mutable ArrayType mJavaArray;
209   mutable PrimitiveType* mRawArray;
210   DISALLOW_COPY_AND_ASSIGN(ScopedCriticalArray);
211 };
212 
213 // Scoped<PrimitiveType>CriticalArray(RO/RW) provide convenient critical
214 // access to Java arrays from JNI code. Usage of these should be careful, as
215 // the JVM imposes significant restrictions for critical array access.
216 // See
217 // https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#GetPrimitiveArrayCritical
218 // for more details about the JVM restrictions.
219 #define INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(PRIMITIVE_TYPE, NAME) \
220   using Scoped##NAME##CriticalArrayRO =                                   \
221       const ScopedCriticalArray<PRIMITIVE_TYPE, PRIMITIVE_TYPE##Array,    \
222                                 JNI_ABORT>;                               \
223   using Scoped##NAME##CriticalArrayRW =                                   \
224       ScopedCriticalArray<PRIMITIVE_TYPE, PRIMITIVE_TYPE##Array, 0>
225 
226 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jboolean, Boolean);
227 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jbyte, Byte);
228 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jchar, Char);
229 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jdouble, Double);
230 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jfloat, Float);
231 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jint, Int);
232 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jlong, Long);
233 INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY(jshort, Short);
234 
235 #undef INSTANTIATE_SCOPED_PRIMITIVE_CRITICAL_ARRAY
236 #undef POINTER_TYPE
237 #undef REFERENCE_TYPE
238 
239 #endif  // SRC_ANDROID_SDK_NATIVEHELPER_SCOPED_PRIMITIVE_ARRAY_H_
240