http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jniprebuild/jni_generator.py ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jniprebuild/jni_generator.py b/weex_core/Source/android/jniprebuild/jni_generator.py new file mode 100644 index 0000000..43a8a43 --- /dev/null +++ b/weex_core/Source/android/jniprebuild/jni_generator.py @@ -0,0 +1,1469 @@ +#!/usr/bin/env python +# Copyright (c) 2012 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. + +"""Extracts native methods from a Java file and generates the JNI bindings. +If you change this, please run and update the tests.""" + +import collections +import errno +import optparse +import os +import re +import string +from string import Template +import subprocess +import sys +import textwrap +import zipfile + + +class ParseError(Exception): + """Exception thrown when we can't parse the input file.""" + + def __init__(self, description, *context_lines): + Exception.__init__(self) + self.description = description + self.context_lines = context_lines + + def __str__(self): + context = '\n'.join(self.context_lines) + return '***\nERROR: %s\n\n%s\n***' % (self.description, context) + + +class Param(object): + """Describes a param for a method, either java or native.""" + + def __init__(self, **kwargs): + self.datatype = kwargs['datatype'] + self.name = kwargs['name'] + + +class NativeMethod(object): + """Describes a C/C++ method that is called by Java code""" + + def __init__(self, **kwargs): + self.static = kwargs['static'] + self.java_class_name = kwargs['java_class_name'] + self.return_type = kwargs['return_type'] + self.name = kwargs['name'] + self.params = kwargs['params'] + if self.params: + assert type(self.params) is list + assert type(self.params[0]) is Param + if (self.params and + self.params[0].datatype == kwargs.get('ptr_type', 'int') and + self.params[0].name.startswith('native')): + self.type = 'method' + self.p0_type = self.params[0].name[len('native'):] + if kwargs.get('native_class_name'): + self.p0_type = kwargs['native_class_name'] + else: + self.type = 'function' + self.method_id_var_name = kwargs.get('method_id_var_name', None) + + +class CalledByNative(object): + """Describes a java method exported to c/c++""" + + def __init__(self, **kwargs): + self.system_class = kwargs['system_class'] + self.unchecked = kwargs['unchecked'] + self.static = kwargs['static'] + self.java_class_name = kwargs['java_class_name'] + self.return_type = kwargs['return_type'] + self.name = kwargs['name'] + self.params = kwargs['params'] + self.method_id_var_name = kwargs.get('method_id_var_name', None) + self.signature = kwargs.get('signature') + self.is_constructor = kwargs.get('is_constructor', False) + self.env_call = GetEnvCall(self.is_constructor, self.static, + self.return_type) + self.static_cast = GetStaticCastForReturnType(self.return_type) + + +class ConstantField(object): + def __init__(self, **kwargs): + self.name = kwargs['name'] + self.value = kwargs['value'] + + +def JavaDataTypeToC(java_type): + """Returns a C datatype for the given java type.""" + java_pod_type_map = { + 'int': 'jint', + 'byte': 'jbyte', + 'char': 'jchar', + 'short': 'jshort', + 'boolean': 'jboolean', + 'long': 'jlong', + 'double': 'jdouble', + 'float': 'jfloat', + } + java_type_map = { + 'void': 'void', + 'String': 'jstring', + 'java/lang/String': 'jstring', + 'java/lang/Class': 'jclass', + } + + if java_type in java_pod_type_map: + return java_pod_type_map[java_type] + elif java_type in java_type_map: + return java_type_map[java_type] + elif java_type.endswith('[]'): + if java_type[:-2] in java_pod_type_map: + return java_pod_type_map[java_type[:-2]] + 'Array' + return 'jobjectArray' + elif java_type.startswith('Class'): + # Checking just the start of the name, rather than a direct comparison, + # in order to handle generics. + return 'jclass' + else: + return 'jobject' + + +def JavaDataTypeToCForCalledByNativeParam(java_type): + """Returns a C datatype to be when calling from native.""" + if java_type == 'int': + return 'int' + else: + return JavaDataTypeToC(java_type) + + +def JavaReturnValueToC(java_type): + """Returns a valid C return value for the given java type.""" + java_pod_type_map = { + 'int': '0', + 'byte': '0', + 'char': '0', + 'short': '0', + 'boolean': 'false', + 'long': '0', + 'double': '0', + 'float': '0', + 'void': '' + } + return java_pod_type_map.get(java_type, 'NULL') + + +class JniParams(object): + _imports = [] + _fully_qualified_class = '' + _package = '' + _inner_classes = [] + _remappings = [] + _implicit_imports = [] + + @staticmethod + def SetFullyQualifiedClass(fully_qualified_class): + JniParams._fully_qualified_class = 'L' + fully_qualified_class + JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1]) + + @staticmethod + def AddAdditionalImport(class_name): + assert class_name.endswith('.class') + raw_class_name = class_name[:-len('.class')] + if '.' in raw_class_name: + raise SyntaxError('%s cannot be used in @JNIAdditionalImport. ' + 'Only import unqualified outer classes.' % class_name) + new_import = 'L%s/%s' % (JniParams._package, raw_class_name) + if new_import in JniParams._imports: + raise SyntaxError('Do not use JNIAdditionalImport on an already ' + 'imported class: %s' % (new_import.replace('/', '.'))) + JniParams._imports += [new_import] + + @staticmethod + def ExtractImportsAndInnerClasses(contents): + if not JniParams._package: + raise RuntimeError('SetFullyQualifiedClass must be called before ' + 'ExtractImportsAndInnerClasses') + contents = contents.replace('\n', '') + re_import = re.compile(r'import.*?(?P<class>\S*?);') + for match in re.finditer(re_import, contents): + JniParams._imports += ['L' + match.group('class').replace('.', '/')] + + re_inner = re.compile(r'(class|interface)\s+?(?P<name>\w+?)\W') + for match in re.finditer(re_inner, contents): + inner = match.group('name') + if not JniParams._fully_qualified_class.endswith(inner): + JniParams._inner_classes += [JniParams._fully_qualified_class + '$' + + inner] + + re_additional_imports = re.compile( + r'@JNIAdditionalImport\(\s*{?(?P<class_names>.*?)}?\s*\)') + for match in re.finditer(re_additional_imports, contents): + for class_name in match.group('class_names').split(','): + JniParams.AddAdditionalImport(class_name.strip()) + + @staticmethod + def ParseJavaPSignature(signature_line): + prefix = 'Signature: ' + index = signature_line.find(prefix) + if index == -1: + prefix = 'descriptor: ' + index = signature_line.index(prefix) + return '"%s"' % signature_line[index + len(prefix):] + + @staticmethod + def JavaToJni(param): + """Converts a java param into a JNI signature type.""" + pod_param_map = { + 'int': 'I', + 'boolean': 'Z', + 'char': 'C', + 'short': 'S', + 'long': 'J', + 'double': 'D', + 'float': 'F', + 'byte': 'B', + 'void': 'V', + } + object_param_list = [ + 'Ljava/lang/Boolean', + 'Ljava/lang/Integer', + 'Ljava/lang/Long', + 'Ljava/lang/Object', + 'Ljava/lang/String', + 'Ljava/lang/Class', + ] + + prefix = '' + # Array? + while param[-2:] == '[]': + prefix += '[' + param = param[:-2] + # Generic? + if '<' in param: + param = param[:param.index('<')] + if param in pod_param_map: + return prefix + pod_param_map[param] + if '/' in param: + # Coming from javap, use the fully qualified param directly. + return prefix + 'L' + JniParams.RemapClassName(param) + ';' + + for qualified_name in (object_param_list + + [JniParams._fully_qualified_class] + + JniParams._inner_classes): + if (qualified_name.endswith('/' + param) or + qualified_name.endswith('$' + param.replace('.', '$')) or + qualified_name == 'L' + param): + return prefix + JniParams.RemapClassName(qualified_name) + ';' + + # Is it from an import? (e.g. referecing Class from import pkg.Class; + # note that referencing an inner class Inner from import pkg.Class.Inner + # is not supported). + for qualified_name in JniParams._imports: + if qualified_name.endswith('/' + param): + # Ensure it's not an inner class. + components = qualified_name.split('/') + if len(components) > 2 and components[-2][0].isupper(): + raise SyntaxError('Inner class (%s) can not be imported ' + 'and used by JNI (%s). Please import the outer ' + 'class and use Outer.Inner instead.' % + (qualified_name, param)) + return prefix + JniParams.RemapClassName(qualified_name) + ';' + + # Is it an inner class from an outer class import? (e.g. referencing + # Class.Inner from import pkg.Class). + if '.' in param: + components = param.split('.') + outer = '/'.join(components[:-1]) + inner = components[-1] + for qualified_name in JniParams._imports: + if qualified_name.endswith('/' + outer): + return (prefix + JniParams.RemapClassName(qualified_name) + + '$' + inner + ';') + raise SyntaxError('Inner class (%s) can not be ' + 'used directly by JNI. Please import the outer ' + 'class, probably:\n' + 'import %s.%s;' % + (param, JniParams._package.replace('/', '.'), + outer.replace('/', '.'))) + + JniParams._CheckImplicitImports(param) + + # Type not found, falling back to same package as this class. + return (prefix + 'L' + + JniParams.RemapClassName(JniParams._package + '/' + param) + ';') + + @staticmethod + def _CheckImplicitImports(param): + # Ensure implicit imports, such as java.lang.*, are not being treated + # as being in the same package. + if not JniParams._implicit_imports: + # This file was generated from android.jar and lists + # all classes that are implicitly imported. + with file(os.path.join(os.path.dirname(sys.argv[0]), + 'android_jar.classes'), 'r') as f: + JniParams._implicit_imports = f.readlines() + for implicit_import in JniParams._implicit_imports: + implicit_import = implicit_import.strip().replace('.class', '') + implicit_import = implicit_import.replace('/', '.') + if implicit_import.endswith('.' + param): + raise SyntaxError('Ambiguous class (%s) can not be used directly ' + 'by JNI.\nPlease import it, probably:\n\n' + 'import %s;' % + (param, implicit_import)) + + + @staticmethod + def Signature(params, returns, wrap): + """Returns the JNI signature for the given datatypes.""" + items = ['('] + items += [JniParams.JavaToJni(param.datatype) for param in params] + items += [')'] + items += [JniParams.JavaToJni(returns)] + if wrap: + return '\n' + '\n'.join(['"' + item + '"' for item in items]) + else: + return '"' + ''.join(items) + '"' + + @staticmethod + def Parse(params): + """Parses the params into a list of Param objects.""" + if not params: + return [] + ret = [] + for p in [p.strip() for p in params.split(',')]: + items = p.split(' ') + if 'final' in items: + items.remove('final') + param = Param( + datatype=items[0], + name=(items[1] if len(items) > 1 else 'p%s' % len(ret)), + ) + ret += [param] + return ret + + @staticmethod + def RemapClassName(class_name): + """Remaps class names using the jarjar mapping table.""" + for old, new in JniParams._remappings: + if old.endswith('**') and old[:-2] in class_name: + return class_name.replace(old[:-2], new, 1) + if '*' not in old and class_name.endswith(old): + return class_name.replace(old, new, 1) + + return class_name + + @staticmethod + def SetJarJarMappings(mappings): + """Parse jarjar mappings from a string.""" + JniParams._remappings = [] + for line in mappings.splitlines(): + rule = line.split() + if rule[0] != 'rule': + continue + _, src, dest = rule + src = src.replace('.', '/') + dest = dest.replace('.', '/') + if src.endswith('**'): + src_real_name = src[:-2] + else: + assert not '*' in src + src_real_name = src + + if dest.endswith('@0'): + JniParams._remappings.append((src, dest[:-2] + src_real_name)) + elif dest.endswith('@1'): + assert '**' in src + JniParams._remappings.append((src, dest[:-2])) + else: + assert not '@' in dest + JniParams._remappings.append((src, dest)) + + +def ExtractJNINamespace(contents): + re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)') + m = re.findall(re_jni_namespace, contents) + if not m: + return '' + return m[0] + + +def ExtractFullyQualifiedJavaClassName(java_file_name, contents): + re_package = re.compile('.*?package (.*?);') + matches = re.findall(re_package, contents) + if not matches: + raise SyntaxError('Unable to find "package" line in %s' % java_file_name) + return (matches[0].replace('.', '/') + '/' + + os.path.splitext(os.path.basename(java_file_name))[0]) + + +def ExtractNatives(contents, ptr_type): + """Returns a list of dict containing information about a native method.""" + contents = contents.replace('\n', '') + natives = [] + re_native = re.compile(r'(@NativeClassQualifiedName' + '\(\"(?P<native_class_name>.*?)\"\)\s+)?' + '(@NativeCall(\(\"(?P<java_class_name>.*?)\"\))\s+)?' + '(?P<qualifiers>\w+\s\w+|\w+|\s+)\s*native ' + '(?P<return_type>\S*) ' + '(?P<name>native\w+)\((?P<params>.*?)\);') + for match in re.finditer(re_native, contents): + native = NativeMethod( + static='static' in match.group('qualifiers'), + java_class_name=match.group('java_class_name'), + native_class_name=match.group('native_class_name'), + return_type=match.group('return_type'), + name=match.group('name').replace('native', ''), + params=JniParams.Parse(match.group('params')), + ptr_type=ptr_type) + natives += [native] + return natives + + +def GetStaticCastForReturnType(return_type): + type_map = { 'String' : 'jstring', + 'java/lang/String' : 'jstring', + 'boolean[]': 'jbooleanArray', + 'byte[]': 'jbyteArray', + 'char[]': 'jcharArray', + 'short[]': 'jshortArray', + 'int[]': 'jintArray', + 'long[]': 'jlongArray', + 'float[]': 'jfloatArray', + 'double[]': 'jdoubleArray' } + ret = type_map.get(return_type, None) + if ret: + return ret + if return_type.endswith('[]'): + return 'jobjectArray' + return None + + +def GetEnvCall(is_constructor, is_static, return_type): + """Maps the types availabe via env->Call__Method.""" + if is_constructor: + return 'NewObject' + env_call_map = {'boolean': 'Boolean', + 'byte': 'Byte', + 'char': 'Char', + 'short': 'Short', + 'int': 'Int', + 'long': 'Long', + 'float': 'Float', + 'void': 'Void', + 'double': 'Double', + 'Object': 'Object', + } + call = env_call_map.get(return_type, 'Object') + if is_static: + call = 'Static' + call + return 'Call' + call + 'Method' + + +def GetMangledParam(datatype): + """Returns a mangled identifier for the datatype.""" + if len(datatype) <= 2: + return datatype.replace('[', 'A') + ret = '' + for i in range(1, len(datatype)): + c = datatype[i] + if c == '[': + ret += 'A' + elif c.isupper() or datatype[i - 1] in ['/', 'L']: + ret += c.upper() + return ret + + +def GetMangledMethodName(name, params, return_type): + """Returns a mangled method name for the given signature. + + The returned name can be used as a C identifier and will be unique for all + valid overloads of the same method. + + Args: + name: string. + params: list of Param. + return_type: string. + + Returns: + A mangled name. + """ + mangled_items = [] + for datatype in [return_type] + [x.datatype for x in params]: + mangled_items += [GetMangledParam(JniParams.JavaToJni(datatype))] + mangled_name = name + '_'.join(mangled_items) + assert re.match(r'[0-9a-zA-Z_]+', mangled_name) + return mangled_name + + +def MangleCalledByNatives(called_by_natives): + """Mangles all the overloads from the call_by_natives list.""" + method_counts = collections.defaultdict( + lambda: collections.defaultdict(lambda: 0)) + for called_by_native in called_by_natives: + java_class_name = called_by_native.java_class_name + name = called_by_native.name + method_counts[java_class_name][name] += 1 + for called_by_native in called_by_natives: + java_class_name = called_by_native.java_class_name + method_name = called_by_native.name + method_id_var_name = method_name + if method_counts[java_class_name][method_name] > 1: + method_id_var_name = GetMangledMethodName(method_name, + called_by_native.params, + called_by_native.return_type) + called_by_native.method_id_var_name = method_id_var_name + return called_by_natives + + +# Regex to match the JNI return types that should be included in a +# ScopedLocalJavaRef. +RE_SCOPED_JNI_RETURN_TYPES = re.compile('jobject|jclass|jstring|.*Array') + +# Regex to match a string like "@CalledByNative public void foo(int bar)". +RE_CALLED_BY_NATIVE = re.compile( + '@CalledByNative(?P<Unchecked>(Unchecked)*?)(?:\("(?P<annotation>.*)"\))?' + '\s+(?P<prefix>[\w ]*?)' + '\s*(?P<return_type>\S+?)' + '\s+(?P<name>\w+)' + '\s*\((?P<params>[^\)]*)\)') + + +def ExtractCalledByNatives(contents): + """Parses all methods annotated with @CalledByNative. + + Args: + contents: the contents of the java file. + + Returns: + A list of dict with information about the annotated methods. + TODO(bulach): return a CalledByNative object. + + Raises: + ParseError: if unable to parse. + """ + called_by_natives = [] + for match in re.finditer(RE_CALLED_BY_NATIVE, contents): + called_by_natives += [CalledByNative( + system_class=False, + unchecked='Unchecked' in match.group('Unchecked'), + static='static' in match.group('prefix'), + java_class_name=match.group('annotation') or '', + return_type=match.group('return_type'), + name=match.group('name'), + params=JniParams.Parse(match.group('params')))] + # Check for any @CalledByNative occurrences that weren't matched. + unmatched_lines = re.sub(RE_CALLED_BY_NATIVE, '', contents).split('\n') + for line1, line2 in zip(unmatched_lines, unmatched_lines[1:]): + if '@CalledByNative' in line1: + raise ParseError('could not parse @CalledByNative method signature', + line1, line2) + return MangleCalledByNatives(called_by_natives) + + +class JNIFromJavaP(object): + """Uses 'javap' to parse a .class file and generate the JNI header file.""" + + def __init__(self, contents, options): + self.contents = contents + self.namespace = options.namespace + for line in contents: + class_name = re.match( + '.*?(public).*?(class|interface) (?P<class_name>\S+?)( |\Z)', + line) + if class_name: + self.fully_qualified_class = class_name.group('class_name') + break + self.fully_qualified_class = self.fully_qualified_class.replace('.', '/') + # Java 7's javap includes type parameters in output, like HashSet<T>. Strip + # away the <...> and use the raw class name that Java 6 would've given us. + self.fully_qualified_class = self.fully_qualified_class.split('<', 1)[0] + JniParams.SetFullyQualifiedClass(self.fully_qualified_class) + self.java_class_name = self.fully_qualified_class.split('/')[-1] + if not self.namespace: + self.namespace = 'JNI_' + self.java_class_name + re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)' + '\((?P<params>.*?)\)') + self.called_by_natives = [] + for lineno, content in enumerate(contents[2:], 2): + match = re.match(re_method, content) + if not match: + continue + self.called_by_natives += [CalledByNative( + system_class=True, + unchecked=False, + static='static' in match.group('prefix'), + java_class_name='', + return_type=match.group('return_type').replace('.', '/'), + name=match.group('name'), + params=JniParams.Parse(match.group('params').replace('.', '/')), + signature=JniParams.ParseJavaPSignature(contents[lineno + 1]))] + re_constructor = re.compile('(.*?)public ' + + self.fully_qualified_class.replace('/', '.') + + '\((?P<params>.*?)\)') + for lineno, content in enumerate(contents[2:], 2): + match = re.match(re_constructor, content) + if not match: + continue + self.called_by_natives += [CalledByNative( + system_class=True, + unchecked=False, + static=False, + java_class_name='', + return_type=self.fully_qualified_class, + name='Constructor', + params=JniParams.Parse(match.group('params').replace('.', '/')), + signature=JniParams.ParseJavaPSignature(contents[lineno + 1]), + is_constructor=True)] + self.called_by_natives = MangleCalledByNatives(self.called_by_natives) + + self.constant_fields = [] + re_constant_field = re.compile('.*?public static final int (?P<name>.*?);') + re_constant_field_value = re.compile( + '.*?Constant(Value| value): int (?P<value>(-*[0-9]+)?)') + for lineno, content in enumerate(contents[2:], 2): + match = re.match(re_constant_field, content) + if not match: + continue + value = re.match(re_constant_field_value, contents[lineno + 2]) + if not value: + value = re.match(re_constant_field_value, contents[lineno + 3]) + if value: + self.constant_fields.append( + ConstantField(name=match.group('name'), + value=value.group('value'))) + + self.inl_header_file_generator = InlHeaderFileGenerator( + self.namespace, self.fully_qualified_class, [], + self.called_by_natives, self.constant_fields, options) + + def GetContent(self): + return self.inl_header_file_generator.GetContent() + + @staticmethod + def CreateFromClass(class_file, options): + class_name = os.path.splitext(os.path.basename(class_file))[0] + p = subprocess.Popen(args=[options.javap, '-c', '-verbose', + '-s', class_name], + cwd=os.path.dirname(class_file), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + stdout, _ = p.communicate() + jni_from_javap = JNIFromJavaP(stdout.split('\n'), options) + return jni_from_javap + + +class JNIFromJavaSource(object): + """Uses the given java source file to generate the JNI header file.""" + + # Match single line comments, multiline comments, character literals, and + # double-quoted strings. + _comment_remover_regex = re.compile( + r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', + re.DOTALL | re.MULTILINE) + + def __init__(self, contents, fully_qualified_class, options): + contents = self._RemoveComments(contents) + JniParams.SetFullyQualifiedClass(fully_qualified_class) + JniParams.ExtractImportsAndInnerClasses(contents) + jni_namespace = ExtractJNINamespace(contents) or options.namespace + natives = ExtractNatives(contents, options.ptr_type) + called_by_natives = ExtractCalledByNatives(contents) + if len(natives) == 0 and len(called_by_natives) == 0: + raise SyntaxError('Unable to find any JNI methods for %s.' % + fully_qualified_class) + inl_header_file_generator = InlHeaderFileGenerator( + jni_namespace, fully_qualified_class, natives, called_by_natives, + [], options) + self.content = inl_header_file_generator.GetContent() + + @classmethod + def _RemoveComments(cls, contents): + # We need to support both inline and block comments, and we need to handle + # strings that contain '//' or '/*'. + # TODO(bulach): This is a bit hacky. It would be cleaner to use a real Java + # parser. Maybe we could ditch JNIFromJavaSource and just always use + # JNIFromJavaP; or maybe we could rewrite this script in Java and use APT. + # http://code.google.com/p/chromium/issues/detail?id=138941 + def replacer(match): + # Replace matches that are comments with nothing; return literals/strings + # unchanged. + s = match.group(0) + if s.startswith('/'): + return '' + else: + return s + return cls._comment_remover_regex.sub(replacer, contents) + + def GetContent(self): + return self.content + + @staticmethod + def CreateFromFile(java_file_name, options): + contents = file(java_file_name).read() + fully_qualified_class = ExtractFullyQualifiedJavaClassName(java_file_name, + contents) + return JNIFromJavaSource(contents, fully_qualified_class, options) + + +class InlHeaderFileGenerator(object): + """Generates an inline header file for JNI integration.""" + + def __init__(self, namespace, fully_qualified_class, natives, + called_by_natives, constant_fields, options): + self.namespace = namespace + self.fully_qualified_class = fully_qualified_class + self.class_name = self.fully_qualified_class.split('/')[-1] + self.natives = natives + self.called_by_natives = called_by_natives + self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI' + self.constant_fields = constant_fields + self.options = options + self.init_native = self.ExtractInitNative(options) + + def ExtractInitNative(self, options): + for native in self.natives: + if options.jni_init_native_name == 'native' + native.name: + self.natives.remove(native) + return native + return None + + def GetContent(self): + """Returns the content of the JNI binding file.""" + template = Template("""\ +// Copyright 2014 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 +// ${SCRIPT_NAME} +// For +// ${FULLY_QUALIFIED_CLASS} + +#ifndef ${HEADER_GUARD} +#define ${HEADER_GUARD} + +#include <jni.h> + +${INCLUDES} + +//#include "base/android/jni_int_wrapper.h" + +// Step 1: forward declarations. +namespace { +$CLASS_PATH_DEFINITIONS +$METHOD_ID_DEFINITIONS +} // namespace + +$OPEN_NAMESPACE +$FORWARD_DECLARATIONS + +$CONSTANT_FIELDS + +// Step 2: method stubs. +$METHOD_STUBS + +// Step 3: RegisterNatives. +$JNI_NATIVE_METHODS +$REGISTER_NATIVES +$CLOSE_NAMESPACE +$JNI_REGISTER_NATIVES +#endif // ${HEADER_GUARD} +""") + values = { + 'SCRIPT_NAME': self.options.script_name, + 'FULLY_QUALIFIED_CLASS': self.fully_qualified_class, + 'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(), + 'METHOD_ID_DEFINITIONS': self.GetMethodIDDefinitionsString(), + 'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(), + 'CONSTANT_FIELDS': self.GetConstantFieldsString(), + 'METHOD_STUBS': self.GetMethodStubsString(), + 'OPEN_NAMESPACE': self.GetOpenNamespaceString(), + 'JNI_NATIVE_METHODS': self.GetJNINativeMethodsString(), + 'REGISTER_NATIVES': self.GetRegisterNativesString(), + 'CLOSE_NAMESPACE': self.GetCloseNamespaceString(), + 'HEADER_GUARD': self.header_guard, + 'INCLUDES': self.GetIncludesString(), + 'JNI_REGISTER_NATIVES': self.GetJNIRegisterNativesString() + } + return WrapOutput(template.substitute(values)) + + def GetClassPathDefinitionsString(self): + ret = [] + ret += [self.GetClassPathDefinitions()] + return '\n'.join(ret) + + def GetMethodIDDefinitionsString(self): + """Returns the definition of method ids for the called by native methods.""" + if not self.options.eager_called_by_natives: + return '' + template = Template("""\ +jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""") + ret = [] + for called_by_native in self.called_by_natives: + values = { + 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, + 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, + } + ret += [template.substitute(values)] + return '\n'.join(ret) + + def GetForwardDeclarationsString(self): + ret = [] + for native in self.natives: + if native.type != 'method': + ret += [self.GetForwardDeclaration(native)] + if self.options.native_exports and ret: + return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' + return '\n'.join(ret) + + def GetConstantFieldsString(self): + if not self.constant_fields: + return '' + ret = ['enum Java_%s_constant_fields {' % self.class_name] + for c in self.constant_fields: + ret += [' %s = %s,' % (c.name, c.value)] + ret += ['};'] + return '\n'.join(ret) + + def GetMethodStubsString(self): + """Returns the code corresponding to method stubs.""" + ret = [] + for native in self.natives: + if native.type == 'method': + ret += [self.GetNativeMethodStubString(native)] + if self.options.eager_called_by_natives: + ret += self.GetEagerCalledByNativeMethodStubs() + else: + ret += self.GetLazyCalledByNativeMethodStubs() + + if self.options.native_exports and ret: + return '\nextern "C" {\n' + "\n".join(ret) + '\n}; // extern "C"' + return '\n'.join(ret) + + def GetLazyCalledByNativeMethodStubs(self): + return [self.GetLazyCalledByNativeMethodStub(called_by_native) + for called_by_native in self.called_by_natives] + + def GetEagerCalledByNativeMethodStubs(self): + ret = [] + if self.called_by_natives: + ret += ['namespace {'] + for called_by_native in self.called_by_natives: + ret += [self.GetEagerCalledByNativeMethodStub(called_by_native)] + ret += ['} // namespace'] + return ret + + def GetIncludesString(self): + if not self.options.includes: + return '' + includes = self.options.includes.split(',') + return '\n'.join('#include "%s"' % x for x in includes) + + def GetKMethodsString(self, clazz): + ret = [] + for native in self.natives: + if (native.java_class_name == clazz or + (not native.java_class_name and clazz == self.class_name)): + ret += [self.GetKMethodArrayEntry(native)] + return '\n'.join(ret) + + def SubstituteNativeMethods(self, template): + """Substitutes JAVA_CLASS and KMETHODS in the provided template.""" + ret = [] + all_classes = self.GetUniqueClasses(self.natives) + all_classes[self.class_name] = self.fully_qualified_class + for clazz in all_classes: + kmethods = self.GetKMethodsString(clazz) + if kmethods: + values = {'JAVA_CLASS': clazz, + 'KMETHODS': kmethods} + ret += [template.substitute(values)] + if not ret: return '' + return '\n' + '\n'.join(ret) + + def GetJNINativeMethodsString(self): + """Returns the implementation of the array of native methods.""" + if self.options.native_exports and not self.options.native_exports_optional: + return '' + template = Template("""\ +static const JNINativeMethod kMethods${JAVA_CLASS}[] = { +${KMETHODS} +}; +""") + return self.SubstituteNativeMethods(template) + + def GetRegisterCalledByNativesImplString(self): + """Returns the code for registering the called by native methods.""" + if not self.options.eager_called_by_natives: + return '' + template = Template("""\ + g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = ${GET_METHOD_ID_IMPL} + if (g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} == NULL) { + return false; + } + """) + ret = [] + for called_by_native in self.called_by_natives: + values = { + 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, + 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, + 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native), + } + ret += [template.substitute(values)] + return '\n'.join(ret) + + def GetRegisterNativesString(self): + """Returns the code for RegisterNatives.""" + template = Template("""\ +${REGISTER_NATIVES_SIGNATURE} { +${EARLY_EXIT} +${CLASSES} +${NATIVES} +${CALLED_BY_NATIVES} + return true; +} +""") + signature = 'static bool RegisterNativesImpl(JNIEnv* env' + if self.init_native: + signature += ', jclass clazz)' + else: + signature += ')' + + early_exit = '' + if self.options.native_exports_optional: + early_exit = """\ + if (base::android::IsManualJniRegistrationDisabled()) return true; +""" + + natives = self.GetRegisterNativesImplString() + called_by_natives = self.GetRegisterCalledByNativesImplString() + values = {'REGISTER_NATIVES_SIGNATURE': signature, + 'EARLY_EXIT': early_exit, + 'CLASSES': self.GetFindClasses(), + 'NATIVES': natives, + 'CALLED_BY_NATIVES': called_by_natives, + } + return template.substitute(values) + + def GetRegisterNativesImplString(self): + """Returns the shared implementation for RegisterNatives.""" + if self.options.native_exports and not self.options.native_exports_optional: + return '' + + template = Template("""\ + const int kMethods${JAVA_CLASS}Size = sizeof(kMethods${JAVA_CLASS})/sizeof(kMethods${JAVA_CLASS}[0]); + + if (env->RegisterNatives(${JAVA_CLASS}_clazz(env), + kMethods${JAVA_CLASS}, + kMethods${JAVA_CLASS}Size) < 0) { + //jni_generator::HandleRegistrationError( + // env, ${JAVA_CLASS}_clazz(env), __FILE__); + return false; + } +""") + return self.SubstituteNativeMethods(template) + + def GetJNIRegisterNativesString(self): + """Returns the implementation for the JNI registration of native methods.""" + if not self.init_native: + return '' + + template = Template("""\ +extern "C" JNIEXPORT bool JNICALL +Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) { + return ${NAMESPACE}RegisterNativesImpl(env, clazz); +} +""") + + if self.options.native_exports: + java_name = JniParams.RemapClassName(self.fully_qualified_class) + java_name = java_name.replace('_', '_1').replace('/', '_') + else: + java_name = self.fully_qualified_class.replace('/', '_') + + namespace = '' + if self.namespace: + namespace = self.namespace + '::' + values = {'FULLY_QUALIFIED_CLASS': java_name, + 'INIT_NATIVE_NAME': 'native' + self.init_native.name, + 'NAMESPACE': namespace, + 'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString() + } + return template.substitute(values) + + def GetOpenNamespaceString(self): + if self.namespace: + all_namespaces = ['namespace %s {' % ns + for ns in self.namespace.split('::')] + return '\n'.join(all_namespaces) + return '' + + def GetCloseNamespaceString(self): + if self.namespace: + all_namespaces = ['} // namespace %s' % ns + for ns in self.namespace.split('::')] + all_namespaces.reverse() + return '\n'.join(all_namespaces) + '\n' + return '' + + def GetJNIFirstParam(self, native): + ret = [] + if native.type == 'method': + ret = ['jobject jcaller'] + elif native.type == 'function': + if native.static: + ret = ['jclass jcaller'] + else: + ret = ['jobject jcaller'] + return ret + + def GetParamsInDeclaration(self, native): + """Returns the params for the stub declaration. + + Args: + native: the native dictionary describing the method. + + Returns: + A string containing the params. + """ + return ',\n '.join(self.GetJNIFirstParam(native) + + [JavaDataTypeToC(param.datatype) + ' ' + + param.name + for param in native.params]) + + def GetCalledByNativeParamsInDeclaration(self, called_by_native): + return ',\n '.join([ + JavaDataTypeToCForCalledByNativeParam(param.datatype) + ' ' + + param.name + for param in called_by_native.params]) + + def GetStubName(self, native): + """Return the name of the stub function for this native method. + + Args: + native: the native dictionary describing the method. + + Returns: + A string with the stub function name. For native exports mode this is the + Java_* symbol name required by the JVM; otherwise it is just the name of + the native method itself. + """ + if self.options.native_exports: + template = Template("Java_${JAVA_NAME}_native${NAME}") + + java_name = JniParams.RemapClassName(self.fully_qualified_class) + java_name = java_name.replace('_', '_1').replace('/', '_') + if native.java_class_name: + java_name += '_00024' + native.java_class_name + + values = {'NAME': native.name, + 'JAVA_NAME': java_name} + return template.substitute(values) + else: + return native.name + + def GetForwardDeclaration(self, native): + template_str = """ +static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS}); +""" + if self.options.native_exports: + template_str += """ +__attribute__((visibility("default"))) +${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS}) { + return ${NAME}(${PARAMS_IN_CALL}); +} +""" + template = Template(template_str) + params_in_call = [] + if not self.options.pure_native_methods: + params_in_call = ['env', 'jcaller'] + params_in_call = ', '.join(params_in_call + [p.name for p in native.params]) + + values = {'RETURN': JavaDataTypeToC(native.return_type), + 'NAME': native.name, + 'PARAMS': self.GetParamsInDeclaration(native), + 'PARAMS_IN_CALL': params_in_call, + 'STUB_NAME': self.GetStubName(native)} + return template.substitute(values) + + def GetNativeMethodStubString(self, native): + """Returns stubs for native methods.""" + if self.options.native_exports: + template_str = """\ +__attribute__((visibility("default"))) +${RETURN} ${STUB_NAME}(JNIEnv* env, + ${PARAMS_IN_DECLARATION}) {""" + else: + template_str = """\ +static ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {""" + template_str += """ + ${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME}); + CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN}); + return native->${NAME}(${PARAMS_IN_CALL})${POST_CALL}; +} +""" + + template = Template(template_str) + params = [] + if not self.options.pure_native_methods: + params = ['env', 'jcaller'] + params_in_call = ', '.join(params + [p.name for p in native.params[1:]]) + + return_type = JavaDataTypeToC(native.return_type) + optional_error_return = JavaReturnValueToC(native.return_type) + if optional_error_return: + optional_error_return = ', ' + optional_error_return + post_call = '' + if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): + post_call = '.Get()' + + values = { + 'RETURN': return_type, + 'OPTIONAL_ERROR_RETURN': optional_error_return, + 'NAME': native.name, + 'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native), + 'PARAM0_NAME': native.params[0].name, + 'P0_TYPE': native.p0_type, + 'PARAMS_IN_CALL': params_in_call, + 'POST_CALL': post_call, + 'STUB_NAME': self.GetStubName(native), + } + return template.substitute(values) + + def GetArgument(self, param): + return ('int(' + param.name + ')' + if param.datatype == 'int' else param.name) + + def GetArgumentsInCall(self, params): + """Return a string of arguments to call from native into Java""" + return [self.GetArgument(p) for p in params] + + def GetCalledByNativeValues(self, called_by_native): + """Fills in necessary values for the CalledByNative methods.""" + java_class = called_by_native.java_class_name or self.class_name + if called_by_native.static or called_by_native.is_constructor: + first_param_in_declaration = '' + first_param_in_call = ('%s_clazz(env)' % java_class) + else: + first_param_in_declaration = ', jobject obj' + first_param_in_call = 'obj' + params_in_declaration = self.GetCalledByNativeParamsInDeclaration( + called_by_native) + if params_in_declaration: + params_in_declaration = ', ' + params_in_declaration + params_in_call = ', '.join(self.GetArgumentsInCall(called_by_native.params)) + if params_in_call: + params_in_call = ', ' + params_in_call + pre_call = '' + post_call = '' + if called_by_native.static_cast: + pre_call = 'static_cast<%s>(' % called_by_native.static_cast + post_call = ')' + check_exception = '' + if not called_by_native.unchecked: + check_exception = 'base::android::CheckException(env);' + return_type = JavaDataTypeToC(called_by_native.return_type) + optional_error_return = JavaReturnValueToC(called_by_native.return_type) + if optional_error_return: + optional_error_return = ', ' + optional_error_return + return_declaration = '' + return_clause = '' + if return_type != 'void': + pre_call = ' ' + pre_call + return_declaration = return_type + ' ret =' + if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type): + return_type = 'base::android::ScopedLocalJavaRef<' + return_type + '>' + return_clause = 'return ' + return_type + '(env, ret);' + else: + return_clause = 'return ret;' + return { + 'JAVA_CLASS': java_class, + 'RETURN_TYPE': return_type, + 'OPTIONAL_ERROR_RETURN': optional_error_return, + 'RETURN_DECLARATION': return_declaration, + 'RETURN_CLAUSE': return_clause, + 'FIRST_PARAM_IN_DECLARATION': first_param_in_declaration, + 'PARAMS_IN_DECLARATION': params_in_declaration, + 'PRE_CALL': pre_call, + 'POST_CALL': post_call, + 'ENV_CALL': called_by_native.env_call, + 'FIRST_PARAM_IN_CALL': first_param_in_call, + 'PARAMS_IN_CALL': params_in_call, + 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, + 'CHECK_EXCEPTION': check_exception, + 'GET_METHOD_ID_IMPL': self.GetMethodIDImpl(called_by_native) + } + + def GetEagerCalledByNativeMethodStub(self, called_by_native): + """Returns the implementation of the called by native method.""" + template = Template(""" +static ${RETURN_TYPE} ${METHOD_ID_VAR_NAME}(\ +JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION}) { + ${RETURN_DECLARATION}${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL}, + g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}${PARAMS_IN_CALL})${POST_CALL}; + ${RETURN_CLAUSE} +}""") + values = self.GetCalledByNativeValues(called_by_native) + return template.substitute(values) + + def GetLazyCalledByNativeMethodStub(self, called_by_native): + """Returns a string.""" + function_signature_template = Template("""\ +static ${RETURN_TYPE} Java_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}(\ +JNIEnv* env${FIRST_PARAM_IN_DECLARATION}${PARAMS_IN_DECLARATION})""") + function_header_template = Template("""\ +${FUNCTION_SIGNATURE} {""") + function_header_with_unused_template = Template("""\ +${FUNCTION_SIGNATURE} __attribute__ ((unused)); +${FUNCTION_SIGNATURE} {""") + template = Template(""" +static intptr_t g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = 0; +${FUNCTION_HEADER} + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, ${FIRST_PARAM_IN_CALL}, + // ${JAVA_CLASS}_clazz(env)${OPTIONAL_ERROR_RETURN}); + jmethodID method_id = + ${GET_METHOD_ID_IMPL} + ${RETURN_DECLARATION} + ${PRE_CALL}env->${ENV_CALL}(${FIRST_PARAM_IN_CALL}, + method_id${PARAMS_IN_CALL})${POST_CALL}; + ${CHECK_EXCEPTION} + ${RETURN_CLAUSE} +}""") + values = self.GetCalledByNativeValues(called_by_native) + values['FUNCTION_SIGNATURE'] = ( + function_signature_template.substitute(values)) + if called_by_native.system_class: + values['FUNCTION_HEADER'] = ( + function_header_with_unused_template.substitute(values)) + else: + values['FUNCTION_HEADER'] = function_header_template.substitute(values) + return template.substitute(values) + + def GetKMethodArrayEntry(self, native): + template = Template(' { "native${NAME}", ${JNI_SIGNATURE}, ' + + 'reinterpret_cast<void*>(${STUB_NAME}) },') + values = {'NAME': native.name, + 'JNI_SIGNATURE': JniParams.Signature(native.params, + native.return_type, + True), + 'STUB_NAME': self.GetStubName(native)} + return template.substitute(values) + + def GetUniqueClasses(self, origin): + ret = {self.class_name: self.fully_qualified_class} + for entry in origin: + class_name = self.class_name + jni_class_path = self.fully_qualified_class + if entry.java_class_name: + class_name = entry.java_class_name + jni_class_path = self.fully_qualified_class + '$' + class_name + ret[class_name] = jni_class_path + return ret + + def GetClassPathDefinitions(self): + """Returns the ClassPath constants.""" + ret = [] + template = Template("""\ +const char k${JAVA_CLASS}ClassPath[] = "${JNI_CLASS_PATH}";""") + native_classes = self.GetUniqueClasses(self.natives) + called_by_native_classes = self.GetUniqueClasses(self.called_by_natives) + if self.options.native_exports: + all_classes = called_by_native_classes + else: + all_classes = native_classes + all_classes.update(called_by_native_classes) + + for clazz in all_classes: + values = { + 'JAVA_CLASS': clazz, + 'JNI_CLASS_PATH': JniParams.RemapClassName(all_classes[clazz]), + } + ret += [template.substitute(values)] + ret += '' + + class_getter_methods = [] + if self.options.native_exports: + template = Template("""\ +// Leaking this jclass as we cannot use LazyInstance from some threads. +base::subtle::AtomicWord g_${JAVA_CLASS}_clazz __attribute__((unused)) = 0; +#define ${JAVA_CLASS}_clazz(env) \ +base::android::LazyGetClass(env, k${JAVA_CLASS}ClassPath, \ +&g_${JAVA_CLASS}_clazz)""") + else: + template = Template("""\ +// Leaking this jclass as we cannot use LazyInstance from some threads. +jclass g_${JAVA_CLASS}_clazz = NULL; +#define ${JAVA_CLASS}_clazz(env) g_${JAVA_CLASS}_clazz""") + + for clazz in called_by_native_classes: + values = { + 'JAVA_CLASS': clazz, + } + ret += [template.substitute(values)] + + return '\n'.join(ret) + + def GetFindClasses(self): + """Returns the imlementation of FindClass for all known classes.""" + if self.init_native: + if self.options.native_exports: + template = Template("""\ + base::subtle::Release_Store(&g_${JAVA_CLASS}_clazz, + static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));""") + else: + template = Template("""\ + g_${JAVA_CLASS}_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));""") + else: + if self.options.native_exports: + return '\n' + template = Template("""\ + g_${JAVA_CLASS}_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( + base::android::GetClass(env, k${JAVA_CLASS}ClassPath).Get()));""") + ret = [] + for clazz in self.GetUniqueClasses(self.called_by_natives): + values = {'JAVA_CLASS': clazz} + ret += [template.substitute(values)] + return '\n'.join(ret) + + def GetMethodIDImpl(self, called_by_native): + """Returns the implementation of GetMethodID.""" + if self.options.eager_called_by_natives: + template = Template("""\ +env->Get${STATIC_METHOD_PART}MethodID( + ${JAVA_CLASS}_clazz(env), + "${JNI_NAME}", ${JNI_SIGNATURE});""") + else: + template = Template("""\ + base::android::GetMethod( + env, ${JAVA_CLASS}_clazz(env), + base::android::${STATIC}_METHOD, + "${JNI_NAME}", + ${JNI_SIGNATURE}, + &g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME}); +""") + jni_name = called_by_native.name + jni_return_type = called_by_native.return_type + if called_by_native.is_constructor: + jni_name = '<init>' + jni_return_type = 'void' + if called_by_native.signature: + signature = called_by_native.signature + else: + signature = JniParams.Signature(called_by_native.params, + jni_return_type, + True) + values = { + 'JAVA_CLASS': called_by_native.java_class_name or self.class_name, + 'JNI_NAME': jni_name, + 'METHOD_ID_VAR_NAME': called_by_native.method_id_var_name, + 'STATIC': 'STATIC' if called_by_native.static else 'INSTANCE', + 'STATIC_METHOD_PART': 'Static' if called_by_native.static else '', + 'JNI_SIGNATURE': signature, + } + return template.substitute(values) + + +def WrapOutput(output): + ret = [] + for line in output.splitlines(): + # Do not wrap lines under 80 characters or preprocessor directives. + if len(line) < 80 or line.lstrip()[:1] == '#': + stripped = line.rstrip() + if len(ret) == 0 or len(ret[-1]) or len(stripped): + ret.append(stripped) + else: + first_line_indent = ' ' * (len(line) - len(line.lstrip())) + subsequent_indent = first_line_indent + ' ' * 4 + if line.startswith('//'): + subsequent_indent = '//' + subsequent_indent + wrapper = textwrap.TextWrapper(width=80, + subsequent_indent=subsequent_indent, + break_long_words=False) + ret += [wrapped.rstrip() for wrapped in wrapper.wrap(line)] + ret += [''] + return '\n'.join(ret) + + +def ExtractJarInputFile(jar_file, input_file, out_dir): + """Extracts input file from jar and returns the filename. + + The input file is extracted to the same directory that the generated jni + headers will be placed in. This is passed as an argument to script. + + Args: + jar_file: the jar file containing the input files to extract. + input_files: the list of files to extract from the jar file. + out_dir: the name of the directories to extract to. + + Returns: + the name of extracted input file. + """ + jar_file = zipfile.ZipFile(jar_file) + + out_dir = os.path.join(out_dir, os.path.dirname(input_file)) + try: + os.makedirs(out_dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise + extracted_file_name = os.path.join(out_dir, os.path.basename(input_file)) + with open(extracted_file_name, 'w') as outfile: + outfile.write(jar_file.read(input_file)) + + return extracted_file_name + + +def GenerateJNIHeader(input_file, output_file, options): + try: + if os.path.splitext(input_file)[1] == '.class': + jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options) + content = jni_from_javap.GetContent() + else: + jni_from_java_source = JNIFromJavaSource.CreateFromFile( + input_file, options) + content = jni_from_java_source.GetContent() + except ParseError, e: + print e + sys.exit(1) + if output_file: + if not os.path.exists(os.path.dirname(os.path.abspath(output_file))): + os.makedirs(os.path.dirname(os.path.abspath(output_file))) + if options.optimize_generation and os.path.exists(output_file): + with file(output_file, 'r') as f: + existing_content = f.read() + if existing_content == content: + return + with file(output_file, 'w') as f: + f.write(content) + else: + print output + + +def GetScriptName(): + script_components = os.path.abspath(sys.argv[0]).split(os.path.sep) + base_index = 0 + for idx, value in enumerate(script_components): + if value == 'base' or value == 'third_party': + base_index = idx + break + return os.sep.join(script_components[base_index:]) + + + +class Opitions(object): + + def __init__(self): + self.ptr_type = 'int' + self.jni_init_native_name = '' + self.script_name = GetScriptName() + self.native_exports = '' + self.eager_called_by_natives = '' + self.pure_native_methods = '' + self.native_exports_optional = '' + self.includes = '' + self.optimize_generation = '' + self.namespace = '' + +if __name__ == '__main__': + """sys.exit(main(sys.argv))""" + if(len(sys.argv) == 3): + options = Opitions() + GenerateJNIHeader(sys.argv[1], sys.argv[2], options)
http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jniprebuild/jni_load.cc ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jniprebuild/jni_load.cc b/weex_core/Source/android/jniprebuild/jni_load.cc new file mode 100644 index 0000000..c731870 --- /dev/null +++ b/weex_core/Source/android/jniprebuild/jni_load.cc @@ -0,0 +1,24 @@ +#include <jni.h> +#include <android/bridge/impl/bridge_impl_android.h> +#include <android/base/jni/android_jni.h> +#include <android/bridge/impl/measure_mode_impl_android.h> +#include <android/bridge/impl/content_box_measurement_impl_android.h> + +jint JNI_OnLoad (JavaVM *vm, void *reserved) +{ + //base::android::InitVM(vm); + // JNIEnv* env = base::android::AttachCurrentThread(); + JNIEnv *env; + /* Get environment */ + if ((vm)->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) { + return JNI_FALSE; + } + WeexCore::RegisterJNIUtils(env); + WeexCore::RegisterJNIMeasureMode(env); + WeexCore::RegisterJNIContentBoxMeasurement(env); + return WeexCore::OnLoad(vm, reserved); +} + +void JNI_OnUnload(JavaVM *vm, void *reserved) { + WeexCore::Unload(vm, reserved); +} http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h b/weex_core/Source/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h new file mode 100644 index 0000000..871e32d --- /dev/null +++ b/weex_core/Source/android/jniprebuild/jniheader/ContentBoxMeasurement_jni.h @@ -0,0 +1,165 @@ +// Copyright 2014 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 +// /Users/miomin/Desktop/workspace/alibaba/WeexCore-dev/WeexCore- +// dev/android/weex_core_debug/Source/WeexCore/platform/android/jniprebuild/jni_generator.py +// For +// com/taobao/weex/layout/ContentBoxMeasurement + +#ifndef com_taobao_weex_layout_ContentBoxMeasurement_JNI +#define com_taobao_weex_layout_ContentBoxMeasurement_JNI + +#include <jni.h> + +//#include "base/android/jni_int_wrapper.h" + +// Step 1: forward declarations. +namespace { +const char kContentBoxMeasurementClassPath[] = + "com/taobao/weex/layout/ContentBoxMeasurement"; +// Leaking this jclass as we cannot use LazyInstance from some threads. +jclass g_ContentBoxMeasurement_clazz = NULL; +#define ContentBoxMeasurement_clazz(env) g_ContentBoxMeasurement_clazz + +} // namespace + +// Step 2: method stubs. + +static intptr_t g_ContentBoxMeasurement_measure = 0; +static void Java_ContentBoxMeasurement_measure(JNIEnv* env, jobject obj, jfloat + width, + jfloat height, + int widthMeasureMode, + int heightMeasureMode) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, obj, + // ContentBoxMeasurement_clazz(env)); + jmethodID method_id = + base::android::GetMethod( + env, ContentBoxMeasurement_clazz(env), + base::android::INSTANCE_METHOD, + "measure", + +"(" +"F" +"F" +"I" +"I" +")" +"V", + &g_ContentBoxMeasurement_measure); + + env->CallVoidMethod(obj, + method_id, width, height, int(widthMeasureMode), + int(heightMeasureMode)); + base::android::CheckException(env); + +} + +static intptr_t g_ContentBoxMeasurement_layoutBefore = 0; +static void Java_ContentBoxMeasurement_layoutBefore(JNIEnv* env, jobject obj) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, obj, + // ContentBoxMeasurement_clazz(env)); + jmethodID method_id = + base::android::GetMethod( + env, ContentBoxMeasurement_clazz(env), + base::android::INSTANCE_METHOD, + "layoutBefore", + +"(" +")" +"V", + &g_ContentBoxMeasurement_layoutBefore); + + env->CallVoidMethod(obj, + method_id); + base::android::CheckException(env); + +} + +static intptr_t g_ContentBoxMeasurement_layoutAfter = 0; +static void Java_ContentBoxMeasurement_layoutAfter(JNIEnv* env, jobject obj, + jfloat computedWidth, + jfloat computedHeight) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, obj, + // ContentBoxMeasurement_clazz(env)); + jmethodID method_id = + base::android::GetMethod( + env, ContentBoxMeasurement_clazz(env), + base::android::INSTANCE_METHOD, + "layoutAfter", + +"(" +"F" +"F" +")" +"V", + &g_ContentBoxMeasurement_layoutAfter); + + env->CallVoidMethod(obj, + method_id, computedWidth, computedHeight); + base::android::CheckException(env); + +} + +static intptr_t g_ContentBoxMeasurement_getWidth = 0; +static jfloat Java_ContentBoxMeasurement_getWidth(JNIEnv* env, jobject obj) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, obj, + // ContentBoxMeasurement_clazz(env), 0); + jmethodID method_id = + base::android::GetMethod( + env, ContentBoxMeasurement_clazz(env), + base::android::INSTANCE_METHOD, + "getWidth", + +"(" +")" +"F", + &g_ContentBoxMeasurement_getWidth); + + jfloat ret = + env->CallFloatMethod(obj, + method_id); + base::android::CheckException(env); + return ret; +} + +static intptr_t g_ContentBoxMeasurement_getHeight = 0; +static jfloat Java_ContentBoxMeasurement_getHeight(JNIEnv* env, jobject obj) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, obj, + // ContentBoxMeasurement_clazz(env), 0); + jmethodID method_id = + base::android::GetMethod( + env, ContentBoxMeasurement_clazz(env), + base::android::INSTANCE_METHOD, + "getHeight", + +"(" +")" +"F", + &g_ContentBoxMeasurement_getHeight); + + jfloat ret = + env->CallFloatMethod(obj, + method_id); + base::android::CheckException(env); + return ret; +} + +// Step 3: RegisterNatives. + +static bool RegisterNativesImpl(JNIEnv* env) { + + g_ContentBoxMeasurement_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( + base::android::GetClass(env, kContentBoxMeasurementClassPath).Get())); + + return true; +} + +#endif // com_taobao_weex_layout_ContentBoxMeasurement_JNI http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jniprebuild/jniheader/MeasureMode_jni.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jniprebuild/jniheader/MeasureMode_jni.h b/weex_core/Source/android/jniprebuild/jniheader/MeasureMode_jni.h new file mode 100644 index 0000000..c707ab1 --- /dev/null +++ b/weex_core/Source/android/jniprebuild/jniheader/MeasureMode_jni.h @@ -0,0 +1,85 @@ +// Copyright 2014 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 +// /Users/miomin/Desktop/workspace/alibaba/WeexCore-dev/WeexCore- +// dev/android/weex_core_debug/Source/WeexCore/platform/android/jniprebuild/jni_generator.py +// For +// com/taobao/weex/layout/MeasureMode + +#ifndef com_taobao_weex_layout_MeasureMode_JNI +#define com_taobao_weex_layout_MeasureMode_JNI + +#include <jni.h> + +//#include "base/android/jni_int_wrapper.h" + +// Step 1: forward declarations. +namespace { +const char kMeasureModeClassPath[] = "com/taobao/weex/layout/MeasureMode"; +// Leaking this jclass as we cannot use LazyInstance from some threads. +jclass g_MeasureMode_clazz = NULL; +#define MeasureMode_clazz(env) g_MeasureMode_clazz + +} // namespace + +// Step 2: method stubs. + +static intptr_t g_MeasureMode_getEXACTLY = 0; +static jint Java_MeasureMode_getEXACTLY(JNIEnv* env) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, MeasureMode_clazz(env), + // MeasureMode_clazz(env), 0); + jmethodID method_id = + base::android::GetMethod( + env, MeasureMode_clazz(env), + base::android::STATIC_METHOD, + "getEXACTLY", + +"(" +")" +"I", + &g_MeasureMode_getEXACTLY); + + jint ret = + env->CallStaticIntMethod(MeasureMode_clazz(env), + method_id); + base::android::CheckException(env); + return ret; +} + +static intptr_t g_MeasureMode_getUNSPECIFIED = 0; +static jint Java_MeasureMode_getUNSPECIFIED(JNIEnv* env) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, MeasureMode_clazz(env), + // MeasureMode_clazz(env), 0); + jmethodID method_id = + base::android::GetMethod( + env, MeasureMode_clazz(env), + base::android::STATIC_METHOD, + "getUNSPECIFIED", + +"(" +")" +"I", + &g_MeasureMode_getUNSPECIFIED); + + jint ret = + env->CallStaticIntMethod(MeasureMode_clazz(env), + method_id); + base::android::CheckException(env); + return ret; +} + +// Step 3: RegisterNatives. + +static bool RegisterNativesImpl(JNIEnv* env) { + + g_MeasureMode_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( + base::android::GetClass(env, kMeasureModeClassPath).Get())); + + return true; +} + +#endif // com_taobao_weex_layout_MeasureMode_JNI http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jniprebuild/jniheader/SystemMessageHandler_jni.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jniprebuild/jniheader/SystemMessageHandler_jni.h b/weex_core/Source/android/jniprebuild/jniheader/SystemMessageHandler_jni.h new file mode 100644 index 0000000..6f5849a --- /dev/null +++ b/weex_core/Source/android/jniprebuild/jniheader/SystemMessageHandler_jni.h @@ -0,0 +1,132 @@ +// Copyright 2014 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 +// /Users/miomin/Desktop/workspace/alibaba/WeexCore-dev/WeexCore- +// dev/android/weex_core_debug/Source/WeexCore/platform/android/jniprebuild/jni_generator.py +// For +// com/taobao/weex/base/SystemMessageHandler + +#ifndef com_taobao_weex_base_SystemMessageHandler_JNI +#define com_taobao_weex_base_SystemMessageHandler_JNI + +#include <jni.h> + +//#include "base/android/jni_int_wrapper.h" + +// Step 1: forward declarations. +namespace { +const char kSystemMessageHandlerClassPath[] = + "com/taobao/weex/base/SystemMessageHandler"; +// Leaking this jclass as we cannot use LazyInstance from some threads. +jclass g_SystemMessageHandler_clazz = NULL; +#define SystemMessageHandler_clazz(env) g_SystemMessageHandler_clazz + +} // namespace + +static void RunWork(JNIEnv* env, jobject jcaller, + jlong delegateNative); + +// Step 2: method stubs. + +static intptr_t g_SystemMessageHandler_create = 0; +static base::android::ScopedLocalJavaRef<jobject> + Java_SystemMessageHandler_create(JNIEnv* env, jlong + messagePumpDelegateNative) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, SystemMessageHandler_clazz(env), + // SystemMessageHandler_clazz(env), NULL); + jmethodID method_id = + base::android::GetMethod( + env, SystemMessageHandler_clazz(env), + base::android::STATIC_METHOD, + "create", + +"(" +"J" +")" +"Lcom/taobao/weex/base/SystemMessageHandler;", + &g_SystemMessageHandler_create); + + jobject ret = + env->CallStaticObjectMethod(SystemMessageHandler_clazz(env), + method_id, messagePumpDelegateNative); + base::android::CheckException(env); + return base::android::ScopedLocalJavaRef<jobject>(env, ret); +} + +static intptr_t g_SystemMessageHandler_scheduleWork = 0; +static void Java_SystemMessageHandler_scheduleWork(JNIEnv* env, jobject obj) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, obj, + // SystemMessageHandler_clazz(env)); + jmethodID method_id = + base::android::GetMethod( + env, SystemMessageHandler_clazz(env), + base::android::INSTANCE_METHOD, + "scheduleWork", + +"(" +")" +"V", + &g_SystemMessageHandler_scheduleWork); + + env->CallVoidMethod(obj, + method_id); + base::android::CheckException(env); + +} + +static intptr_t g_SystemMessageHandler_stop = 0; +static void Java_SystemMessageHandler_stop(JNIEnv* env, jobject obj) { + /* Must call RegisterNativesImpl() */ + //CHECK_CLAZZ(env, obj, + // SystemMessageHandler_clazz(env)); + jmethodID method_id = + base::android::GetMethod( + env, SystemMessageHandler_clazz(env), + base::android::INSTANCE_METHOD, + "stop", + +"(" +")" +"V", + &g_SystemMessageHandler_stop); + + env->CallVoidMethod(obj, + method_id); + base::android::CheckException(env); + +} + +// Step 3: RegisterNatives. + +static const JNINativeMethod kMethodsSystemMessageHandler[] = { + { "nativeRunWork", +"(" +"J" +")" +"V", reinterpret_cast<void*>(RunWork) }, +}; + +static bool RegisterNativesImpl(JNIEnv* env) { + + g_SystemMessageHandler_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( + base::android::GetClass(env, kSystemMessageHandlerClassPath).Get())); + + const int kMethodsSystemMessageHandlerSize = + sizeof(kMethodsSystemMessageHandler)/sizeof(kMethodsSystemMessageHandler[0]); + + if (env->RegisterNatives(SystemMessageHandler_clazz(env), + kMethodsSystemMessageHandler, + kMethodsSystemMessageHandlerSize) < 0) { + //jni_generator::HandleRegistrationError( + // env, SystemMessageHandler_clazz(env), __FILE__); + return false; + } + + return true; +} + +#endif // com_taobao_weex_base_SystemMessageHandler_JNI http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h b/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h new file mode 100644 index 0000000..f55f8a1 --- /dev/null +++ b/weex_core/Source/android/jniprebuild/jniheader/WXBridge_jni.h @@ -0,0 +1,345 @@ +// Copyright 2014 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 +// /Users/miomin/Desktop/workspace/alibaba/WeexCore-dev/WeexCore- +// dev/android/weex_core_debug/Source/WeexCore/platform/android/jniprebuild/jni_generator.py +// For +// com/taobao/weex/bridge/WXBridge + +#ifndef com_taobao_weex_bridge_WXBridge_JNI +#define com_taobao_weex_bridge_WXBridge_JNI + +#include <jni.h> + +//#include "base/android/jni_int_wrapper.h" + +// Step 1: forward declarations. +namespace { +const char kWXBridgeClassPath[] = "com/taobao/weex/bridge/WXBridge"; +// Leaking this jclass as we cannot use LazyInstance from some threads. +jclass g_WXBridge_clazz = NULL; +#define WXBridge_clazz(env) g_WXBridge_clazz + +} // namespace + +static jint InitFrameworkEnv(JNIEnv* env, jobject jcaller, + jstring framework, + jobject params, + jstring cacheDir, + jboolean pieSupport); + +static jint InitFramework(JNIEnv* env, jobject jcaller, + jstring framework, + jobject params); + +static jint ExecJS(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring name, + jstring function, + jobjectArray args); + +static jint ExecJSService(JNIEnv* env, jobject jcaller, + jstring javascript); + +static jbyteArray ExecJSWithResult(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring _namespace, + jstring _function, + jobjectArray args); + +static jint CreateInstanceContext(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring name, + jstring function, + jobjectArray args); + +static jint DestoryInstance(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring name, + jstring function, + jobjectArray args); + +static jstring ExecJSOnInstance(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring script, + jint type); + +static void TakeHeapSnapshot(JNIEnv* env, jobject jcaller, + jstring filename); + +static void BindMeasurementToWXCore(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring ref, + jobject contentBoxMeasurement); + +static void SetRenderContainerWrapContent(JNIEnv* env, jobject jcaller, + jboolean wrap, + jstring instanceId); + +static jint PrintFirstScreenRenderTime(JNIEnv* env, jobject jcaller, + jstring instanceId); + +static jint PrintRenderFinishTime(JNIEnv* env, jobject jcaller, + jstring instanceId); + +static void SetDefaultHeightAndWidthIntoRootDom(JNIEnv* env, jobject jcaller, + jstring instanceId, + jfloat defaultWidth, + jfloat defaultHeight, + jboolean isWidthWrapContent, + jboolean isHeightWrapContent); + +static void OnInstanceClose(JNIEnv* env, jobject jcaller, + jstring instanceId); + +static void ForceLayout(JNIEnv* env, jobject jcaller, + jstring instanceId); + +static jboolean NotifyLayout(JNIEnv* env, jobject jcaller, + jstring instanceId); + +static void SetStyleWidth(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring ref, + jfloat value); + +static void SetStyleHeight(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring ref, + jfloat value); + +static void SetMargin(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring ref, + jint edge, + jfloat value); + +static void SetPadding(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring ref, + jint edge, + jfloat value); + +static void SetPosition(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring ref, + jint edge, + jfloat value); + +static void MarkDirty(JNIEnv* env, jobject jcaller, + jstring instanceId, + jstring ref, + jboolean dirty); + +static void RegisterCoreEnv(JNIEnv* env, jobject jcaller, + jstring key, + jstring value); + +static void SetViewPortWidth(JNIEnv* env, jobject jcaller, + jstring instanceId, + jfloat value); + +static void UpdateGlobalConfig(JNIEnv* env, jobject jcaller, + jstring config); + +// Step 2: method stubs. + +// Step 3: RegisterNatives. + +static const JNINativeMethod kMethodsWXBridge[] = { + { "nativeInitFrameworkEnv", +"(" +"Ljava/lang/String;" +"Lcom/taobao/weex/bridge/WXParams;" +"Ljava/lang/String;" +"Z" +")" +"I", reinterpret_cast<void*>(InitFrameworkEnv) }, + { "nativeInitFramework", +"(" +"Ljava/lang/String;" +"Lcom/taobao/weex/bridge/WXParams;" +")" +"I", reinterpret_cast<void*>(InitFramework) }, + { "nativeExecJS", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"Ljava/lang/String;" +"[Lcom/taobao/weex/bridge/WXJSObject;" +")" +"I", reinterpret_cast<void*>(ExecJS) }, + { "nativeExecJSService", +"(" +"Ljava/lang/String;" +")" +"I", reinterpret_cast<void*>(ExecJSService) }, + { "nativeExecJSWithResult", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"Ljava/lang/String;" +"[Lcom/taobao/weex/bridge/WXJSObject;" +")" +"[B", reinterpret_cast<void*>(ExecJSWithResult) }, + { "nativeCreateInstanceContext", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"Ljava/lang/String;" +"[Lcom/taobao/weex/bridge/WXJSObject;" +")" +"I", reinterpret_cast<void*>(CreateInstanceContext) }, + { "nativeDestoryInstance", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"Ljava/lang/String;" +"[Lcom/taobao/weex/bridge/WXJSObject;" +")" +"I", reinterpret_cast<void*>(DestoryInstance) }, + { "nativeExecJSOnInstance", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"I" +")" +"Ljava/lang/String;", reinterpret_cast<void*>(ExecJSOnInstance) }, + { "nativeTakeHeapSnapshot", +"(" +"Ljava/lang/String;" +")" +"V", reinterpret_cast<void*>(TakeHeapSnapshot) }, + { "nativeBindMeasurementToWXCore", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"Lcom/taobao/weex/layout/ContentBoxMeasurement;" +")" +"V", reinterpret_cast<void*>(BindMeasurementToWXCore) }, + { "nativeSetRenderContainerWrapContent", +"(" +"Z" +"Ljava/lang/String;" +")" +"V", reinterpret_cast<void*>(SetRenderContainerWrapContent) }, + { "nativePrintFirstScreenRenderTime", +"(" +"Ljava/lang/String;" +")" +"I", reinterpret_cast<void*>(PrintFirstScreenRenderTime) }, + { "nativePrintRenderFinishTime", +"(" +"Ljava/lang/String;" +")" +"I", reinterpret_cast<void*>(PrintRenderFinishTime) }, + { "nativeSetDefaultHeightAndWidthIntoRootDom", +"(" +"Ljava/lang/String;" +"F" +"F" +"Z" +"Z" +")" +"V", reinterpret_cast<void*>(SetDefaultHeightAndWidthIntoRootDom) }, + { "nativeOnInstanceClose", +"(" +"Ljava/lang/String;" +")" +"V", reinterpret_cast<void*>(OnInstanceClose) }, + { "nativeForceLayout", +"(" +"Ljava/lang/String;" +")" +"V", reinterpret_cast<void*>(ForceLayout) }, + { "nativeNotifyLayout", +"(" +"Ljava/lang/String;" +")" +"Z", reinterpret_cast<void*>(NotifyLayout) }, + { "nativeSetStyleWidth", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"F" +")" +"V", reinterpret_cast<void*>(SetStyleWidth) }, + { "nativeSetStyleHeight", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"F" +")" +"V", reinterpret_cast<void*>(SetStyleHeight) }, + { "nativeSetMargin", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"I" +"F" +")" +"V", reinterpret_cast<void*>(SetMargin) }, + { "nativeSetPadding", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"I" +"F" +")" +"V", reinterpret_cast<void*>(SetPadding) }, + { "nativeSetPosition", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"I" +"F" +")" +"V", reinterpret_cast<void*>(SetPosition) }, + { "nativeMarkDirty", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +"Z" +")" +"V", reinterpret_cast<void*>(MarkDirty) }, + { "nativeRegisterCoreEnv", +"(" +"Ljava/lang/String;" +"Ljava/lang/String;" +")" +"V", reinterpret_cast<void*>(RegisterCoreEnv) }, + { "nativeSetViewPortWidth", +"(" +"Ljava/lang/String;" +"F" +")" +"V", reinterpret_cast<void*>(SetViewPortWidth) }, + { "nativeUpdateGlobalConfig", +"(" +"Ljava/lang/String;" +")" +"V", reinterpret_cast<void*>(UpdateGlobalConfig) }, +}; + +static bool RegisterNativesImpl(JNIEnv* env) { + + g_WXBridge_clazz = reinterpret_cast<jclass>(env->NewGlobalRef( + base::android::GetClass(env, kWXBridgeClassPath).Get())); + + const int kMethodsWXBridgeSize = + sizeof(kMethodsWXBridge)/sizeof(kMethodsWXBridge[0]); + + if (env->RegisterNatives(WXBridge_clazz(env), + kMethodsWXBridge, + kMethodsWXBridgeSize) < 0) { + //jni_generator::HandleRegistrationError( + // env, WXBridge_clazz(env), __FILE__); + return false; + } + + return true; +} + +#endif // com_taobao_weex_bridge_WXBridge_JNI http://git-wip-us.apache.org/repos/asf/incubator-weex/blob/2f8caedb/weex_core/Source/android/jniprebuild/prebuild.sh ---------------------------------------------------------------------- diff --git a/weex_core/Source/android/jniprebuild/prebuild.sh b/weex_core/Source/android/jniprebuild/prebuild.sh new file mode 100755 index 0000000..a496821 --- /dev/null +++ b/weex_core/Source/android/jniprebuild/prebuild.sh @@ -0,0 +1,13 @@ +#!/bin/bash +CURRENT_PATH=$(cd `dirname $0`; pwd) +ROOT_WEEX_JAVA_PATH=$CURRENT_PATH"../../../../android/sdk/src/main/java/" +WEEX_OUTPUT_DIR=$CURRENT_PATH"/jniheader/" +WEEX_GEN_FILE=$CURRENT_PATH"/jni_generator.py" +while read line +do + file_name=${line##*/} + jni_file_name=${file_name%.*}"_jni.h" + input_file=$ROOT_WEEX_JAVA_PATH$line + output_file=$WEEX_OUTPUT_DIR$jni_file_name + python $WEEX_GEN_FILE $input_file $output_file +done < $CURRENT_PATH"/jni_files" \ No newline at end of file
