| #!/usr/bin/env python |
| # Copyright 2017 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Generate JNI registration entry points |
| |
| Creates a header file with two static functions: RegisterMainDexNatives() and |
| RegisterNonMainDexNatives(). Together, these will use manual JNI registration |
| to register all native methods that exist within an application.""" |
| |
| import argparse |
| import jni_generator |
| import os |
| import string |
| import sys |
| from util import build_utils |
| |
| |
| def GenerateJNIHeader(java_file_paths, output_file, args): |
| """Generate a header file including two registration functions. |
| |
| Forward declares all JNI registration functions created by jni_generator.py. |
| Calls the functions in RegisterMainDexNatives() if they are main dex. And |
| calls them in RegisterNonMainDexNatives() if they are non-main dex. |
| |
| Args: |
| java_file_paths: A list of java file paths. |
| output_file: A relative path to output file. |
| args: All input arguments. |
| """ |
| registration_dict = { |
| 'FORWARD_DECLARATIONS': '', |
| 'REGISTER_MAIN_DEX_NATIVES': '', |
| 'REGISTER_NON_MAIN_DEX_NATIVES': '' |
| } |
| # Sort the file list to make sure the order is deterministic. |
| java_file_paths.sort() |
| for path in java_file_paths: |
| if path in args.no_register_java: |
| continue |
| with open(path) as f: |
| contents = f.read() |
| natives = jni_generator.ExtractNatives(contents, 'long') |
| if len(natives) == 0: |
| continue |
| fully_qualified_class = jni_generator.ExtractFullyQualifiedJavaClassName( |
| path, contents) |
| main_dex = jni_generator.IsMainDexJavaClass(contents) |
| header_generator = HeaderGenerator( |
| fully_qualified_class, registration_dict, main_dex) |
| registration_dict = header_generator.GetContent() |
| |
| header_content = CreateFromDict(registration_dict) |
| if output_file: |
| jni_generator.WriteOutput(output_file, header_content) |
| else: |
| print header_content |
| |
| |
| def CreateFromDict(registration_dict): |
| """Returns the content of the header file.""" |
| |
| template = string.Template("""\ |
| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| |
| // This file is autogenerated by |
| // base/android/jni_generator/jni_registration_generator.py |
| // Please do not change its content. |
| |
| #ifndef HEADER_GUARD |
| #define HEADER_GUARD |
| |
| #include <jni.h> |
| |
| #include "base/android/jni_generator/jni_generator_helper.h" |
| #include "base/android/jni_int_wrapper.h" |
| |
| // Step 1: Forward declaration. |
| ${FORWARD_DECLARATIONS} |
| |
| // Step 2: Main dex and non-main dex registration functions. |
| |
| bool RegisterMainDexNatives(JNIEnv* env) { |
| ${REGISTER_MAIN_DEX_NATIVES} |
| |
| return true; |
| } |
| |
| bool RegisterNonMainDexNatives(JNIEnv* env) { |
| ${REGISTER_NON_MAIN_DEX_NATIVES} |
| |
| return true; |
| } |
| |
| #endif // HEADER_GUARD |
| """) |
| if len(registration_dict['FORWARD_DECLARATIONS']) == 0: |
| return '' |
| return jni_generator.WrapOutput(template.substitute(registration_dict)) |
| |
| |
| class HeaderGenerator(object): |
| """Generates an inline header file for JNI registration.""" |
| |
| def __init__(self, fully_qualified_class, registration_dict, main_dex): |
| self.fully_qualified_class = fully_qualified_class |
| self.class_name = self.fully_qualified_class.split('/')[-1] |
| self.registration_dict = registration_dict |
| self.main_dex = main_dex |
| |
| def GetContent(self): |
| self._AddForwardDeclaration() |
| self._AddRegisterNatives() |
| return self.registration_dict |
| |
| def _AddForwardDeclaration(self): |
| """Add the content of the forward declaration to the dictionary.""" |
| template = string.Template('JNI_REGISTRATION_EXPORT bool ${METHOD_NAME}(' |
| 'JNIEnv* env);\n') |
| value = { |
| 'METHOD_NAME': |
| jni_generator.GetRegistrationFunctionName( |
| self.fully_qualified_class) |
| } |
| self.registration_dict['FORWARD_DECLARATIONS'] += template.substitute(value) |
| |
| def _AddRegisterNatives(self): |
| """Add the body of the RegisterNativesImpl method to the dictionary.""" |
| template = string.Template(""" |
| if (!${REGISTER_NAME}(env)) |
| return false; |
| """) |
| value = { |
| 'REGISTER_NAME': |
| jni_generator.GetRegistrationFunctionName( |
| self.fully_qualified_class) |
| } |
| register_body = template.substitute(value) |
| if self.main_dex: |
| self.registration_dict['REGISTER_MAIN_DEX_NATIVES'] += register_body |
| else: |
| self.registration_dict['REGISTER_NON_MAIN_DEX_NATIVES'] += register_body |
| |
| |
| def main(argv): |
| arg_parser = argparse.ArgumentParser() |
| build_utils.AddDepfileOption(arg_parser) |
| |
| arg_parser.add_argument('--sources_files', |
| help='A list of .sources files which contain Java ' |
| 'file paths. Must be used with --output.') |
| arg_parser.add_argument('--output', |
| help='The output file path.') |
| arg_parser.add_argument('--no_register_java', |
| help='A list of Java files which should be ignored ' |
| 'by the parser.') |
| args = arg_parser.parse_args(build_utils.ExpandFileArgs(argv[1:])) |
| args.sources_files = build_utils.ParseGnList(args.sources_files) |
| |
| if args.sources_files: |
| java_file_paths = [] |
| for f in args.sources_files: |
| # java_file_paths stores each Java file path as a string. |
| java_file_paths += build_utils.ReadSourcesList(f) |
| else: |
| print '\nError: Must specify --sources_files.' |
| return 1 |
| output_file = args.output |
| GenerateJNIHeader(java_file_paths, output_file, args) |
| |
| if args.depfile: |
| build_utils.WriteDepfile(args.depfile, output_file) |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv)) |