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 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
405 java_class_name=match.group('java_class_name'), | 405 java_class_name=match.group('java_class_name'), |
406 native_class_name=match.group('native_class_name'), | 406 native_class_name=match.group('native_class_name'), |
407 return_type=match.group('return_type'), | 407 return_type=match.group('return_type'), |
408 name=match.group('name').replace('native', ''), | 408 name=match.group('name').replace('native', ''), |
409 params=JniParams.Parse(match.group('params')), | 409 params=JniParams.Parse(match.group('params')), |
410 ptr_type=ptr_type) | 410 ptr_type=ptr_type) |
411 natives += [native] | 411 natives += [native] |
412 return natives | 412 return natives |
413 | 413 |
414 | 414 |
| 415 def IsMainDexJavaClass(contents): |
| 416 """Returns "true" if the class is annotated with "@MainDex", "false" if not. |
| 417 |
| 418 JNI registration doesn't always need to be completed for non-browser processes |
| 419 since most Java code is only used by the browser process. Classes that are |
| 420 needed by non-browser processes must explicitly be annotated with @MainDex |
| 421 to force JNI registration. |
| 422 """ |
| 423 re_maindex = re.compile(r'@MainDex[\s\S]*class\s+\w+\s*{') |
| 424 found = re.search(re_maindex, contents) |
| 425 return 'true' if found else 'false' |
| 426 |
| 427 |
415 def GetStaticCastForReturnType(return_type): | 428 def GetStaticCastForReturnType(return_type): |
416 type_map = { 'String' : 'jstring', | 429 type_map = { 'String' : 'jstring', |
417 'java/lang/String' : 'jstring', | 430 'java/lang/String' : 'jstring', |
418 'Throwable': 'jthrowable', | 431 'Throwable': 'jthrowable', |
419 'java/lang/Throwable': 'jthrowable', | 432 'java/lang/Throwable': 'jthrowable', |
420 'boolean[]': 'jbooleanArray', | 433 'boolean[]': 'jbooleanArray', |
421 'byte[]': 'jbyteArray', | 434 'byte[]': 'jbyteArray', |
422 'char[]': 'jcharArray', | 435 'char[]': 'jcharArray', |
423 'short[]': 'jshortArray', | 436 'short[]': 'jshortArray', |
424 'int[]': 'jintArray', | 437 'int[]': 'jintArray', |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
627 continue | 640 continue |
628 value = re.match(re_constant_field_value, contents[lineno + 2]) | 641 value = re.match(re_constant_field_value, contents[lineno + 2]) |
629 if not value: | 642 if not value: |
630 value = re.match(re_constant_field_value, contents[lineno + 3]) | 643 value = re.match(re_constant_field_value, contents[lineno + 3]) |
631 if value: | 644 if value: |
632 self.constant_fields.append( | 645 self.constant_fields.append( |
633 ConstantField(name=match.group('name'), | 646 ConstantField(name=match.group('name'), |
634 value=value.group('value'))) | 647 value=value.group('value'))) |
635 | 648 |
636 self.inl_header_file_generator = InlHeaderFileGenerator( | 649 self.inl_header_file_generator = InlHeaderFileGenerator( |
637 self.namespace, self.fully_qualified_class, [], | 650 self.namespace, self.fully_qualified_class, [], self.called_by_natives, |
638 self.called_by_natives, self.constant_fields, options) | 651 self.constant_fields, options) |
639 | 652 |
640 def GetContent(self): | 653 def GetContent(self): |
641 return self.inl_header_file_generator.GetContent() | 654 return self.inl_header_file_generator.GetContent() |
642 | 655 |
643 @staticmethod | 656 @staticmethod |
644 def CreateFromClass(class_file, options): | 657 def CreateFromClass(class_file, options): |
645 class_name = os.path.splitext(os.path.basename(class_file))[0] | 658 class_name = os.path.splitext(os.path.basename(class_file))[0] |
646 p = subprocess.Popen(args=[options.javap, '-c', '-verbose', | 659 p = subprocess.Popen(args=[options.javap, '-c', '-verbose', |
647 '-s', class_name], | 660 '-s', class_name], |
648 cwd=os.path.dirname(class_file), | 661 cwd=os.path.dirname(class_file), |
(...skipping 13 matching lines...) Expand all Loading... |
662 r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', | 675 r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', |
663 re.DOTALL | re.MULTILINE) | 676 re.DOTALL | re.MULTILINE) |
664 | 677 |
665 def __init__(self, contents, fully_qualified_class, options): | 678 def __init__(self, contents, fully_qualified_class, options): |
666 contents = self._RemoveComments(contents) | 679 contents = self._RemoveComments(contents) |
667 JniParams.SetFullyQualifiedClass(fully_qualified_class) | 680 JniParams.SetFullyQualifiedClass(fully_qualified_class) |
668 JniParams.ExtractImportsAndInnerClasses(contents) | 681 JniParams.ExtractImportsAndInnerClasses(contents) |
669 jni_namespace = ExtractJNINamespace(contents) or options.namespace | 682 jni_namespace = ExtractJNINamespace(contents) or options.namespace |
670 natives = ExtractNatives(contents, options.ptr_type) | 683 natives = ExtractNatives(contents, options.ptr_type) |
671 called_by_natives = ExtractCalledByNatives(contents) | 684 called_by_natives = ExtractCalledByNatives(contents) |
| 685 maindex = IsMainDexJavaClass(contents) |
672 if len(natives) == 0 and len(called_by_natives) == 0: | 686 if len(natives) == 0 and len(called_by_natives) == 0: |
673 raise SyntaxError('Unable to find any JNI methods for %s.' % | 687 raise SyntaxError('Unable to find any JNI methods for %s.' % |
674 fully_qualified_class) | 688 fully_qualified_class) |
675 inl_header_file_generator = InlHeaderFileGenerator( | 689 inl_header_file_generator = InlHeaderFileGenerator( |
676 jni_namespace, fully_qualified_class, natives, called_by_natives, | 690 jni_namespace, fully_qualified_class, natives, called_by_natives, [], |
677 [], options) | 691 options, maindex) |
678 self.content = inl_header_file_generator.GetContent() | 692 self.content = inl_header_file_generator.GetContent() |
679 | 693 |
680 @classmethod | 694 @classmethod |
681 def _RemoveComments(cls, contents): | 695 def _RemoveComments(cls, contents): |
682 # We need to support both inline and block comments, and we need to handle | 696 # We need to support both inline and block comments, and we need to handle |
683 # strings that contain '//' or '/*'. | 697 # strings that contain '//' or '/*'. |
684 # TODO(bulach): This is a bit hacky. It would be cleaner to use a real Java | 698 # TODO(bulach): This is a bit hacky. It would be cleaner to use a real Java |
685 # parser. Maybe we could ditch JNIFromJavaSource and just always use | 699 # parser. Maybe we could ditch JNIFromJavaSource and just always use |
686 # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT. | 700 # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT. |
687 # http://code.google.com/p/chromium/issues/detail?id=138941 | 701 # http://code.google.com/p/chromium/issues/detail?id=138941 |
(...skipping 15 matching lines...) Expand all Loading... |
703 contents = file(java_file_name).read() | 717 contents = file(java_file_name).read() |
704 fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name, | 718 fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name, |
705 contents) | 719 contents) |
706 return JNIFromJavaSource(contents, fully_qualified_class, options) | 720 return JNIFromJavaSource(contents, fully_qualified_class, options) |
707 | 721 |
708 | 722 |
709 class InlHeaderFileGenerator(object): | 723 class InlHeaderFileGenerator(object): |
710 """Generates an inline header file for JNI integration.""" | 724 """Generates an inline header file for JNI integration.""" |
711 | 725 |
712 def __init__(self, namespace, fully_qualified_class, natives, | 726 def __init__(self, namespace, fully_qualified_class, natives, |
713 called_by_natives, constant_fields, options): | 727 called_by_natives, constant_fields, options, maindex='false'): |
714 self.namespace = namespace | 728 self.namespace = namespace |
715 self.fully_qualified_class = fully_qualified_class | 729 self.fully_qualified_class = fully_qualified_class |
716 self.class_name = self.fully_qualified_class.split('/')[-1] | 730 self.class_name = self.fully_qualified_class.split('/')[-1] |
717 self.natives = natives | 731 self.natives = natives |
718 self.called_by_natives = called_by_natives | 732 self.called_by_natives = called_by_natives |
719 self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' | 733 self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' |
720 self.constant_fields = constant_fields | 734 self.constant_fields = constant_fields |
| 735 self.maindex = maindex |
721 self.options = options | 736 self.options = options |
722 | 737 |
723 | 738 |
724 def GetContent(self): | 739 def GetContent(self): |
725 """Returns the content of the JNI binding file.""" | 740 """Returns the content of the JNI binding file.""" |
726 template = Template("""\ | 741 template = Template("""\ |
727 // Copyright 2014 The Chromium Authors. All rights reserved. | 742 // Copyright 2014 The Chromium Authors. All rights reserved. |
728 // Use of this source code is governed by a BSD-style license that can be | 743 // Use of this source code is governed by a BSD-style license that can be |
729 // found in the LICENSE file. | 744 // found in the LICENSE file. |
730 | 745 |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
855 ${REGISTER_NATIVES_SIGNATURE} { | 870 ${REGISTER_NATIVES_SIGNATURE} { |
856 ${EARLY_EXIT} | 871 ${EARLY_EXIT} |
857 ${NATIVES} | 872 ${NATIVES} |
858 return true; | 873 return true; |
859 } | 874 } |
860 """) | 875 """) |
861 signature = 'static bool RegisterNativesImpl(JNIEnv* env)' | 876 signature = 'static bool RegisterNativesImpl(JNIEnv* env)' |
862 early_exit = '' | 877 early_exit = '' |
863 if self.options.native_exports_optional: | 878 if self.options.native_exports_optional: |
864 early_exit = """\ | 879 early_exit = """\ |
865 if (base::android::IsManualJniRegistrationDisabled()) return true; | 880 if (jni_generator::ShouldSkipJniRegistration(%s)) |
866 """ | 881 return true; |
| 882 """ % self.maindex |
867 | 883 |
868 values = {'REGISTER_NATIVES_SIGNATURE': signature, | 884 values = {'REGISTER_NATIVES_SIGNATURE': signature, |
869 'EARLY_EXIT': early_exit, | 885 'EARLY_EXIT': early_exit, |
870 'NATIVES': natives, | 886 'NATIVES': natives, |
871 } | 887 } |
872 | 888 |
873 return template.substitute(values) | 889 return template.substitute(values) |
874 | 890 |
875 def GetRegisterNativesImplString(self): | 891 def GetRegisterNativesImplString(self): |
876 """Returns the shared implementation for RegisterNatives.""" | 892 """Returns the shared implementation for RegisterNatives.""" |
(...skipping 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1393 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1409 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1394 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1410 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1395 GenerateJNIHeader(input_file, output_file, options) | 1411 GenerateJNIHeader(input_file, output_file, options) |
1396 | 1412 |
1397 if options.depfile: | 1413 if options.depfile: |
1398 build_utils.WriteDepfile(options.depfile, output_file) | 1414 build_utils.WriteDepfile(options.depfile, output_file) |
1399 | 1415 |
1400 | 1416 |
1401 if __name__ == '__main__': | 1417 if __name__ == '__main__': |
1402 sys.exit(main(sys.argv)) | 1418 sys.exit(main(sys.argv)) |
OLD | NEW |