diff options
author | sl.ostapenko@samsung.com <sl.ostapenko@samsung.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-07 08:44:55 +0000 |
---|---|---|
committer | sl.ostapenko@samsung.com <sl.ostapenko@samsung.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-07 08:44:55 +0000 |
commit | 1d70cc60526e7cb00f5e2f293f951f202ed016e6 (patch) | |
tree | a473590f0ffb07bbe0e834cd306cf62a70480ef8 | |
parent | 33ed90e0e7389ef045de283bbe2bdab2e3a91f4f (diff) | |
download | chromium_src-1d70cc60526e7cb00f5e2f293f951f202ed016e6.zip chromium_src-1d70cc60526e7cb00f5e2f293f951f202ed016e6.tar.gz chromium_src-1d70cc60526e7cb00f5e2f293f951f202ed016e6.tar.bz2 |
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
-rwxr-xr-x | base/android/jni_generator/jni_generator.py | 82 | ||||
-rwxr-xr-x | base/android/jni_generator/jni_generator_tests.py | 41 | ||||
-rw-r--r-- | base/android/jni_generator/testNativeExportsOption.golden | 216 | ||||
-rw-r--r-- | build/android/android_exports.lst | 14 | ||||
-rw-r--r-- | build/common.gypi | 19 | ||||
-rw-r--r-- | build/jar_file_jni_generator.gypi | 1 | ||||
-rw-r--r-- | build/jni_generator.gypi | 1 | ||||
-rw-r--r-- | mojo/mojo_public.gypi | 20 | ||||
-rw-r--r-- | mojo/mojo_services.gypi | 8 |
9 files changed, 383 insertions, 19 deletions
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py index 35a7510..5018cf53 100755 --- a/base/android/jni_generator/jni_generator.py +++ b/base/android/jni_generator/jni_generator.py @@ -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, diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py index 6b7c010..98dd8de 100755 --- a/base/android/jni_generator/jni_generator_tests.py +++ b/base/android/jni_generator/jni_generator_tests.py @@ -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; diff --git a/base/android/jni_generator/testNativeExportsOption.golden b/base/android/jni_generator/testNativeExportsOption.golden new file mode 100644 index 0000000..231be7c --- /dev/null +++ b/base/android/jni_generator/testNativeExportsOption.golden @@ -0,0 +1,216 @@ +// 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 diff --git a/build/android/android_exports.lst b/build/android/android_exports.lst new file mode 100644 index 0000000..820d6ec --- /dev/null +++ b/build/android/android_exports.lst @@ -0,0 +1,14 @@ +# 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: *; +}; diff --git a/build/common.gypi b/build/common.gypi index 73c2a44..a1a9b79 100644 --- a/build/common.gypi +++ b/build/common.gypi @@ -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 diff --git a/build/jar_file_jni_generator.gypi b/build/jar_file_jni_generator.gypi index dc43c49..59ab64e 100644 --- a/build/jar_file_jni_generator.gypi +++ b/build/jar_file_jni_generator.gypi @@ -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, diff --git a/build/jni_generator.gypi b/build/jni_generator.gypi index da99331..da4b880 100644 --- a/build/jni_generator.gypi +++ b/build/jni_generator.gypi @@ -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, diff --git a/mojo/mojo_public.gypi b/mojo/mojo_public.gypi index fc4a2c2..8f10f5c 100644 --- a/mojo/mojo_public.gypi +++ b/mojo/mojo_public.gypi @@ -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. diff --git a/mojo/mojo_services.gypi b/mojo/mojo_services.gypi index b2da5f2..eaedd51 100644 --- a/mojo/mojo_services.gypi +++ b/mojo/mojo_services.gypi @@ -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', + ], }], ], }, |