def _DictForPath(path, use_proxy_hash=False):
    with open(path) as f:
        contents = jni_generator.RemoveComments(f.read())
        if '@JniIgnoreNatives' in contents:
            return None

    fully_qualified_class = jni_generator.ExtractFullyQualifiedJavaClassName(
        path, contents)
    natives = jni_generator.ExtractNatives(contents, 'long')

    natives += jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
        fully_qualified_class=fully_qualified_class,
        contents=contents,
        ptr_type='long',
        use_hash=use_proxy_hash)
    if len(natives) == 0:
        return None
    namespace = jni_generator.ExtractJNINamespace(contents)
    jni_params = jni_generator.JniParams(fully_qualified_class)
    jni_params.ExtractImportsAndInnerClasses(contents)
    is_main_dex = jni_generator.IsMainDexJavaClass(contents)
    header_generator = HeaderGenerator(namespace, fully_qualified_class,
                                       natives, jni_params, is_main_dex,
                                       use_proxy_hash)
    return header_generator.Generate()
Пример #2
0
  def testFullyQualifiedClassName(self):
    contents = """
// Copyright (c) 2010 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.

package org.chromium.content.browser;

import org.chromium.base.BuildInfo;
"""
    self.assertEquals('org/chromium/content/browser/Foo',
                      jni_generator.ExtractFullyQualifiedJavaClassName(
                          'org/chromium/content/browser/Foo.java', contents))
    self.assertEquals('org/chromium/content/browser/Foo',
                      jni_generator.ExtractFullyQualifiedJavaClassName(
                          'frameworks/Foo.java', contents))
    self.assertRaises(SyntaxError,
                      jni_generator.ExtractFullyQualifiedJavaClassName,
                      'com/foo/Bar', 'no PACKAGE line')
Пример #3
0
def _DictForPath(path):
    with open(path) as f:
        contents = jni_generator.RemoveComments(f.read())
    natives = jni_generator.ExtractNatives(contents, 'long')
    if len(natives) == 0:
        return None
    namespace = jni_generator.ExtractJNINamespace(contents)
    fully_qualified_class = jni_generator.ExtractFullyQualifiedJavaClassName(
        path, contents)
    jni_params = jni_generator.JniParams(fully_qualified_class)
    jni_params.ExtractImportsAndInnerClasses(contents)
    main_dex = jni_generator.IsMainDexJavaClass(contents)
    header_generator = HeaderGenerator(namespace, fully_qualified_class,
                                       natives, jni_params, main_dex)
    return header_generator.Generate()
Пример #4
0
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 = {}
    # 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 = jni_generator.RemoveComments(f.read())
        natives = jni_generator.ExtractNatives(contents, 'long')
        if len(natives) == 0:
            continue
        namespace = jni_generator.ExtractJNINamespace(contents)
        fully_qualified_class = jni_generator.ExtractFullyQualifiedJavaClassName(
            path, contents)
        jni_params = jni_generator.JniParams(fully_qualified_class)
        jni_params.ExtractImportsAndInnerClasses(contents)
        main_dex = jni_generator.IsMainDexJavaClass(contents)
        header_generator = HeaderGenerator(namespace, fully_qualified_class,
                                           natives, jni_params,
                                           registration_dict, main_dex)
        header_generator.AddContent()

    header_content = CreateFromDict(registration_dict)
    if output_file:
        jni_generator.WriteOutput(output_file, header_content)
    else:
        print header_content
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
Пример #6
0
def convert_file_to_proxy_natives(java_file_name, dry=False, verbose=True):
    if not os.path.isfile(java_file_name):
        if verbose:
            print('%s does not exist', java_file_name)
        return

    with open(java_file_name, 'r') as f:
        contents = f.read()

    no_comment_content = jni_generator.RemoveComments(contents)
    natives = jni_generator.ExtractNatives(no_comment_content, 'long')

    static_natives = [n for n in natives if n.static]

    if not static_natives:
        if verbose:
            print('%s has no static natives.', java_file_name)
        return

    contents = add_chromium_import_to_java_file(contents, JNI_IMPORT_STRING)

    # Extract comments and annotations above native methods.
    native_map = {}
    for itr in re.finditer(_NATIVES_REGEX, contents):
        n_dict = {}
        n_dict['annotations'] = itr.group('annotations').strip()
        n_dict['comments'] = itr.group('comments').strip()
        n_dict['params'] = itr.group('params').strip()
        native_map[itr.group('name')] = n_dict

    # Using static natives here ensures all the methods that are picked up by
    # the JNI generator are also caught by our own regex.
    methods = []
    for n in static_natives:
        new_name = n.name[0].lower() + n.name[1:]
        n_dict = native_map['native' + n.name]
        params = n_dict['params']
        comments = n_dict['comments']
        annotations = n_dict['annotations']
        methods.append(
            build_method_declaration(n.return_type, new_name, params,
                                     annotations, comments))

    fully_qualified_class = jni_generator.ExtractFullyQualifiedJavaClassName(
        java_file_name, contents)
    class_name = fully_qualified_class.split('/')[-1]
    jni_class_name = class_name + 'Jni'

    # Remove all old declarations.
    for n in static_natives:
        pattern = _NATIVES_REGEX
        contents = re.sub(pattern, '', contents)

    # Replace occurences with new signature.
    for n in static_natives:
        # Okay not to match first (.
        # Since even if natives share a prefix, the replacement is the same.
        # E.g. if nativeFoo() and nativeFooBar() are both statics
        # and in nativeFooBar() we replace nativeFoo -> AJni.get().foo
        # the result is the same as replacing nativeFooBar() -> AJni.get().fooBar
        pattern = r'native%s' % n.name
        lower_name = n.name[0].lower() + n.name[1:]
        contents = re.sub(pattern,
                          '%s.get().%s' % (jni_class_name, lower_name),
                          contents)

    # Build and insert the @NativeMethods interface.
    interface = _JNI_INTERFACE_TEMPLATES.substitute({
        'INTERFACE_NAME': 'Natives',
        'METHODS': ''.join(methods)
    })

    # Insert the interface at the bottom of the top level class.
    # Most of the time this will be before the last }.
    insertion_point = contents.rfind('}')
    contents = contents[:insertion_point] + '\n' + interface + contents[
        insertion_point:]

    if not dry:
        with open(java_file_name, 'w') as f:
            f.write(contents)
    else:
        print(contents)
    return contents
Пример #7
0
def convert_nonstatic_to_static(java_file_name, dry=False, verbose=True):
    if java_file_name is None:
        return
    if not os.path.isfile(java_file_name):
        if verbose:
            print('%s does not exist', java_file_name)
        return

    with open(java_file_name, 'r') as f:
        contents = f.read()

    no_comment_content = jni_generator.RemoveComments(contents)
    parsed_natives = jni_generator.ExtractNatives(no_comment_content, 'long')
    non_static_natives = [n for n in parsed_natives if not n.static]
    if not non_static_natives:
        if verbose:
            print('no natives found')
        return

    class_name = jni_generator.ExtractFullyQualifiedJavaClassName(
        java_file_name, no_comment_content).split('/')[-1]

    replace_patterns = []
    should_add_comma = []

    new_contents = contents

    # 1. Change non-static -> static.
    insertion_offset = 0

    matches = []
    for match in _NON_STATIC_NATIVES_REGEX.finditer(contents):
        if not 'static' in match.group('qualifiers'):
            matches.append(match)
            # Insert static as a keyword.
            qual_end = match.end('qualifiers') + insertion_offset
            insert_str = ' static '
            new_contents = new_contents[:qual_end] + insert_str + new_contents[
                qual_end:]
            insertion_offset += len(insert_str)

            # Insert an object param.
            start = insertion_offset + match.end('params')
            insert_str = '%s caller' % class_name
            if match.group('params'):
                insert_str = ', ' + insert_str

            # Match lines that don't have a native keyword.
            replace_patterns.append(r'(^\s*' + match.group('name') +
                                    r'\(.*?(?=\)))')
            replace_patterns.append(r'(return ' + match.group('name') +
                                    r'\(.*?(?=\)))')
            replace_patterns.append(r'([\:\)\(\+\*\?\&\|,\.\-\=\!\/][ \t]*' +
                                    match.group('name') + r'\(.*?(?=\)))')

            add_comma = bool(match.group('params'))
            should_add_comma.extend([add_comma] * 3)

            new_contents = new_contents[:start] + insert_str + new_contents[
                start:]
            insertion_offset += len(insert_str)

    assert len(matches) == len(non_static_natives), (
        'Regex missed a native '
        'method that was found by '
        'the jni_generator.')

    # 2. Add a this param to all calls.
    for i, r in enumerate(replace_patterns):
        if should_add_comma[i]:
            new_contents = re.sub(r,
                                  '\g<1>, %s.this' % class_name,
                                  new_contents,
                                  flags=re.MULTILINE)
        else:
            new_contents = re.sub(r,
                                  '\g<1>%s.this' % class_name,
                                  new_contents,
                                  flags=re.MULTILINE)

    if dry:
        print(new_contents)
    else:
        with open(java_file_name, 'w') as f:
            f.write(new_contents)
Пример #8
0
def convert_nonstatic_to_static(java_file_name,
                                skip_caller=False,
                                dry=False,
                                verbose=True):
    if java_file_name is None:
        return
    if not os.path.isfile(java_file_name):
        if verbose:
            print('%s does not exist', java_file_name)
        return

    with open(java_file_name, 'r') as f:
        contents = f.read()

    no_comment_content = jni_generator.RemoveComments(contents)
    parsed_natives = jni_generator.ExtractNatives(no_comment_content, 'long')
    non_static_natives = [n for n in parsed_natives if not n.static]
    if not non_static_natives:
        if verbose:
            print('no natives found')
        return

    class_name = jni_generator.ExtractFullyQualifiedJavaClassName(
        java_file_name, no_comment_content).split('/')[-1]

    # For fixing call sites.
    replace_patterns = []
    should_append_comma = []
    should_prepend_comma = []

    new_contents = contents

    # 1. Change non-static -> static.
    insertion_offset = 0

    matches = []
    for match in _NON_STATIC_NATIVES_REGEX.finditer(contents):
        if not 'static' in match.group('qualifiers'):
            matches.append(match)
            # Insert static as a keyword.
            qual_end = match.end('qualifiers') + insertion_offset
            insert_str = ' static '
            new_contents = new_contents[:qual_end] + insert_str + new_contents[
                qual_end:]
            insertion_offset += len(insert_str)

            if skip_caller:
                continue

            # Insert an object param.
            insert_str = '%s caller' % class_name
            # No params.
            if not match.group('params'):
                start = insertion_offset + match.start('params')
                append_comma = False
                prepend_comma = False

            # One or more params.
            else:
                # Has mNativePtr.
                if _NATIVE_PTR_REGEX.match(match.group('params')):
                    # Only 1 param, append to end of params.
                    if match.group('params').count(',') == 0:
                        start = insertion_offset + match.end('params')
                        append_comma = False
                        prepend_comma = True
                    # Multiple params, insert after first param.
                    else:
                        comma_pos = match.group('params').find(',')
                        start = insertion_offset + match.start(
                            'params') + comma_pos + 1
                        append_comma = True
                        prepend_comma = False
                else:
                    # No mNativePtr, insert as first param.
                    start = insertion_offset + match.start('params')
                    append_comma = True
                    prepend_comma = False

            if prepend_comma:
                insert_str = ', ' + insert_str
            if append_comma:
                insert_str = insert_str + ', '
            new_contents = new_contents[:start] + insert_str + new_contents[
                start:]

            # Match lines that don't have a native keyword.
            native_match = r'\((\s*?(([ms]Native\w+)|([ms]\w+Android(Ptr)?)),?)?)'
            replace_patterns.append(r'(^\s*' + match.group('name') +
                                    native_match)
            replace_patterns.append(r'(return ' + match.group('name') +
                                    native_match)
            replace_patterns.append(r'([\:\)\(\+\*\?\&\|,\.\-\=\!\/][ \t]*' +
                                    match.group('name') + native_match)

            should_append_comma.extend([append_comma] * 3)
            should_prepend_comma.extend([prepend_comma] * 3)
            insertion_offset += len(insert_str)

    assert len(matches) == len(non_static_natives), (
        'Regex missed a native '
        'method that was found by '
        'the jni_generator.')

    # 2. Add a this param to all calls.
    for i, r in enumerate(replace_patterns):
        prepend_comma = ', ' if should_prepend_comma[i] else ''
        append_comma = ', ' if should_append_comma[i] else ''
        repl_str = '\g<1>' + prepend_comma + ' %s.this' + append_comma
        new_contents = re.sub(r,
                              repl_str % class_name,
                              new_contents,
                              flags=re.MULTILINE)

    if dry:
        print(new_contents)
    else:
        with open(java_file_name, 'w') as f:
            f.write(new_contents)