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 871 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
882 kmethods = self.GetKMethodsString(clazz) | 882 kmethods = self.GetKMethodsString(clazz) |
883 if kmethods: | 883 if kmethods: |
884 values = {'JAVA_CLASS': clazz, | 884 values = {'JAVA_CLASS': clazz, |
885 'KMETHODS': kmethods} | 885 'KMETHODS': kmethods} |
886 ret += [template.substitute(values)] | 886 ret += [template.substitute(values)] |
887 if not ret: return '' | 887 if not ret: return '' |
888 return '\n' + '\n'.join(ret) | 888 return '\n' + '\n'.join(ret) |
889 | 889 |
890 def GetJNINativeMethodsString(self): | 890 def GetJNINativeMethodsString(self): |
891 """Returns the implementation of the array of native methods.""" | 891 """Returns the implementation of the array of native methods.""" |
892 if self.options.native_exports and not self.options.native_exports_optional: | 892 if self.options.native_exports: |
893 return '' | 893 return '' |
894 template = Template("""\ | 894 template = Template("""\ |
895 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { | 895 static const JNINativeMethod kMethods${JAVA_CLASS}[] = { |
896 ${KMETHODS} | 896 ${KMETHODS} |
897 }; | 897 }; |
898 """) | 898 """) |
899 return self.SubstituteNativeMethods(template) | 899 return self.SubstituteNativeMethods(template) |
900 | 900 |
901 def GetRegisterCalledByNativesImplString(self): | 901 def GetRegisterCalledByNativesImplString(self): |
902 """Returns the code for registering the called by native methods.""" | 902 """Returns the code for registering the called by native methods.""" |
(...skipping 12 matching lines...) Expand all Loading... |
915 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, | 915 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, |
916 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native), | 916 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native), |
917 } | 917 } |
918 ret += [template.substitute(values)] | 918 ret += [template.substitute(values)] |
919 return '\n'.join(ret) | 919 return '\n'.join(ret) |
920 | 920 |
921 def GetRegisterNativesString(self): | 921 def GetRegisterNativesString(self): |
922 """Returns the code for RegisterNatives.""" | 922 """Returns the code for RegisterNatives.""" |
923 template = Template("""\ | 923 template = Template("""\ |
924 ${REGISTER_NATIVES_SIGNATURE} { | 924 ${REGISTER_NATIVES_SIGNATURE} { |
925 ${EARLY_EXIT}${CLASSES} | 925 ${CLASSES} |
926 ${NATIVES} | 926 ${NATIVES} |
927 ${CALLED_BY_NATIVES} | 927 ${CALLED_BY_NATIVES} |
928 return true; | 928 return true; |
929 } | 929 } |
930 """) | 930 """) |
931 signature = 'static bool RegisterNativesImpl(JNIEnv* env' | 931 signature = 'static bool RegisterNativesImpl(JNIEnv* env' |
932 if self.init_native: | 932 if self.init_native: |
933 signature += ', jclass clazz)' | 933 signature += ', jclass clazz)' |
934 else: | 934 else: |
935 signature += ')' | 935 signature += ')' |
936 | 936 |
937 early_exit = '' | |
938 if self.options.native_exports_optional: | |
939 early_exit = """\ | |
940 if (base::android::IsManualJniRegistrationDisabled()) return true; | |
941 """ | |
942 | |
943 natives = self.GetRegisterNativesImplString() | 937 natives = self.GetRegisterNativesImplString() |
944 called_by_natives = self.GetRegisterCalledByNativesImplString() | 938 called_by_natives = self.GetRegisterCalledByNativesImplString() |
945 values = {'REGISTER_NATIVES_SIGNATURE': signature, | 939 values = {'REGISTER_NATIVES_SIGNATURE': signature, |
946 'EARLY_EXIT': early_exit, | |
947 'CLASSES': self.GetFindClasses(), | 940 'CLASSES': self.GetFindClasses(), |
948 'NATIVES': natives, | 941 'NATIVES': natives, |
949 'CALLED_BY_NATIVES': called_by_natives, | 942 'CALLED_BY_NATIVES': called_by_natives, |
950 } | 943 } |
951 return template.substitute(values) | 944 return template.substitute(values) |
952 | 945 |
953 def GetRegisterNativesImplString(self): | 946 def GetRegisterNativesImplString(self): |
954 """Returns the shared implementation for RegisterNatives.""" | 947 """Returns the shared implementation for RegisterNatives.""" |
955 if self.options.native_exports and not self.options.native_exports_optional: | 948 if self.options.native_exports: |
956 return '' | 949 return '' |
957 | 950 |
958 template = Template("""\ | 951 template = Template("""\ |
959 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); | 952 const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS}); |
960 | 953 |
961 if (env->RegisterNatives(${JAVA_CLASS}_clazz(env), | 954 if (env->RegisterNatives(${JAVA_CLASS}_clazz(env), |
962 kMethods${JAVA_CLASS}, | 955 kMethods${JAVA_CLASS}, |
963 kMethods${JAVA_CLASS}Size) < 0) { | 956 kMethods${JAVA_CLASS}Size) < 0) { |
964 jni_generator::HandleRegistrationError( | 957 jni_generator::HandleRegistrationError( |
965 env, ${JAVA_CLASS}_clazz(env), __FILE__); | 958 env, ${JAVA_CLASS}_clazz(env), __FILE__); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 [JavaDataTypeToC(param.datatype) + ' ' + | 1028 [JavaDataTypeToC(param.datatype) + ' ' + |
1036 param.name | 1029 param.name |
1037 for param in native.params]) | 1030 for param in native.params]) |
1038 | 1031 |
1039 def GetCalledByNativeParamsInDeclaration(self, called_by_native): | 1032 def GetCalledByNativeParamsInDeclaration(self, called_by_native): |
1040 return ',\n '.join([ | 1033 return ',\n '.join([ |
1041 JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' + | 1034 JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' + |
1042 param.name | 1035 param.name |
1043 for param in called_by_native.params]) | 1036 for param in called_by_native.params]) |
1044 | 1037 |
1045 def GetStubName(self, native): | |
1046 """Return the name of the stub function for this native method. | |
1047 | |
1048 Args: | |
1049 native: the native dictionary describing the method. | |
1050 | |
1051 Returns: | |
1052 A string with the stub function name. For native exports mode this is the | |
1053 Java_* symbol name required by the JVM; otherwise it is just the name of | |
1054 the native method itself. | |
1055 """ | |
1056 if self.options.native_exports: | |
1057 template = Template("Java_${JAVA_NAME}_native${NAME}") | |
1058 | |
1059 java_name = JniParams.RemapClassName(self.fully_qualified_class) | |
1060 java_name = java_name.replace('_', '_1').replace('/', '_') | |
1061 if native.java_class_name: | |
1062 java_name += '_00024' + native.java_class_name | |
1063 | |
1064 values = {'NAME': native.name, | |
1065 'JAVA_NAME': java_name} | |
1066 return template.substitute(values) | |
1067 else: | |
1068 return native.name | |
1069 | |
1070 def GetForwardDeclaration(self, native): | 1038 def GetForwardDeclaration(self, native): |
1071 template_str = """ | 1039 template_str = """ |
1072 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); | 1040 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); |
1073 """ | 1041 """ |
1074 if self.options.native_exports: | 1042 if self.options.native_exports: |
1075 template_str += """ | 1043 template_str += """ |
1076 __attribute__((visibility("default"), alias("${NAME}"))) | 1044 __attribute__((visibility("default"), alias("${NAME}"))) |
1077 ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS}); | 1045 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS}); |
1078 """ | 1046 """ |
1079 template = Template(template_str) | 1047 template = Template(template_str) |
1080 params_in_call = [] | 1048 params_in_call = [] |
1081 if not self.options.pure_native_methods: | 1049 if not self.options.pure_native_methods: |
1082 params_in_call = ['env', 'jcaller'] | 1050 params_in_call = ['env', 'jcaller'] |
1083 params_in_call = ', '.join(params_in_call + [p.name for p in native.params]) | 1051 params_in_call = ', '.join(params_in_call + [p.name for p in native.params]) |
1084 | 1052 |
| 1053 java_name = JniParams.RemapClassName(self.fully_qualified_class) |
| 1054 java_name = java_name.replace('_', '_1').replace('/', '_') |
| 1055 if native.java_class_name: |
| 1056 java_name += '_00024' + native.java_class_name |
| 1057 |
1085 values = {'RETURN': JavaDataTypeToC(native.return_type), | 1058 values = {'RETURN': JavaDataTypeToC(native.return_type), |
1086 'NAME': native.name, | 1059 'NAME': native.name, |
| 1060 'JAVA_NAME': java_name, |
1087 'PARAMS': self.GetParamsInDeclaration(native), | 1061 'PARAMS': self.GetParamsInDeclaration(native), |
1088 'PARAMS_IN_CALL': params_in_call, | 1062 'PARAMS_IN_CALL': params_in_call} |
1089 'STUB_NAME': self.GetStubName(native)} | |
1090 return template.substitute(values) | 1063 return template.substitute(values) |
1091 | 1064 |
1092 def GetNativeMethodStubString(self, native): | 1065 def GetNativeMethodStubString(self, native): |
1093 """Returns stubs for native methods.""" | 1066 """Returns stubs for native methods.""" |
1094 if self.options.native_exports: | 1067 if self.options.native_exports: |
1095 template_str = """\ | 1068 template_str = """\ |
1096 __attribute__((visibility("default"))) | 1069 __attribute__((visibility("default"))) |
1097 ${RETURN} ${STUB_NAME}(JNIEnv* env, | 1070 ${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, |
1098 ${PARAMS_IN_DECLARATION}) {""" | 1071 ${PARAMS_IN_DECLARATION}) {""" |
1099 else: | 1072 else: |
1100 template_str = """\ | 1073 template_str = """\ |
1101 static ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {""" | 1074 static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {""" |
1102 template_str += """ | 1075 template_str += """ |
1103 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); | 1076 ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); |
1104 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); | 1077 CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); |
1105 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; | 1078 return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; |
1106 } | 1079 } |
1107 """ | 1080 """ |
1108 | 1081 |
1109 template = Template(template_str) | 1082 template = Template(template_str) |
1110 params = [] | 1083 params = [] |
1111 if not self.options.pure_native_methods: | 1084 if not self.options.pure_native_methods: |
1112 params = ['env', 'jcaller'] | 1085 params = ['env', 'jcaller'] |
1113 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) | 1086 params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) |
1114 | 1087 |
1115 return_type = JavaDataTypeToC(native.return_type) | 1088 return_type = JavaDataTypeToC(native.return_type) |
1116 optional_error_return = JavaReturnValueToC(native.return_type) | 1089 optional_error_return = JavaReturnValueToC(native.return_type) |
1117 if optional_error_return: | 1090 if optional_error_return: |
1118 optional_error_return = ', ' + optional_error_return | 1091 optional_error_return = ', ' + optional_error_return |
1119 post_call = '' | 1092 post_call = '' |
1120 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): | 1093 if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): |
1121 post_call = '.Release()' | 1094 post_call = '.Release()' |
1122 | 1095 |
| 1096 if self.options.native_exports: |
| 1097 java_name = JniParams.RemapClassName(self.fully_qualified_class) |
| 1098 java_name = java_name.replace('_', '_1').replace('/', '_') |
| 1099 if native.java_class_name: |
| 1100 java_name += '_00024' + native.java_class_name |
| 1101 else: |
| 1102 java_name = '' |
| 1103 |
1123 values = { | 1104 values = { |
1124 'RETURN': return_type, | 1105 'RETURN': return_type, |
1125 'OPTIONAL_ERROR_RETURN': optional_error_return, | 1106 'OPTIONAL_ERROR_RETURN': optional_error_return, |
| 1107 'JAVA_NAME': java_name, |
1126 'NAME': native.name, | 1108 'NAME': native.name, |
1127 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), | 1109 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), |
1128 'PARAM0_NAME': native.params[0].name, | 1110 'PARAM0_NAME': native.params[0].name, |
1129 'P0_TYPE': native.p0_type, | 1111 'P0_TYPE': native.p0_type, |
1130 'PARAMS_IN_CALL': params_in_call, | 1112 'PARAMS_IN_CALL': params_in_call, |
1131 'POST_CALL': post_call, | 1113 'POST_CALL': post_call |
1132 'STUB_NAME': self.GetStubName(native), | |
1133 } | 1114 } |
1134 return template.substitute(values) | 1115 return template.substitute(values) |
1135 | 1116 |
1136 def GetArgument(self, param): | 1117 def GetArgument(self, param): |
1137 return ('as_jint(' + param.name + ')' | 1118 return ('as_jint(' + param.name + ')' |
1138 if param.datatype == 'int' else param.name) | 1119 if param.datatype == 'int' else param.name) |
1139 | 1120 |
1140 def GetArgumentsInCall(self, params): | 1121 def GetArgumentsInCall(self, params): |
1141 """Return a string of arguments to call from native into Java""" | 1122 """Return a string of arguments to call from native into Java""" |
1142 return [self.GetArgument(p) for p in params] | 1123 return [self.GetArgument(p) for p in params] |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1237 values['FUNCTION_SIGNATURE'] = ( | 1218 values['FUNCTION_SIGNATURE'] = ( |
1238 function_signature_template.substitute(values)) | 1219 function_signature_template.substitute(values)) |
1239 if called_by_native.system_class: | 1220 if called_by_native.system_class: |
1240 values['FUNCTION_HEADER'] = ( | 1221 values['FUNCTION_HEADER'] = ( |
1241 function_header_with_unused_template.substitute(values)) | 1222 function_header_with_unused_template.substitute(values)) |
1242 else: | 1223 else: |
1243 values['FUNCTION_HEADER'] = function_header_template.substitute(values) | 1224 values['FUNCTION_HEADER'] = function_header_template.substitute(values) |
1244 return template.substitute(values) | 1225 return template.substitute(values) |
1245 | 1226 |
1246 def GetKMethodArrayEntry(self, native): | 1227 def GetKMethodArrayEntry(self, native): |
1247 template = Template(' { "native${NAME}", ${JNI_SIGNATURE}, ' + | 1228 template = Template("""\ |
1248 'reinterpret_cast<void*>(${STUB_NAME}) },') | 1229 { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""") |
1249 values = {'NAME': native.name, | 1230 values = {'NAME': native.name, |
1250 'JNI_SIGNATURE': JniParams.Signature(native.params, | 1231 'JNI_SIGNATURE': JniParams.Signature(native.params, |
1251 native.return_type, | 1232 native.return_type, |
1252 True), | 1233 True)} |
1253 'STUB_NAME': self.GetStubName(native)} | |
1254 return template.substitute(values) | 1234 return template.substitute(values) |
1255 | 1235 |
1256 def GetUniqueClasses(self, origin): | 1236 def GetUniqueClasses(self, origin): |
1257 ret = {self.class_name: self.fully_qualified_class} | 1237 ret = {self.class_name: self.fully_qualified_class} |
1258 for entry in origin: | 1238 for entry in origin: |
1259 class_name = self.class_name | 1239 class_name = self.class_name |
1260 jni_class_path = self.fully_qualified_class | 1240 jni_class_path = self.fully_qualified_class |
1261 if entry.java_class_name: | 1241 if entry.java_class_name: |
1262 class_name = entry.java_class_name | 1242 class_name = entry.java_class_name |
1263 jni_class_path = self.fully_qualified_class + '$' + class_name | 1243 jni_class_path = self.fully_qualified_class + '$' + class_name |
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1513 action='store_true', dest='eager_called_by_natives', | 1493 action='store_true', dest='eager_called_by_natives', |
1514 help='When true, the called-by-native methods will ' | 1494 help='When true, the called-by-native methods will ' |
1515 'be initialized in a non-atomic way.') | 1495 'be initialized in a non-atomic way.') |
1516 option_parser.add_option('--cpp', default='cpp', | 1496 option_parser.add_option('--cpp', default='cpp', |
1517 help='The path to cpp command.') | 1497 help='The path to cpp command.') |
1518 option_parser.add_option('--javap', default='javap', | 1498 option_parser.add_option('--javap', default='javap', |
1519 help='The path to javap command.') | 1499 help='The path to javap command.') |
1520 option_parser.add_option('--native_exports', action='store_true', | 1500 option_parser.add_option('--native_exports', action='store_true', |
1521 help='Native method registration through .so ' | 1501 help='Native method registration through .so ' |
1522 'exports.') | 1502 'exports.') |
1523 option_parser.add_option('--native_exports_optional', action='store_true', | |
1524 help='Support both explicit and native method' | |
1525 'registration.') | |
1526 options, args = option_parser.parse_args(argv) | 1503 options, args = option_parser.parse_args(argv) |
1527 if options.native_exports_optional: | |
1528 options.native_exports = True | |
1529 if options.jar_file: | 1504 if options.jar_file: |
1530 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 1505 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1531 options.output_dir) | 1506 options.output_dir) |
1532 elif options.input_file: | 1507 elif options.input_file: |
1533 input_file = options.input_file | 1508 input_file = options.input_file |
1534 else: | 1509 else: |
1535 option_parser.print_help() | 1510 option_parser.print_help() |
1536 print '\nError: Must specify --jar_file or --input_file.' | 1511 print '\nError: Must specify --jar_file or --input_file.' |
1537 return 1 | 1512 return 1 |
1538 output_file = None | 1513 output_file = None |
1539 if options.output_dir: | 1514 if options.output_dir: |
1540 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1515 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1541 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1516 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1542 if options.jarjar: | 1517 if options.jarjar: |
1543 with open(options.jarjar) as f: | 1518 with open(options.jarjar) as f: |
1544 JniParams.SetJarJarMappings(f.read()) | 1519 JniParams.SetJarJarMappings(f.read()) |
1545 GenerateJNIHeader(input_file, output_file, options) | 1520 GenerateJNIHeader(input_file, output_file, options) |
1546 | 1521 |
1547 if options.depfile: | 1522 if options.depfile: |
1548 build_utils.WriteDepfile( | 1523 build_utils.WriteDepfile( |
1549 options.depfile, | 1524 options.depfile, |
1550 build_utils.GetPythonDependencies()) | 1525 build_utils.GetPythonDependencies()) |
1551 | 1526 |
1552 | 1527 |
1553 if __name__ == '__main__': | 1528 if __name__ == '__main__': |
1554 sys.exit(main(sys.argv)) | 1529 sys.exit(main(sys.argv)) |
OLD | NEW |