Remove unneeded JNI registrations.

Rather than registering all jni bindings at startup, only get references
to the class object for those files which require bindings. All others
are satisfied by exporting symbols which can be found automatically by
dalvik.

This patch replaces excldue-libs=ALL with ld version script to strip unwanted
symbols: https://sourceware.org/binutils/docs-2.24/ld/VERSION.html#VERSION

BUG=

Review URL: https://codereview.chromium.org/147533004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@275652 0039d316-1c4b-4281-b951-d872f2087c98
parent 33ed90e0
......@@ -793,6 +793,8 @@ jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
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):
......@@ -814,6 +816,9 @@ jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
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):
......@@ -859,6 +864,8 @@ jmethodID g_${JAVA_CLASS}_${METHOD_ID_VAR_NAME} = NULL;""")
def GetJNINativeMethodsString(self):
"""Returns the implementation of the array of native methods."""
if self.options.native_exports:
return ''
template = Template("""\
static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
${KMETHODS}
......@@ -913,6 +920,9 @@ ${CALLED_BY_NATIVES}
def GetRegisterNativesImplString(self):
"""Returns the shared implementation for RegisterNatives."""
if self.options.native_exports:
return ''
template = Template("""\
const int kMethods${JAVA_CLASS}Size = arraysize(kMethods${JAVA_CLASS});
......@@ -937,11 +947,17 @@ Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
return ${NAMESPACE}RegisterNativesImpl(env, clazz);
}
""")
fully_qualified_class = self.fully_qualified_class.replace('/', '_')
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': fully_qualified_class,
values = {'FULLY_QUALIFIED_CLASS': java_name,
'INIT_NATIVE_NAME': 'native' + self.init_native.name,
'NAMESPACE': namespace,
'REGISTER_NATIVES_IMPL': self.GetRegisterNativesImplString()
......@@ -995,23 +1011,52 @@ Java_${FULLY_QUALIFIED_CLASS}_${INIT_NATIVE_NAME}(JNIEnv* env, jclass clazz) {
for param in called_by_native.params])
def GetForwardDeclaration(self, native):
template = Template("""
template_str = """
static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
""")
"""
if self.options.native_exports:
template_str += """
__attribute__((visibility("default")))
${RETURN} Java_${JAVA_NAME}_native${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])
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 = {'RETURN': JavaDataTypeToC(native.return_type),
'NAME': native.name,
'PARAMS': self.GetParamsInDeclaration(native)}
'JAVA_NAME': java_name,
'PARAMS': self.GetParamsInDeclaration(native),
'PARAMS_IN_CALL': params_in_call}
return template.substitute(values)
def GetNativeMethodStubString(self, native):
"""Returns stubs for native methods."""
template = Template("""\
static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {
if self.options.native_exports:
template_str = """\
__attribute__((visibility("default")))
${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env,
${PARAMS_IN_DECLARATION}) {"""
else:
template_str = """\
static ${RETURN} ${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']
......@@ -1024,9 +1069,19 @@ static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {
post_call = ''
if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
post_call = '.Release()'
if self.options.native_exports:
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
else:
java_name = ''
values = {
'RETURN': return_type,
'OPTIONAL_ERROR_RETURN': optional_error_return,
'JAVA_NAME': java_name,
'NAME': native.name,
'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
'PARAM0_NAME': native.params[0].name,
......@@ -1174,8 +1229,12 @@ ${FUNCTION_HEADER}
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)
all_classes = native_classes
all_classes.update(called_by_native_classes)
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,
......@@ -1394,6 +1453,9 @@ See SampleForTests.java for more details.
help='The path to cpp command.')
option_parser.add_option('--javap', default='javap',
help='The path to javap command.')
option_parser.add_option('--native_exports', action='store_true',
help='Native method registration through .so '
'exports.')
options, args = option_parser.parse_args(argv)
if options.jar_file:
input_file = ExtractJarInputFile(options.jar_file, options.input_file,
......
......@@ -42,7 +42,7 @@ class TestOptions(object):
self.eager_called_by_natives = False
self.cpp = 'cpp'
self.javap = 'javap'
self.native_exports = False
class TestGenerator(unittest.TestCase):
def assertObjEquals(self, first, second):
......@@ -996,6 +996,45 @@ class Foo {
test_data, 'org/chromium/example/jni_generator/Test', options)
self.assertGoldenTextEquals(jni_from_java.GetContent())
def testNativeExportsOption(self):
test_data = """
package org.chromium.example.jni_generator;
/** The pointer to the native Test. */
long nativeTest;
class Test {
private static native boolean nativeInitNativeClass();
private static native int nativeStaticMethod(long nativeTest, int arg1);
private native int nativeMethod(long nativeTest, int arg1);
@CalledByNative
private void testMethodWithParam(int iParam);
@CalledByNative
private String testMethodWithParamAndReturn(int iParam);
@CalledByNative
private static int testStaticMethodWithParam(int iParam);
@CalledByNative
private static double testMethodWithNoParam();
@CalledByNative
private static String testStaticMethodWithNoParam();
class MyInnerClass {
@NativeCall("MyInnerClass")
private native int nativeInit();
}
class MyOtherInnerClass {
@NativeCall("MyOtherInnerClass")
private native int nativeInit();
}
}
"""
options = TestOptions()
options.jni_init_native_name = 'nativeInitNativeClass'
options.native_exports = True
jni_from_java = jni_generator.JNIFromJavaSource(
test_data, 'org/chromium/example/jni_generator/SampleForTests', options)
self.assertGoldenTextEquals(jni_from_java.GetContent())
def testOuterInnerRaises(self):
test_data = """
package org.chromium.media;
......
// 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
// base/android/jni_generator/jni_generator.py
// For
// org/chromium/example/jni_generator/SampleForTests
#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
#define org_chromium_example_jni_generator_SampleForTests_JNI
#include <jni.h>
#include "base/android/jni_generator/jni_generator_helper.h"
#include "base/android/jni_int_wrapper.h"
// Step 1: forward declarations.
namespace {
const char kSampleForTestsClassPath[] =
"org/chromium/example/jni_generator/SampleForTests";
// Leaking this jclass as we cannot use LazyInstance from some threads.
jclass g_SampleForTests_clazz = NULL;
} // namespace
extern "C" {
static jint Init(JNIEnv* env, jobject jcaller);
__attribute__((visibility("default")))
jint
Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
env, jobject jcaller) {
return Init(env, jcaller);
}
static jint Init(JNIEnv* env, jobject jcaller);
__attribute__((visibility("default")))
jint
Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
env, jobject jcaller) {
return Init(env, jcaller);
}
}; // extern "C"
// Step 2: method stubs.
extern "C" {
__attribute__((visibility("default")))
jint
Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
env,
jobject jcaller,
jlong nativeTest,
jint arg1) {
Test* native = reinterpret_cast<Test*>(nativeTest);
CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
return native->StaticMethod(env, jcaller, arg1);
}
__attribute__((visibility("default")))
jint
Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
env,
jobject jcaller,
jlong nativeTest,
jint arg1) {
Test* native = reinterpret_cast<Test*>(nativeTest);
CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
return native->Method(env, jcaller, arg1);
}
static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
JniIntWrapper iParam) {
/* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, obj,
g_SampleForTests_clazz);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, g_SampleForTests_clazz,
"testMethodWithParam",
"("
"I"
")"
"V",
&g_SampleForTests_testMethodWithParam);
env->CallVoidMethod(obj,
method_id, as_jint(iParam));
jni_generator::CheckException(env);
}
static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
0;
static base::android::ScopedJavaLocalRef<jstring>
Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
JniIntWrapper iParam) {
/* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, obj,
g_SampleForTests_clazz, NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_INSTANCE>(
env, g_SampleForTests_clazz,
"testMethodWithParamAndReturn",
"("
"I"
")"
"Ljava/lang/String;",
&g_SampleForTests_testMethodWithParamAndReturn);
jstring ret =
static_cast<jstring>(env->CallObjectMethod(obj,
method_id, as_jint(iParam)));
jni_generator::CheckException(env);
return base::android::ScopedJavaLocalRef<jstring>(env, ret);
}
static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
JniIntWrapper iParam) {
/* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, g_SampleForTests_clazz,
g_SampleForTests_clazz, 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_STATIC>(
env, g_SampleForTests_clazz,
"testStaticMethodWithParam",
"("
"I"
")"
"I",
&g_SampleForTests_testStaticMethodWithParam);
jint ret =
env->CallStaticIntMethod(g_SampleForTests_clazz,
method_id, as_jint(iParam));
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
/* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, g_SampleForTests_clazz,
g_SampleForTests_clazz, 0);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_STATIC>(
env, g_SampleForTests_clazz,
"testMethodWithNoParam",
"("
")"
"D",
&g_SampleForTests_testMethodWithNoParam);
jdouble ret =
env->CallStaticDoubleMethod(g_SampleForTests_clazz,
method_id);
jni_generator::CheckException(env);
return ret;
}
static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
0;
static base::android::ScopedJavaLocalRef<jstring>
Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
/* Must call RegisterNativesImpl() */
CHECK_CLAZZ(env, g_SampleForTests_clazz,
g_SampleForTests_clazz, NULL);
jmethodID method_id =
base::android::MethodID::LazyGet<
base::android::MethodID::TYPE_STATIC>(
env, g_SampleForTests_clazz,
"testStaticMethodWithNoParam",
"("
")"
"Ljava/lang/String;",
&g_SampleForTests_testStaticMethodWithNoParam);
jstring ret =
static_cast<jstring>(env->CallStaticObjectMethod(g_SampleForTests_clazz,
method_id));
jni_generator::CheckException(env);
return base::android::ScopedJavaLocalRef<jstring>(env, ret);
}
}; // extern "C"
// Step 3: RegisterNatives.
static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
g_SampleForTests_clazz = static_cast<jclass>(env->NewWeakGlobalRef(clazz));
return true;
}
extern "C" JNIEXPORT bool JNICALL
Java_org_chromium_example_jni_1generator_SampleForTests_nativeInitNativeClass(JNIEnv*
env, jclass clazz) {
return RegisterNativesImpl(env, clazz);
}
#endif // org_chromium_example_jni_generator_SampleForTests_JNI
# 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.
# Default exports specification for chromium shared libraries on android.
# Check ld version script manual:
# https://sourceware.org/binutils/docs-2.24/ld/VERSION.html#VERSION
{
global:
Java_*_native*;
JNI_OnLoad;
local: *;
};
......@@ -1731,6 +1731,9 @@
# Copy it out one scope.
'android_webview_build%': '<(android_webview_build)',
# Default android linker script for shared library exports.
'android_linker_script%': '<!(cd <(DEPTH) && pwd -P)/build/android/android_exports.lst',
}], # OS=="android"
['android_webview_build==1', {
# When building the WebView in the Android tree, jarjar will remap all
......@@ -4150,7 +4153,13 @@
},
'target_conditions': [
['_type=="shared_library"', {
'product_extension': '<(android_product_extension)',
'product_extension': '<(android_product_extension)',
}],
['_toolset=="target" and component=="static_library" and _type=="shared_library"', {
'ldflags': [
# Only export symbols that are specified in version script.
'-Wl,--version-script=<(android_linker_script)',
],
}],
# Settings for building device targets using Android's toolchain.
......@@ -4216,8 +4225,7 @@
'ldflags': [
'-nostdlib',
'-Wl,--no-undefined',
# Don't export symbols from statically linked libraries.
'-Wl,--exclude-libs=ALL',
],
'libraries': [
'-l<(android_stlport_library)',
......@@ -4228,11 +4236,6 @@
'-lm',
],
'conditions': [
['component=="shared_library"', {
'ldflags!': [
'-Wl,--exclude-libs=ALL',
],
}],
['clang==1', {
'cflags': [
# Work around incompatibilities between bionic and clang
......
......@@ -54,6 +54,7 @@
'<(jni_generator_includes)',
'--optimize_generation',
'<(optimize_jni_generation)',
'--native_exports',
],
'message': 'Generating JNI bindings from <(input_jar_file)/<(input_java_class)',
'process_outputs_as_sources': 1,
......
......@@ -61,6 +61,7 @@
'<(jni_generator_jarjar_file)',
'--ptr_type',
'<(jni_generator_ptr_type)',
'--native_exports',
],
'message': 'Generating JNI bindings from <(RULE_INPUT_PATH)',
'process_outputs_as_sources': 1,
......
......@@ -66,6 +66,16 @@
'public/gles2/gles2_private.h',
],
'conditions': [
['OS=="android"', {
'ldflags!': [
# Remove default export list because this lib has different exports.
'-Wl,--version-script=<(android_linker_script)',
],
'ldflags': [
# Don't export symbols from statically linked libraries.
'-Wl,--exclude-libs=ALL',
],
}],
['OS=="mac"', {
'xcode_settings': {
# Make it a run-path dependent library.
......@@ -95,6 +105,16 @@
'public/tests/test_support_private.h',
],
'conditions': [
['OS=="android"', {
'ldflags!': [
# Remove default export list because this lib has different exports.
'-Wl,--version-script=<(android_linker_script)',
],
'ldflags': [
# Don't export symbols from statically linked libraries.
'-Wl,--exclude-libs=ALL',
],
}],
['OS=="mac"', {
'xcode_settings': {
# Make it a run-path dependent library.
......
......@@ -179,6 +179,14 @@
'dependencies': [
'mojo_jni_headers',
],
'ldflags!': [
# Remove default export list because this lib has different exports.
'-Wl,--version-script=<(android_linker_script)',
],
'ldflags': [
# Don't export symbols from statically linked libraries.
'-Wl,--exclude-libs=ALL',
],
}],
],
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment