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 #pragma once 145 146 // The below basic macros do not perform automatic stringification, 147 // invoked e.g. as MAKE_JNI_NATIVE_METHOD("some_name", "()V", void_fn) 148 149 // An expression that evaluates to JNINativeMethod { name, signature, function }, 150 // and applies the above compile-time checking for signature+function. 151 // The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative. 152 #define MAKE_JNI_NATIVE_METHOD(name, signature, function) \ 153 _NATIVEHELPER_JNI_MAKE_METHOD(kNormalNative, name, signature, function) 154 155 // An expression that evaluates to JNINativeMethod { name, signature, function }, 156 // and applies the above compile-time checking for signature+function. 157 // The equivalent Java Language code must be annotated with @FastNative. 158 #define MAKE_JNI_FAST_NATIVE_METHOD(name, signature, function) \ 159 _NATIVEHELPER_JNI_MAKE_METHOD(kFastNative, name, signature, function) 160 161 // An expression that evaluates to JNINativeMethod { name, signature, function }, 162 // and applies the above compile-time checking for signature+function. 163 // The equivalent Java Language code must be annotated with @CriticalNative. 164 #define MAKE_JNI_CRITICAL_NATIVE_METHOD(name, signature, function) \ 165 _NATIVEHELPER_JNI_MAKE_METHOD(kCriticalNative, name, signature, function) 166 167 // Automatically signature-inferencing macros are also available, 168 // which also checks the C++ function types for validity: 169 170 // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } 171 // by inferring the signature at compile-time. Only works when the C++ function type 172 // corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???). 173 // 174 // The equivalent Java Language code must not be annotated with @FastNative/@CriticalNative. 175 #define MAKE_JNI_NATIVE_METHOD_AUTOSIG(name, function) \ 176 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kNormalNative, name, function) 177 178 // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } 179 // by inferring the signature at compile-time. Only works when the C++ function type 180 // corresponds to one unambigous JNI parameter (e.g. 'jintArray' -> '[I' but 'jobject' -> ???). 181 // 182 // The equivalent Java Language code must be annotated with @FastNative. 183 #define MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(name, function) \ 184 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kFastNative, name, function) 185 186 // An expression that evalutes to JNINativeMethod { name, infersig(function), function) } 187 // by inferring the signature at compile-time. 188 // 189 // The equivalent Java Language code must be annotated with @CriticalNative. 190 #define MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(name, function) \ 191 _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kCriticalNative, name, function) 192 193 // Convenience macros when the functions follow the naming convention: 194 // .java file .cpp file 195 // JavaLanguageName <-> ${ClassName}_${JavaLanguageName} 196 // 197 // Stringification is done automatically, invoked as: 198 // NATIVE_[FAST_|CRITICAL]_METHOD(ClassName, JavaLanguageName, Signature) 199 // 200 // Intended to construct a JNINativeMethod. 201 // (Assumes the C name is the ClassName_JavaMethodName). 202 // 203 // The Java Language code must be annotated with one of (none,@FastNative,@CriticalNative) 204 // for the (none,FAST_,CRITICAL_) variants of these macros. 205 206 #define NATIVE_METHOD(className, functionName, signature) \ 207 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) 208 209 #define OVERLOADED_NATIVE_METHOD(className, functionName, signature, identifier) \ 210 MAKE_JNI_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) 211 212 #define NATIVE_METHOD_AUTOSIG(className, functionName) \ 213 MAKE_JNI_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) 214 215 #define FAST_NATIVE_METHOD(className, functionName, signature) \ 216 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) 217 218 #define OVERLOADED_FAST_NATIVE_METHOD(className, functionName, signature, identifier) \ 219 MAKE_JNI_FAST_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) 220 221 #define FAST_NATIVE_METHOD_AUTOSIG(className, functionName) \ 222 MAKE_JNI_FAST_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) 223 224 #define CRITICAL_NATIVE_METHOD(className, functionName, signature) \ 225 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## functionName) 226 227 #define OVERLOADED_CRITICAL_NATIVE_METHOD(className, functionName, signature, identifier) \ 228 MAKE_JNI_CRITICAL_NATIVE_METHOD(#functionName, signature, className ## _ ## identifier) 229 230 #define CRITICAL_NATIVE_METHOD_AUTOSIG(className, functionName) \ 231 MAKE_JNI_CRITICAL_NATIVE_METHOD_AUTOSIG(#functionName, className ## _ ## functionName) 232 233 //////////////////////////////////////////////////////// 234 // IMPLEMENTATION ONLY. 235 // DO NOT USE DIRECTLY. 236 //////////////////////////////////////////////////////// 237 238 #if defined(__cplusplus) && __cplusplus >= 201402L 239 #include "nativehelper/detail/signature_checker.h" // for MAKE_CHECKED_JNI_NATIVE_METHOD 240 #endif 241 242 // Expands to an expression whose type is JNINativeMethod. 243 // This is for older versions of C++ or C, so it has no compile-time checking. 244 #define _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) \ 245 ( \ 246 (JNINativeMethod) { \ 247 (name), \ 248 (sig), \ 249 _NATIVEHELPER_JNI_MACRO_CAST(reinterpret_cast, void *)(fn) \ 250 } \ 251 ) 252 253 // C++14 or better, use compile-time checking. 254 #if defined(__cplusplus) && __cplusplus >= 201402L 255 // Expands to a compound expression whose type is JNINativeMethod. 256 #define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \ 257 MAKE_CHECKED_JNI_NATIVE_METHOD(kind, name, sig, fn) 258 259 // Expands to a compound expression whose type is JNINativeMethod. 260 #define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \ 261 MAKE_INFERRED_JNI_NATIVE_METHOD(kind, name, function) 262 263 #else 264 // Older versions of C++ or C code get the regular macro that's unchecked. 265 // Expands to a compound expression whose type is JNINativeMethod. 266 #define _NATIVEHELPER_JNI_MAKE_METHOD(kind, name, sig, fn) \ 267 _NATIVEHELPER_JNI_MAKE_METHOD_OLD(kind, name, sig, fn) 268 269 // Need C++14 or newer to use the AUTOSIG macros. 270 #define _NATIVEHELPER_JNI_MAKE_METHOD_AUTOSIG(kind, name, function) \ 271 static_assert(false, "Cannot infer JNI signatures prior to C++14 for function " #function); 272 273 #endif // C++14 check 274 275 // C-style cast for C, C++-style cast for C++ to avoid warnings/errors. 276 #if defined(__cplusplus) 277 #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \ 278 which_cast<to> 279 #else 280 #define _NATIVEHELPER_JNI_MACRO_CAST(which_cast, to) \ 281 (to) 282 #endif 283 284