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 # TODO (qinmin): Need to refactor this file as base should not know about | 6 # TODO (qinmin): Need to refactor this file as base should not know about |
7 # higher level concepts. Currently this file has knowledge about higher level | 7 # higher level concepts. Currently this file has knowledge about higher level |
8 # java classes. | 8 # java classes. |
9 | 9 |
10 """Extracts native methods from a Java file and generates the JNI bindings. | 10 """Extracts native methods from a Java file and generates the JNI bindings. |
11 If you change this, please run and update the tests.""" | 11 If you change this, please run and update the tests.""" |
12 | 12 |
13 import collections | 13 import collections |
14 import optparse | 14 import optparse |
15 import os | 15 import os |
16 import re | 16 import re |
17 import string | 17 import string |
18 from string import Template | 18 from string import Template |
19 import subprocess | 19 import subprocess |
20 import sys | 20 import sys |
21 import textwrap | 21 import textwrap |
22 import zipfile | 22 import zipfile |
23 | 23 |
24 UNKNOWN_JAVA_TYPE_PREFIX = 'UNKNOWN_JAVA_TYPE: ' | 24 UNKNOWN_JAVA_TYPE_PREFIX = 'UNKNOWN_JAVA_TYPE: ' |
25 | 25 EXTERNAL_PARAM_LIST = [] |
26 | 26 |
27 class ParseError(Exception): | 27 class ParseError(Exception): |
28 """Exception thrown when we can't parse the input file.""" | 28 """Exception thrown when we can't parse the input file.""" |
29 | 29 |
30 def __init__(self, description, *context_lines): | 30 def __init__(self, description, *context_lines): |
31 Exception.__init__(self) | 31 Exception.__init__(self) |
32 self.description = description | 32 self.description = description |
33 self.context_lines = context_lines | 33 self.context_lines = context_lines |
34 | 34 |
35 def __str__(self): | 35 def __str__(self): |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
133 'Ljava/util/ArrayList', | 133 'Ljava/util/ArrayList', |
134 'Ljava/util/HashMap', | 134 'Ljava/util/HashMap', |
135 'Ljava/util/List', | 135 'Ljava/util/List', |
136 'Landroid/content/Context', | 136 'Landroid/content/Context', |
137 'Landroid/graphics/Bitmap', | 137 'Landroid/graphics/Bitmap', |
138 'Landroid/graphics/Canvas', | 138 'Landroid/graphics/Canvas', |
139 'Landroid/graphics/Rect', | 139 'Landroid/graphics/Rect', |
140 'Landroid/graphics/RectF', | 140 'Landroid/graphics/RectF', |
141 'Landroid/graphics/Matrix', | 141 'Landroid/graphics/Matrix', |
142 'Landroid/graphics/Point', | 142 'Landroid/graphics/Point', |
143 'Landroid/graphics/SurfaceTexture', | |
143 'Landroid/graphics/SurfaceTexture$OnFrameAvailableListener', | 144 'Landroid/graphics/SurfaceTexture$OnFrameAvailableListener', |
144 'Landroid/media/MediaPlayer', | 145 'Landroid/media/MediaPlayer', |
145 'Landroid/os/Message', | 146 'Landroid/os/Message', |
146 'Landroid/view/KeyEvent', | 147 'Landroid/view/KeyEvent', |
147 'Landroid/view/Surface', | 148 'Landroid/view/Surface', |
148 'Landroid/view/View', | 149 'Landroid/view/View', |
149 'Landroid/webkit/ValueCallback', | 150 'Landroid/webkit/ValueCallback', |
150 'Ljava/io/InputStream', | 151 'Ljava/io/InputStream', |
151 'Ljava/nio/ByteBuffer', | 152 'Ljava/nio/ByteBuffer', |
152 'Ljava/util/Vector', | 153 'Ljava/util/Vector', |
153 ] | 154 ] |
154 app_param_list = [ | |
155 'Landroid/graphics/SurfaceTexture', | |
156 'Lcom/google/android/apps/chrome/ChromeContextMenuInfo', | |
157 'Lcom/google/android/apps/chrome/ChromeWindow', | |
158 'Lcom/google/android/apps/chrome/GoogleLocationSettingsHelperImpl', | |
159 'Lcom/google/android/apps/chrome/OmniboxSuggestion', | |
160 'Lcom/google/android/apps/chrome/PageInfoViewer', | |
161 'Lcom/google/android/apps/chrome/Tab', | |
162 'Lcom/google/android/apps/chrome/infobar/AutoLogin', | |
163 'Lcom/google/android/apps/chrome/infobar/InfoBarContainer', | |
164 'Lcom/google/android/apps/chrome/infobar/InfoBarContainer$NativeInfoBar', | |
165 ('Lcom/google/android/apps/chrome/preferences/ChromeNativePreferences$' | |
166 'PasswordListObserver'), | |
167 'Lorg/chromium/android_webview/AwContents', | |
168 'Lorg/chromium/android_webview/AwContentsClient', | |
169 'Lorg/chromium/android_webview/AwHttpAuthHandler', | |
170 'Lorg/chromium/android_webview/AwContentsIoThreadClient', | |
171 'Lorg/chromium/android_webview/AwWebContentsDelegate', | |
172 'Lorg/chromium/android_webview/InterceptedRequestData', | |
173 'Lorg/chromium/android_webview/JsPromptResultReceiver', | |
174 'Lorg/chromium/android_webview/JsResultHandler', | |
175 'Lorg/chromium/android_webview/JsResultReceiver', | |
176 'Lorg/chromium/base/SystemMessageHandler', | |
177 'Lorg/chromium/chrome/browser/autofill/AutofillExternalDelegate', | |
178 'Lorg/chromium/chrome/browser/autofill/AutofillSuggestion', | |
179 'Lorg/chromium/chrome/browser/ChromeBrowserProvider$BookmarkNode', | |
180 'Lorg/chromium/chrome/browser/ChromeHttpAuthHandler', | |
181 'Lorg/chromium/chrome/browser/ChromeWebContentsDelegateAndroid', | |
182 'Lorg/chromium/chrome/browser/FindMatchRectsDetails', | |
183 'Lorg/chromium/chrome/browser/FindNotificationDetails', | |
184 'Lorg/chromium/chrome/browser/GoogleLocationSettingsHelper', | |
185 'Lorg/chromium/chrome/browser/GoogleLocationSettingsHelperStub', | |
186 'Lorg/chromium/chrome/browser/JavascriptAppModalDialog', | |
187 'Lorg/chromium/chrome/browser/ProcessUtils', | |
188 ('Lorg/chromium/chrome/browser/component/navigation_interception/' | |
189 'InterceptNavigationDelegate'), | |
190 ('Lorg/chromium/chrome/browser/component/web_contents_delegate_android/' | |
191 'WebContentsDelegateAndroid'), | |
192 'Lorg/chromium/chrome/browser/database/SQLiteCursor', | |
193 'Lorg/chromium/content/app/SandboxedProcessService', | |
194 'Lorg/chromium/content/browser/ContainerViewDelegate', | |
195 'Lorg/chromium/content/browser/ContentVideoView', | |
196 'Lorg/chromium/content/browser/ContentViewCore', | |
197 'Lorg/chromium/content/browser/DeviceOrientation', | |
198 'Lorg/chromium/content/browser/JavaInputStream', | |
199 'Lorg/chromium/content/browser/LocationProvider', | |
200 'Lorg/chromium/content/browser/SandboxedProcessArgs', | |
201 'Lorg/chromium/content/browser/SandboxedProcessConnection', | |
202 'Lorg/chromium/content/browser/TouchPoint', | |
203 'Lorg/chromium/content/browser/WaitableNativeEvent', | |
204 'Lorg/chromium/content/browser/WebContentsObserverAndroid', | |
205 'Lorg/chromium/content/common/DeviceInfo', | |
206 'Lorg/chromium/content/common/SurfaceTextureListener', | |
207 'Lorg/chromium/media/MediaPlayerListener', | |
208 'Lorg/chromium/net/NetworkChangeNotifier', | |
209 'Lorg/chromium/net/ProxyChangeListener', | |
210 'Lorg/chromium/ui/gfx/NativeWindow', | |
211 'Lorg/chromium/ui/SelectFileDialog', | |
212 ] | |
213 if param == 'byte[][]': | 155 if param == 'byte[][]': |
214 return '[[B' | 156 return '[[B' |
215 prefix = '' | 157 prefix = '' |
216 # Array? | 158 # Array? |
217 if param[-2:] == '[]': | 159 if param[-2:] == '[]': |
218 prefix = '[' | 160 prefix = '[' |
219 param = param[:-2] | 161 param = param[:-2] |
220 # Generic? | 162 # Generic? |
221 if '<' in param: | 163 if '<' in param: |
222 param = param[:param.index('<')] | 164 param = param[:param.index('<')] |
223 if param in pod_param_map: | 165 if param in pod_param_map: |
224 return prefix + pod_param_map[param] | 166 return prefix + pod_param_map[param] |
225 if '/' in param: | 167 if '/' in param: |
226 # Coming from javap, use the fully qualified param directly. | 168 # Coming from javap, use the fully qualified param directly. |
227 return 'L' + param + ';' | 169 return 'L' + param + ';' |
228 for qualified_name in object_param_list + app_param_list: | 170 for qualified_name in object_param_list + EXTERNAL_PARAM_LIST: |
Nico
2012/10/30 19:47:36
CAPS_NAMES are usually constants, which this isn't
bulach
2012/10/31 10:17:02
good points, thanks nico!
I refactored this a bit
| |
229 if (qualified_name.endswith('/' + param) or | 171 if (qualified_name.endswith('/' + param) or |
230 qualified_name.endswith('$' + param.replace('.', '$')) or | 172 qualified_name.endswith('$' + param.replace('.', '$')) or |
231 qualified_name == 'L' + param): | 173 qualified_name == 'L' + param): |
232 return prefix + qualified_name + ';' | 174 return prefix + qualified_name + ';' |
233 else: | 175 else: |
234 return UNKNOWN_JAVA_TYPE_PREFIX + prefix + param + ';' | 176 return UNKNOWN_JAVA_TYPE_PREFIX + prefix + param + ';' |
235 | 177 |
236 | 178 |
237 def JniSignature(params, returns, wrap): | 179 def JniSignature(params, returns, wrap): |
238 """Returns the JNI signature for the given datatypes.""" | 180 """Returns the JNI signature for the given datatypes.""" |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
559 self.fully_qualified_class = fully_qualified_class | 501 self.fully_qualified_class = fully_qualified_class |
560 self.class_name = self.fully_qualified_class.split('/')[-1] | 502 self.class_name = self.fully_qualified_class.split('/')[-1] |
561 self.natives = natives | 503 self.natives = natives |
562 self.called_by_natives = called_by_natives | 504 self.called_by_natives = called_by_natives |
563 self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' | 505 self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' |
564 unknown_datatypes = GetUnknownDatatypes(self.natives + | 506 unknown_datatypes = GetUnknownDatatypes(self.natives + |
565 self.called_by_natives) | 507 self.called_by_natives) |
566 if unknown_datatypes: | 508 if unknown_datatypes: |
567 msg = ('There are a few unknown datatypes in %s' % | 509 msg = ('There are a few unknown datatypes in %s' % |
568 self.fully_qualified_class) | 510 self.fully_qualified_class) |
569 msg += '\nPlease, edit %s' % sys.argv[0] | 511 msg += '\nPlease, edit %s' % sys.argv[0] |
Yaron
2012/10/30 19:42:36
Actually, with this change, this will no longer be
bulach
2012/10/31 10:17:02
Done.
| |
570 msg += '\nand add the java type to JavaParamToJni()\n' | 512 msg += '\nand add the java type to JavaParamToJni()\n' |
571 for unknown_datatype in unknown_datatypes: | 513 for unknown_datatype in unknown_datatypes: |
572 msg += '\n%s in methods:\n' % unknown_datatype | 514 msg += '\n%s in methods:\n' % unknown_datatype |
573 msg += '\n '.join(unknown_datatypes[unknown_datatype]) | 515 msg += '\n '.join(unknown_datatypes[unknown_datatype]) |
574 raise SyntaxError(msg) | 516 raise SyntaxError(msg) |
575 | 517 |
576 def GetContent(self): | 518 def GetContent(self): |
577 """Returns the content of the JNI binding file.""" | 519 """Returns the content of the JNI binding file.""" |
578 template = Template("""\ | 520 template = Template("""\ |
579 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 521 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
(...skipping 424 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1004 sys.exit(1) | 946 sys.exit(1) |
1005 if output_file: | 947 if output_file: |
1006 if not os.path.exists(os.path.dirname(os.path.abspath(output_file))): | 948 if not os.path.exists(os.path.dirname(os.path.abspath(output_file))): |
1007 os.makedirs(os.path.dirname(os.path.abspath(output_file))) | 949 os.makedirs(os.path.dirname(os.path.abspath(output_file))) |
1008 with file(output_file, 'w') as f: | 950 with file(output_file, 'w') as f: |
1009 f.write(content) | 951 f.write(content) |
1010 else: | 952 else: |
1011 print output | 953 print output |
1012 | 954 |
1013 | 955 |
956 def ReadExtraAppParamList(external_param_files): | |
957 if not external_param_files: | |
958 return | |
959 for external_param_file in set(external_param_files): | |
960 with file(external_param_file, 'r') as f: | |
961 contents = f.read() | |
962 global EXTERNAL_PARAM_LIST | |
963 EXTERNAL_PARAM_LIST += [x.strip() for x in contents.splitlines() | |
964 if x and not x.startswith('#')] | |
965 | |
966 | |
1014 def main(argv): | 967 def main(argv): |
1015 usage = """usage: %prog [OPTIONS] | 968 usage = """usage: %prog [OPTIONS] |
1016 This script will parse the given java source code extracting the native | 969 This script will parse the given java source code extracting the native |
1017 declarations and print the header file to stdout (or a file). | 970 declarations and print the header file to stdout (or a file). |
1018 See SampleForTests.java for more details. | 971 See SampleForTests.java for more details. |
1019 """ | 972 """ |
1020 option_parser = optparse.OptionParser(usage=usage) | 973 option_parser = optparse.OptionParser(usage=usage) |
1021 option_parser.add_option('-j', dest='jar_file', | 974 option_parser.add_option('-j', dest='jar_file', |
1022 help='Extract the list of input files from' | 975 help='Extract the list of input files from' |
1023 ' a specified jar file.' | 976 ' a specified jar file.' |
1024 ' Uses javap to extract the methods from a' | 977 ' Uses javap to extract the methods from a' |
1025 ' pre-compiled class. --input should point' | 978 ' pre-compiled class. --input should point' |
1026 ' to pre-compiled Java .class files.') | 979 ' to pre-compiled Java .class files.') |
1027 option_parser.add_option('-n', dest='namespace', | 980 option_parser.add_option('-n', dest='namespace', |
1028 help='Uses as a namespace in the generated header,' | 981 help='Uses as a namespace in the generated header,' |
1029 ' instead of the javap class name.') | 982 ' instead of the javap class name.') |
1030 option_parser.add_option('--input_file', | 983 option_parser.add_option('--input_file', |
1031 help='Single input file name. The output file name ' | 984 help='Single input file name. The output file name ' |
1032 'will be derived from it. Must be used with ' | 985 'will be derived from it. Must be used with ' |
1033 '--output_dir.') | 986 '--output_dir.') |
1034 option_parser.add_option('--output_dir', | 987 option_parser.add_option('--output_dir', |
1035 help='The output directory. Must be used with ' | 988 help='The output directory. Must be used with ' |
1036 '--input') | 989 '--input') |
990 option_parser.add_option('--external_param_list', | |
991 help='A file name containing a list with extra ' | |
992 'fully-qualified param names. Can be used multiple ' | |
993 'times.', | |
994 action='append') | |
1037 options, args = option_parser.parse_args(argv) | 995 options, args = option_parser.parse_args(argv) |
996 ReadExtraAppParamList(options.external_param_list) | |
1038 if options.jar_file: | 997 if options.jar_file: |
1039 input_file = ExtractJarInputFile(options.jar_file, options.input_file, | 998 input_file = ExtractJarInputFile(options.jar_file, options.input_file, |
1040 options.output_dir) | 999 options.output_dir) |
1041 else: | 1000 else: |
1042 input_file = options.input_file | 1001 input_file = options.input_file |
1043 output_file = None | 1002 output_file = None |
1044 if options.output_dir: | 1003 if options.output_dir: |
1045 root_name = os.path.splitext(os.path.basename(input_file))[0] | 1004 root_name = os.path.splitext(os.path.basename(input_file))[0] |
1046 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' | 1005 output_file = os.path.join(options.output_dir, root_name) + '_jni.h' |
1047 GenerateJNIHeader(input_file, output_file, options.namespace) | 1006 GenerateJNIHeader(input_file, output_file, options.namespace) |
1048 | 1007 |
1049 | 1008 |
1050 if __name__ == '__main__': | 1009 if __name__ == '__main__': |
1051 sys.exit(main(sys.argv)) | 1010 sys.exit(main(sys.argv)) |
OLD | NEW |