| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Extracts native methods from a Java file and generates the JNI bindings. | 6 """Extracts native methods from a Java file and generates the JNI bindings. |
| 7 If you change this, please run and update the tests.""" | 7 If you change this, please run and update the tests.""" |
| 8 | 8 |
| 9 import collections | 9 import collections |
| 10 import errno | 10 import errno |
| (...skipping 800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 811 kmethods = self.GetKMethodsString(clazz) | 811 kmethods = self.GetKMethodsString(clazz) |
| 812 if kmethods: | 812 if kmethods: |
| 813 values = {'JAVA_CLASS': clazz, | 813 values = {'JAVA_CLASS': clazz, |
| 814 'KMETHODS': kmethods} | 814 'KMETHODS': kmethods} |
| 815 ret += [template.substitute(values)] | 815 ret += [template.substitute(values)] |
| 816 if not ret: return '' | 816 if not ret: return '' |
| 817 return '\n' + '\n'.join(ret) | 817 return '\n' + '\n'.join(ret) |
| 818 | 818 |
| 819 def GetJNINativeMethodsString(self): | 819 def GetJNINativeMethodsString(self): |
| 820 """Returns the implementation of the array of native methods.""" | 820 """Returns the implementation of the array of native methods.""" |
| 821 if self.options.native_exports and not self.options.native_exports_optional: | 821 if not self.options.native_exports_optional: |
| 822 return '' | 822 return '' |
| 823 template = Template("""\ | 823 template = Template("""\ |
| 824 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { | 824 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { |
| 825 ${KMETHODS} | 825 ${KMETHODS} |
| 826 }; | 826 }; |
| 827 """) | 827 """) |
| 828 return self.SubstituteNativeMethods(template) | 828 return self.SubstituteNativeMethods(template) |
| 829 | 829 |
| 830 def GetRegisterNativesString(self): | 830 def GetRegisterNativesString(self): |
| 831 """Returns the code for RegisterNatives.""" | 831 """Returns the code for RegisterNatives.""" |
| 832 template = Template("""\ | 832 template = Template("""\ |
| 833 ${REGISTER_NATIVES_SIGNATURE} { | 833 ${REGISTER_NATIVES_SIGNATURE} { |
| 834 ${EARLY_EXIT} | 834 ${EARLY_EXIT} |
| 835 ${CLASSES} | |
| 836 ${NATIVES} | 835 ${NATIVES} |
| 837 return true; | 836 return true; |
| 838 } | 837 } |
| 839 """) | 838 """) |
| 840 signature = 'static bool RegisterNativesImpl(JNIEnv* env)' | 839 signature = 'static bool RegisterNativesImpl(JNIEnv* env)' |
| 841 early_exit = '' | 840 early_exit = '' |
| 842 if self.options.native_exports_optional: | 841 if self.options.native_exports_optional: |
| 843 early_exit = """\ | 842 early_exit = """\ |
| 844 if (base::android::IsManualJniRegistrationDisabled()) return true; | 843 if (base::android::IsManualJniRegistrationDisabled()) return true; |
| 845 """ | 844 """ |
| 846 | 845 |
| 847 natives = self.GetRegisterNativesImplString() | 846 natives = self.GetRegisterNativesImplString() |
| 848 values = {'REGISTER_NATIVES_SIGNATURE': signature, | 847 values = {'REGISTER_NATIVES_SIGNATURE': signature, |
| 849 'EARLY_EXIT': early_exit, | 848 'EARLY_EXIT': early_exit, |
| 850 'CLASSES': self.GetFindClasses(), | |
| 851 'NATIVES': natives, | 849 'NATIVES': natives, |
| 852 } | 850 } |
| 853 return template.substitute(values) | 851 return template.substitute(values) |
| 854 | 852 |
| 855 def GetRegisterNativesImplString(self): | 853 def GetRegisterNativesImplString(self): |
| 856 """Returns the shared implementation for RegisterNatives.""" | 854 """Returns the shared implementation for RegisterNatives.""" |
| 857 if self.options.native_exports and not self.options.native_exports_optional: | 855 if not self.options.native_exports_optional: |
| 858 return '' | 856 return '' |
| 859 | 857 |
| 860 template = Template("""\ | 858 template = Template("""\ |
| 861 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); | 859 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); |
| 862 | 860 |
| 863 if (env->RegisterNatives(${JAVA_CLASS}_clazz(env), | 861 if (env->RegisterNatives(${JAVA_CLASS}_clazz(env), |
| 864 kMethods${JAVA_CLASS}, | 862 kMethods${JAVA_CLASS}, |
| 865 kMethods${JAVA_CLASS}Size) < 0) { | 863 kMethods${JAVA_CLASS}Size) < 0) { |
| 866 jni_generator::HandleRegistrationError( | 864 jni_generator::HandleRegistrationError( |
| 867 env, ${JAVA_CLASS}_clazz(env), __FILE__); | 865 env, ${JAVA_CLASS}_clazz(env), __FILE__); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 params = native.params | 970 params = native.params |
| 973 params_in_call = ['env'] + self.GetJNIFirstParamForCall(native) | 971 params_in_call = ['env'] + self.GetJNIFirstParamForCall(native) |
| 974 for p in params: | 972 for p in params: |
| 975 c_type = JavaDataTypeToC(p.datatype) | 973 c_type = JavaDataTypeToC(p.datatype) |
| 976 if re.match(RE_SCOPED_JNI_TYPES, c_type): | 974 if re.match(RE_SCOPED_JNI_TYPES, c_type): |
| 977 params_in_call.append(self.GetJavaParamRefForCall(c_type, p.name)) | 975 params_in_call.append(self.GetJavaParamRefForCall(c_type, p.name)) |
| 978 else: | 976 else: |
| 979 params_in_call.append(p.name) | 977 params_in_call.append(p.name) |
| 980 params_in_call = ', '.join(params_in_call) | 978 params_in_call = ', '.join(params_in_call) |
| 981 | 979 |
| 982 if self.options.native_exports: | |
| 983 stub_visibility = 'extern "C" __attribute__((visibility("default")))\n' | |
| 984 else: | |
| 985 stub_visibility = 'static ' | |
| 986 return_type = return_declaration = JavaDataTypeToC(native.return_type) | 980 return_type = return_declaration = JavaDataTypeToC(native.return_type) |
| 987 post_call = '' | 981 post_call = '' |
| 988 if re.match(RE_SCOPED_JNI_TYPES, return_type): | 982 if re.match(RE_SCOPED_JNI_TYPES, return_type): |
| 989 post_call = '.Release()' | 983 post_call = '.Release()' |
| 990 return_declaration = 'ScopedJavaLocalRef<' + return_type + '>' | 984 return_declaration = 'ScopedJavaLocalRef<' + return_type + '>' |
| 991 values = { | 985 values = { |
| 992 'RETURN': return_type, | 986 'RETURN': return_type, |
| 993 'RETURN_DECLARATION': return_declaration, | 987 'RETURN_DECLARATION': return_declaration, |
| 994 'NAME': native.name, | 988 'NAME': native.name, |
| 995 'PARAMS': self.GetParamsInDeclaration(native), | 989 'PARAMS': self.GetParamsInDeclaration(native), |
| 996 'PARAMS_IN_STUB': self.GetParamsInStub(native), | 990 'PARAMS_IN_STUB': self.GetParamsInStub(native), |
| 997 'PARAMS_IN_CALL': params_in_call, | 991 'PARAMS_IN_CALL': params_in_call, |
| 998 'POST_CALL': post_call, | 992 'POST_CALL': post_call, |
| 999 'STUB_NAME': self.GetStubName(native), | 993 'STUB_NAME': self.GetStubName(native), |
| 1000 'STUB_VISIBILITY': stub_visibility, | |
| 1001 } | 994 } |
| 1002 | 995 |
| 1003 if is_method: | 996 if is_method: |
| 1004 optional_error_return = JavaReturnValueToC(native.return_type) | 997 optional_error_return = JavaReturnValueToC(native.return_type) |
| 1005 if optional_error_return: | 998 if optional_error_return: |
| 1006 optional_error_return = ', ' + optional_error_return | 999 optional_error_return = ', ' + optional_error_return |
| 1007 values.update({ | 1000 values.update({ |
| 1008 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1001 'OPTIONAL_ERROR_RETURN': optional_error_return, |
| 1009 'PARAM0_NAME': native.params[0].name, | 1002 'PARAM0_NAME': native.params[0].name, |
| 1010 'P0_TYPE': native.p0_type, | 1003 'P0_TYPE': native.p0_type, |
| 1011 }) | 1004 }) |
| 1012 template = Template("""\ | 1005 template = Template("""\ |
| 1013 ${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env, | 1006 extern "C" __attribute__((visibility("default"))) |
| 1007 ${RETURN} ${STUB_NAME}(JNIEnv* env, |
| 1014 ${PARAMS_IN_STUB}) { | 1008 ${PARAMS_IN_STUB}) { |
| 1015 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 1009 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
| 1016 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 1010 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
| 1017 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1011 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
| 1018 } | 1012 } |
| 1019 """) | 1013 """) |
| 1020 else: | 1014 else: |
| 1021 template = Template(""" | 1015 template = Template(""" |
| 1022 static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS}); | 1016 static ${RETURN_DECLARATION} ${NAME}(JNIEnv* env, ${PARAMS}); |
| 1023 | 1017 |
| 1024 ${STUB_VISIBILITY}${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) { | 1018 extern "C" __attribute__((visibility("default"))) |
| 1019 ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_STUB}) { |
| 1025 return ${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1020 return ${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
| 1026 } | 1021 } |
| 1027 """) | 1022 """) |
| 1028 | 1023 |
| 1029 return template.substitute(values) | 1024 return template.substitute(values) |
| 1030 | 1025 |
| 1031 def GetArgument(self, param): | 1026 def GetArgument(self, param): |
| 1032 return ('as_jint(' + param.name + ')' | 1027 return ('as_jint(' + param.name + ')' |
| 1033 if param.datatype == 'int' else param.name) | 1028 if param.datatype == 'int' else param.name) |
| 1034 | 1029 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1146 class_name = entry.java_class_name | 1141 class_name = entry.java_class_name |
| 1147 jni_class_path = self.fully_qualified_class + '$' + class_name | 1142 jni_class_path = self.fully_qualified_class + '$' + class_name |
| 1148 ret[class_name] = jni_class_path | 1143 ret[class_name] = jni_class_path |
| 1149 return ret | 1144 return ret |
| 1150 | 1145 |
| 1151 def GetClassPathDefinitions(self): | 1146 def GetClassPathDefinitions(self): |
| 1152 """Returns the ClassPath constants.""" | 1147 """Returns the ClassPath constants.""" |
| 1153 ret = [] | 1148 ret = [] |
| 1154 template = Template("""\ | 1149 template = Template("""\ |
| 1155 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") | 1150 const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") |
| 1156 native_classes = self.GetUniqueClasses(self.natives) | 1151 all_classes = self.GetUniqueClasses(self.called_by_natives) |
| 1157 called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) | 1152 if self.options.native_exports_optional: |
| 1158 if self.options.native_exports and not self.options.native_exports_optional: | 1153 all_classes.update(self.GetUniqueClasses(self.natives)) |
| 1159 all_classes = called_by_native_classes | |
| 1160 else: | |
| 1161 all_classes = native_classes | |
| 1162 all_classes.update(called_by_native_classes) | |
| 1163 | 1154 |
| 1164 for clazz in all_classes: | 1155 for clazz in all_classes: |
| 1165 values = { | 1156 values = { |
| 1166 'JAVA_CLASS': clazz, | 1157 'JAVA_CLASS': clazz, |
| 1167 'JNI_CLASS_PATH': all_classes[clazz], | 1158 'JNI_CLASS_PATH': all_classes[clazz], |
| 1168 } | 1159 } |
| 1169 ret += [template.substitute(values)] | 1160 ret += [template.substitute(values)] |
| 1170 ret += '' | 1161 ret += '' |
| 1171 | 1162 |
| 1172 if self.options.native_exports: | 1163 template = Template("""\ |
| 1173 template = Template("""\ | |
| 1174 // Leaking this jclass as we cannot use LazyInstance from some threads. | 1164 // Leaking this jclass as we cannot use LazyInstance from some threads. |
| 1175 base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0; | 1165 base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0; |
| 1176 #define ${JAVA_CLASS}_clazz(env) \ | 1166 #define ${JAVA_CLASS}_clazz(env) \ |
| 1177 base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \ | 1167 base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \ |
| 1178 &g_${JAVA_CLASS}_clazz)""") | 1168 &g_${JAVA_CLASS}_clazz)""") |
| 1179 else: | |
| 1180 template = Template("""\ | |
| 1181 // Leaking this jclass as we cannot use LazyInstance from some threads. | |
| 1182 jclass g_${JAVA_CLASS}_clazz = NULL; | |
| 1183 #define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""") | |
| 1184 | 1169 |
| 1185 for clazz in all_classes: | 1170 for clazz in all_classes: |
| 1186 values = { | 1171 values = { |
| 1187 'JAVA_CLASS': clazz, | 1172 'JAVA_CLASS': clazz, |
| 1188 } | 1173 } |
| 1189 ret += [template.substitute(values)] | 1174 ret += [template.substitute(values)] |
| 1190 | 1175 |
| 1191 return '\n'.join(ret) | 1176 return '\n'.join(ret) |
| 1192 | 1177 |
| 1193 def GetFindClasses(self): | |
| 1194 """Returns the imlementation of FindClass for all known classes.""" | |
| 1195 if self.options.native_exports: | |
| 1196 return '\n' | |
| 1197 template = Template("""\ | |
| 1198 g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( | |
| 1199 base::android::GetClass(env, k${JAVA_CLASS}ClassPath).obj()));""") | |
| 1200 ret = [] | |
| 1201 all_classes = self.GetUniqueClasses(self.natives) | |
| 1202 all_classes.update(self.GetUniqueClasses(self.called_by_natives)) | |
| 1203 for clazz in all_classes: | |
| 1204 values = {'JAVA_CLASS': clazz} | |
| 1205 ret += [template.substitute(values)] | |
| 1206 return '\n'.join(ret) | |
| 1207 | |
| 1208 def GetMethodIDImpl(self, called_by_native): | 1178 def GetMethodIDImpl(self, called_by_native): |
| 1209 """Returns the implementation of GetMethodID.""" | 1179 """Returns the implementation of GetMethodID.""" |
| 1210 template = Template("""\ | 1180 template = Template("""\ |
| 1211 base::android::MethodID::LazyGet< | 1181 base::android::MethodID::LazyGet< |
| 1212 base::android::MethodID::TYPE_${STATIC}>( | 1182 base::android::MethodID::TYPE_${STATIC}>( |
| 1213 env, ${JAVA_CLASS}_clazz(env), | 1183 env, ${JAVA_CLASS}_clazz(env), |
| 1214 "${JNI_NAME}", | 1184 "${JNI_NAME}", |
| 1215 ${JNI_SIGNATURE}, | 1185 ${JNI_SIGNATURE}, |
| 1216 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); | 1186 &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); |
| 1217 """) | 1187 """) |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1360 'include in the generated header.') | 1330 'include in the generated header.') |
| 1361 option_parser.add_option('--ptr_type', default='int', | 1331 option_parser.add_option('--ptr_type', default='int', |
| 1362 type='choice', choices=['int', 'long'], | 1332 type='choice', choices=['int', 'long'], |
| 1363 help='The type used to represent native pointers in ' | 1333 help='The type used to represent native pointers in ' |
| 1364 'Java code. For 32-bit, use int; ' | 1334 'Java code. For 32-bit, use int; ' |
| 1365 'for 64-bit, use long.') | 1335 'for 64-bit, use long.') |
| 1366 option_parser.add_option('--cpp', default='cpp', | 1336 option_parser.add_option('--cpp', default='cpp', |
| 1367 help='The path to cpp command.') | 1337 help='The path to cpp command.') |
| 1368 option_parser.add_option('--javap', default='javap', | 1338 option_parser.add_option('--javap', default='javap', |
| 1369 help='The path to javap command.') | 1339 help='The path to javap command.') |
| 1370 option_parser.add_option('--native_exports', action='store_true', | |
| 1371 help='Native method registration through .so ' | |
| 1372 'exports.') | |
| 1373 option_parser.add_option('--native_exports_optional', action='store_true', | 1340 option_parser.add_option('--native_exports_optional', action='store_true', |
| 1374 help='Support both explicit and native method' | 1341 help='Support both explicit and native method' |
| 1375 'registration.') | 1342 'registration.') |
| 1376 options, args = option_parser.parse_args(argv) | 1343 options, args = option_parser.parse_args(argv) |
| 1377 if options.native_exports_optional: | |
| 1378 options.native_exports = True | |
| 1379 if options.jar_file: | 1344 if options.jar_file: |
| 1380 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1345 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
| 1381 options.output_dir) | 1346 options.output_dir) |
| 1382 elif options.input_file: | 1347 elif options.input_file: |
| 1383 input_file = options.input_file | 1348 input_file = options.input_file |
| 1384 else: | 1349 else: |
| 1385 option_parser.print_help() | 1350 option_parser.print_help() |
| 1386 print '\nError: Must specify --jar_file or --input_file.' | 1351 print '\nError: Must specify --jar_file or --input_file.' |
| 1387 return 1 | 1352 return 1 |
| 1388 output_file = None | 1353 output_file = None |
| 1389 if options.output_dir: | 1354 if options.output_dir: |
| 1390 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1355 root_name = os.path.splitext(os.path.basename(input_file))[0] |
| 1391 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1356 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
| 1392 GenerateJNIHeader(input_file, output_file, options) | 1357 GenerateJNIHeader(input_file, output_file, options) |
| 1393 | 1358 |
| 1394 if options.depfile: | 1359 if options.depfile: |
| 1395 build_utils.WriteDepfile( | 1360 build_utils.WriteDepfile( |
| 1396 options.depfile, | 1361 options.depfile, |
| 1397 build_utils.GetPythonDependencies()) | 1362 build_utils.GetPythonDependencies()) |
| 1398 | 1363 |
| 1399 | 1364 |
| 1400 if __name__ == '__main__': | 1365 if __name__ == '__main__': |
| 1401 sys.exit(main(sys.argv)) | 1366 sys.exit(main(sys.argv)) |
| OLD | NEW |