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