1 /* 2 * Copyright (C) 2017 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 /** 18 * Compile-time, zero-cost checking of JNI signatures against their C++ function type. 19 * This can trigger compile-time assertions if any of the input is invalid: 20 * (a) The signature specified does not conform to the JNI function descriptor syntax. 21 * (b) The C++ function is itself an invalid JNI function (e.g. missing JNIEnv*, etc). 22 * (c) The descriptor does not match the C++ function (e.g. "()V" will not match jint(jint)). 23 * 24 * The fundamental macros are as following: 25 * MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD - Create a checked JNINativeMethod{name, sig, func}. 26 * MAKE_JNI_[FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Same as above, but infer the JNI signature. 27 * 28 * Usage examples: 29 * // path/to/package/KlassName.java 30 * class KlassName { 31 * native jobject normal(int x); 32 * @FastNative native jobject fast(int x); 33 * @CriticalNative native int critical(long ptr); 34 * } 35 * // path_to_package_KlassName.cpp 36 * jobject KlassName_normal(JNIEnv*,jobject,jint) {...} 37 * jobject KlassName_fast(JNIEnv*,jobject,jint) {...} 38 * jint KlassName_critical(jlong) {...} 39 * 40 * // Manually specify each signature: 41 * JNINativeMethod[] gMethods = { 42 * MAKE_JNI_NATIVE_METHOD("normal", "(I)Ljava/lang/Object;", KlassName_normal), 43 * MAKE_JNI_FAST_NATIVE_METHOD("fast", "(I)Ljava/lang/Object;", KlassName_fast), 44 * MAKE_JNI_CRITICAL_NATIVE_METHOD("critical", "(Z)I", KlassName_critical), 45 * }; 46 * 47 * // Automatically infer the signature: 48 * JNINativeMethod[] gMethodsAutomaticSignature = { 49 * MAKE_JNI_NATIVE_METHOD_AUTOSIG("normal", KlassName_normal), 50 * MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG("fast", KlassName_fast), 51 * MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG("critical", KlassName_critical), 52 * }; 53 * 54 * // and then call JNIEnv::RegisterNatives with gMethods as usual. 55 * 56 * For convenience the following macros are defined: 57 * [FAST_|CRITICAL_]NATIVE_METHOD - Return JNINativeMethod for class, func name, and signature. 58 * OVERLOADED_[FAST_|CRITICAL_]NATIVE_METHOD - Same as above but allows a separate func identifier. 59 * [FAST_|CRITICAL_]NATIVE_METHOD_AUTOSIG - Return JNINativeMethod, sig inferred from function. 60 * 61 * The FAST_ prefix corresponds to functions annotated with @FastNative, 62 * and the CRITICAL_ prefix corresponds to functions annotated with @CriticalNative. 63 * See dalvik.annotation.optimization.CriticalNative for more details. 64 * 65 * ======================================= 66 * Checking rules 67 * ======================================= 68 * 69 * --------------------------------------- 70 * JNI descriptor syntax for functions 71 * 72 * Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification 73 * under the subsection "Type Signatures" table entry "method type". 74 * 75 * JNI signatures not conforming to the above syntax are rejected. 76 * --------------------------------------- 77 * C++ function types 78 * 79 * A normal or @FastNative JNI function type must be of the form 80 * 81 * ReturnType (JNIEnv*, jclass|jobject, [ArgTypes...]) {} 82 * 83 * A @CriticalNative JNI function type: 84 * 85 * must be of the form... ReturnType ([ArgTypes...]){} 86 * and must not contain any Reference Types. 87 * 88 * Refer to "Chapter 3: JNI Types and Data Structures" of the JNI specification 89 * under the subsection "Primitive Types" and "Reference Types" for the list 90 * of valid argument/return types. 91 * 92 * C++ function types not conforming to the above requirements are rejected. 93 * --------------------------------------- 94 * Matching of C++ function type against JNI function descriptor. 95 * 96 * Assuming all of the above conditions are met for signature and C++ type validity, 97 * then matching between the signature and the type validity can occur: 98 * 99 * Given a signature (Args...)Ret and the 100 * C++ function type of the form "CRet fn(JNIEnv*, jclass|jobject, CArgs...)", 101 * or for @CriticalNative of the form "CRet fn(CArgs...)" 102 * 103 * The number of Args... and the number of CArgs... must be equal. 104 * 105 * If so, attempt to match every component from the signature and function type 106 * against each other: 107 * 108 * ReturnType: 109 * V <-> void 110 * ArgumentType 111 * 112 * ArgumentType: 113 * PrimitiveType 114 * ReferenceType [except for @CriticalNative] 115 * 116 * PrimitiveType: 117 * Z <-> jboolean 118 * B <-> jbyte 119 * C <-> jchar 120 * S <-> jshort 121 * I <-> jint 122 * J <-> jlong 123 * F <-> jfloat 124 * D <-> jdouble 125 * 126 * ReferenceType: 127 * Ljava/lang/String; <-> jstring 128 * Ljava/lang/Class; <-> jclass 129 * L*; <- jobject 130 * Ljava/lang/Throwable; -> jthrowable 131 * L*; <- jthrowable 132 * [ PrimitiveType <-> ${CPrimitiveType}Array 133 * [ ReferenceType <-> jobjectArray 134 * [* <- jarray 135 * 136 * Wherein <-> represents a strong match (if the left or right pattern occurs, 137 * then left must match right, otherwise matching fails). <- and -> represent 138 * weak matches (that is, other match rules can be still attempted). 139 * 140 * Sidenote: Whilst a jobject could also represent a jclass, jstring, etc, 141 * the stricter approach is taken: the most exact C++ type must be used. 142 */ 143 144 #ifndef NATIVEHELPER_JNI_MACROS_H 145 #define NATIVEHELPER_JNI_MACROS_H 146 147 // The below basic macros do not perform automatic stringification, 148 // invoked e.g. as MAKE_JNI_NATIVE_METHOD("some_name", "()V", void_fn) 149 150 // An expression that evaluates to JNINativeMethod { name, signature, function }, 151 // and applies the above compile-time checking for signature+function. 152 // The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative. 153 #define MAKE_JNI_NATIVE_METHOD(name, signature, function) \ 154 _NATIVEHELPER_JNI_MAKE_METHOD(kNormalNative, name, signature, function) 155 156 // An expression that evaluates to JNINativeMethod { name, signature, function }, 157 // and applies the above compile-time checking for signature+function. 158 // The equivalent Java Language code must be annotated with @FastNative. 159 #define MAKE_JNI_FAST_NATIVE_METHOD(name, signature, function) \ 160 _NATIVEHELPER_JNI_MAKE_METHOD(kFastNative, name, signature, function) 161 162 // An expression that evaluates to JNINativeMethod { name, signature, function }, 163 // and applies the above compile-time checking for signature+function. 164 // The equivalent Java Language code must be annotated with @CriticalNative. 165 #define MAKE_JNI_CRITICAL_NATIVE_METHOD(name, signature, function) \ 166 _NATIVEHELPER_JNI_MAKE_METHOD(kCriticalNative, name, signature, function) 167 168 // Automatically signature-inferencing macros are also available, 169 // which also checks the C++ function types for validity: 170 171 // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } 172 // by inferring the signature at compile-time. Only works when the C++ function type 173 // corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???). 174 // 175 // The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative. 176 #define MAKE_JNI_NATIVE_METHOD_AUTOSIG(name, function) \ 177 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kNormalNative, name, function) 178 179 // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } 180 // by inferring the signature at compile-time. Only works when the C++ function type 181 // corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???). 182 // 183 // The equivalent Java Language code must be annotated with @FastNative. 184 #define MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(name, function) \ 185 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kFastNative, name, function) 186 187 // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } 188 // by inferring the signature at compile-time. 189 // 190 // The equivalent Java Language code must be annotated with @CriticalNative. 191 #define MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(name, function) \ 192 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kCriticalNative, name, function) 193 194 // Convenience macros when the functions follow the naming convention: 195 // .java file .cpp file 196 // JavaLanguageName <-> ${ClassName}_${JavaLanguageName} 197 // 198 // Stringification is done automatically, invoked as: 199 // NATIVE_[FAST_|CRITICAL]_METHOD(ClassName, JavaLanguageName, Signature) 200 // 201 // Intended to construct a JNINativeMethod. 202 // (Assumes the C name is the ClassName_JavaMethodName). 203 // 204 // The Java Language code must be annotated with one of (none,@FastNative,@CriticalNative) 205 // for the (none,FAST_,CRITICAL_) variants of these macros. 206 207 #define NATIVE_METHOD(className, functionName, signature) \ 208 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) 209 210 #define OVERLOADED_NATIVE_METHOD(className, functionName, signature, identifier) \ 211 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) 212 213 #define NATIVE_METHOD_AUTOSIG(className, functionName) \ 214 MAKE_JNI_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) 215 216 #define FAST_NATIVE_METHOD(className, functionName, signature) \ 217 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) 218 219 #define OVERLOADED_FAST_NATIVE_METHOD(className, functionName, signature, identifier) \ 220 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) 221 222 #define FAST_NATIVE_METHOD_AUTOSIG(className, functionName) \ 223 MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) 224 225 #define CRITICAL_NATIVE_METHOD(className, functionName, signature) \ 226 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) 227 228 #define OVERLOADED_CRITICAL_NATIVE_METHOD(className, functionName, signature, identifier) \ 229 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) 230 231 #define CRITICAL_NATIVE_METHOD_AUTOSIG(className, functionName) \ 232 MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) 233 234 //////////////////////////////////////////////////////// 235 // IMPLEMENTATION ONLY. 236 // DO NOT USE DIRECTLY. 237 //////////////////////////////////////////////////////// 238 239 #if defined(__cplusplus) && __cplusplus >= 201402L 240 #include "nativehelper/detail/signature_checker.h" // for MAKE_CHECKED_JNI_NATIVE_METHOD 241 #endif 242 243 // Expands to an expression whose type is JNINativeMethod. 244 // This is for older versions of C++ or C, so it has no compile-time checking. 245 #define _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) \ 246 ( \ 247 (JNINativeMethod) { \ 248 (name), \ 249 (sig), \ 250 _NATIVEHELPER_JNI_MACRO_CAST(reinterpret_cast, void *)(fn) \ 251 } \ 252 ) 253 254 // C++14 or better, use compile-time checking. 255 #if defined(__cplusplus) && __cplusplus >= 201402L 256 // Expands to a compound expression whose type is JNINativeMethod. 257 #define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \ 258 MAKE_CHECKED_JNI_NATIVE_METHOD(kind, name, sig, fn) 259 260 // Expands to a compound expression whose type is JNINativeMethod. 261 #define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \ 262 MAKE_INFERRED_JNI_NATIVE_METHOD(kind, name, function) 263 264 #else 265 // Older versions of C++ or C code get the regular macro that's unchecked. 266 // Expands to a compound expression whose type is JNINativeMethod. 267 #define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \ 268 _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) 269 270 // Need C++14 or newer to use the AUTOSIG macros. 271 #define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \ 272 static_assert(false, "Cannot infer JNI signatures prior to C++14 for function " #function); 273 274 #endif // C++14 check 275 276 // C-style cast for C, C++-style cast for C++ to avoid warnings/errors. 277 #if defined(__cplusplus) 278 #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \ 279 which_cast<to> 280 #else 281 #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \ 282 (to) 283 #endif 284 285 #endif // NATIVEHELPER_JNI_MACROS_H 286