summaryrefslogtreecommitdiffstats
path: root/base/android
diff options
context:
space:
mode:
authorbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-07 19:06:51 +0000
committerbulach@chromium.org <bulach@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-11-07 19:06:51 +0000
commit2f8aa425134919f4573b8dd9ac85fd0b4310d8e2 (patch)
treebbf49efd48d56440814ed779028aa8ffceeeb398 /base/android
parent3e89600cff82761ccf4cad606b6ea6c12148fd65 (diff)
downloadchromium_src-2f8aa425134919f4573b8dd9ac85fd0b4310d8e2.zip
chromium_src-2f8aa425134919f4573b8dd9ac85fd0b4310d8e2.tar.gz
chromium_src-2f8aa425134919f4573b8dd9ac85fd0b4310d8e2.tar.bz2
Android: uses "import" section and inner classes for obtaining qualified JNI parameters.
Rather than explicitly listing all the parameters (see crbug.com/158722), infer almost all of them from the import section and inner classes. Assumes other classes are in the same package as a fallback. BUG=159397 TEST=base/android/jni_generator/jni_generator_tests.py Review URL: https://chromiumcodereview.appspot.com/11363079 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@166482 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/android')
-rw-r--r--base/android/jni_generator/SampleForTests.java2
-rw-r--r--base/android/jni_generator/class_list.jni50
-rwxr-xr-xbase/android/jni_generator/jni_generator.py112
-rwxr-xr-xbase/android/jni_generator/jni_generator_tests.py94
4 files changed, 106 insertions, 152 deletions
diff --git a/base/android/jni_generator/SampleForTests.java b/base/android/jni_generator/SampleForTests.java
index 6f8b1ca..341f0ea 100644
--- a/base/android/jni_generator/SampleForTests.java
+++ b/base/android/jni_generator/SampleForTests.java
@@ -4,6 +4,8 @@
package org.chromium.example.jni_generator;
+import android.graphics.Rect;
+
// This class serves as a reference test for the bindings generator, and as example documentation
// for how to use the jni generator.
// The C++ counter-part is sample_for_tests.cc.
diff --git a/base/android/jni_generator/class_list.jni b/base/android/jni_generator/class_list.jni
deleted file mode 100644
index 3395a3d..0000000
--- a/base/android/jni_generator/class_list.jni
+++ /dev/null
@@ -1,50 +0,0 @@
-# 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.
-
-# This file contains a list of JNI parameters used to generate the
-# bindings.
-# TODO(bulach): this file should only contain classes from base/ all other
-# classes should move to corresponding class_list.jni files closer to their own
-# directories. See crbug.com/158722
-Lcom/google/android/apps/chrome/ChromeContextMenuInfo
-Lcom/google/android/apps/chrome/ChromeWindow
-Lcom/google/android/apps/chrome/OmniboxSuggestion
-Lcom/google/android/apps/chrome/PageInfoViewer
-Lcom/google/android/apps/chrome/Tab
-Lcom/google/android/apps/chrome/infobar/AutoLogin
-Lcom/google/android/apps/chrome/infobar/InfoBarContainer
-Lcom/google/android/apps/chrome/infobar/InfoBarContainer$NativeInfoBar
-Lcom/google/android/apps/chrome/preferences/ChromeNativePreferences$PasswordListObserver
-Lorg/chromium/android_webview/AwContents
-Lorg/chromium/android_webview/AwContentsClient
-Lorg/chromium/android_webview/AwHttpAuthHandler
-Lorg/chromium/android_webview/AwContentsIoThreadClient
-Lorg/chromium/android_webview/AwWebContentsDelegate
-Lorg/chromium/android_webview/InterceptedRequestData
-Lorg/chromium/android_webview/JsPromptResultReceiver
-Lorg/chromium/android_webview/JsResultHandler
-Lorg/chromium/android_webview/JsResultReceiver
-Lorg/chromium/base/SystemMessageHandler
-Lorg/chromium/chrome/browser/component/navigation_interception/InterceptNavigationDelegate
-Lorg/chromium/chrome/browser/ChromeHttpAuthHandler
-Lorg/chromium/chrome/browser/ChromeWebContentsDelegateAndroid
-Lorg/chromium/content/app/SandboxedProcessService
-Lorg/chromium/content/browser/ContainerViewDelegate
-Lorg/chromium/content/browser/ContentVideoView
-Lorg/chromium/content/browser/ContentViewCore
-Lorg/chromium/content/browser/DeviceOrientation
-Lorg/chromium/content/browser/JavaInputStream
-Lorg/chromium/content/browser/LocationProvider
-Lorg/chromium/content/browser/SandboxedProcessArgs
-Lorg/chromium/content/browser/SandboxedProcessConnection
-Lorg/chromium/content/browser/TouchPoint
-Lorg/chromium/content/browser/WaitableNativeEvent
-Lorg/chromium/content/browser/WebContentsObserverAndroid
-Lorg/chromium/content/common/DeviceInfo
-Lorg/chromium/content/common/SurfaceTextureListener
-Lorg/chromium/media/MediaPlayerListener
-Lorg/chromium/net/NetworkChangeNotifier
-Lorg/chromium/net/ProxyChangeListener
-Lorg/chromium/ui/gfx/NativeWindow
-Lorg/chromium/ui/SelectFileDialog \ No newline at end of file
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 20595dd..8616240 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -94,6 +94,7 @@ def JavaDataTypeToC(java_type):
java_type_map = {
'void': 'void',
'String': 'jstring',
+ 'java/lang/String': 'jstring',
}
if java_type in java_pod_type_map:
return java_pod_type_map[java_type]
@@ -108,22 +109,29 @@ def JavaDataTypeToC(java_type):
class JniParams(object):
- _UNKNOWN_JAVA_TYPE_PREFIX = 'UNKNOWN_JAVA_TYPE: '
- _external_param_files = set()
- _external_param_list = []
+ _imports = []
+ _fully_qualified_class = ''
+ _package = ''
+ _inner_classes = []
@staticmethod
- def ReadExternalParamList(external_param_files):
- if not external_param_files:
- return
- assert not JniParams._external_param_files
- JniParams._external_param_files = set(external_param_files)
- for external_param_file in JniParams._external_param_files:
- with file(external_param_file, 'r') as f:
- contents = f.read()
- JniParams._external_param_list += [x.strip()
- for x in contents.splitlines()
- if x and not x.startswith('#')]
+ def SetFullyQualifiedClass(fully_qualified_class):
+ JniParams._fully_qualified_class = 'L' + fully_qualified_class
+ JniParams._package = '/'.join(fully_qualified_class.split('/')[:-1])
+
+ @staticmethod
+ def ExtractImportsAndInnerClasses(contents):
+ 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]
@staticmethod
def JavaToJni(param):
@@ -143,27 +151,6 @@ class JniParams(object):
'Ljava/lang/Long',
'Ljava/lang/Object',
'Ljava/lang/String',
- 'Ljava/util/ArrayList',
- 'Ljava/util/HashMap',
- 'Ljava/util/List',
- 'Landroid/content/Context',
- 'Landroid/graphics/Bitmap',
- 'Landroid/graphics/Canvas',
- 'Landroid/graphics/Rect',
- 'Landroid/graphics/RectF',
- 'Landroid/graphics/Matrix',
- 'Landroid/graphics/Point',
- 'Landroid/graphics/SurfaceTexture',
- 'Landroid/graphics/SurfaceTexture$OnFrameAvailableListener',
- 'Landroid/media/MediaPlayer',
- 'Landroid/os/Message',
- 'Landroid/view/KeyEvent',
- 'Landroid/view/Surface',
- 'Landroid/view/View',
- 'Landroid/webkit/ValueCallback',
- 'Ljava/io/InputStream',
- 'Ljava/nio/ByteBuffer',
- 'Ljava/util/Vector',
]
if param == 'byte[][]':
return '[[B'
@@ -180,13 +167,16 @@ class JniParams(object):
if '/' in param:
# Coming from javap, use the fully qualified param directly.
return 'L' + param + ';'
- for qualified_name in object_param_list + JniParams._external_param_list:
+ for qualified_name in (object_param_list +
+ JniParams._imports +
+ [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 + qualified_name + ';'
- else:
- return JniParams._UNKNOWN_JAVA_TYPE_PREFIX + prefix + param + ';'
+ # Type not found, falling back to same package as this class.
+ return prefix + 'L' + JniParams._package + '/' + param + ';'
@staticmethod
def Signature(params, returns, wrap):
@@ -217,33 +207,6 @@ class JniParams(object):
ret += [param]
return ret
- @staticmethod
- def CheckUnknownDatatypes(fully_qualified_class, items):
- unknown_datatypes = JniParams._GetUnknownDatatypes(items)
- if unknown_datatypes:
- msg = ('There are a few unknown datatypes in %s' %
- fully_qualified_class)
- msg += '\nPlease, edit %s' % str(JniParams._external_param_files)
- msg += '\nand add the JNI type(s):\n'
- for unknown_datatype in unknown_datatypes:
- msg += '\n%s in methods:\n' % unknown_datatype
- msg += '\n '.join(unknown_datatypes[unknown_datatype])
- raise SyntaxError(msg)
-
- @staticmethod
- def _GetUnknownDatatypes(items):
- """Returns a list containing the unknown datatypes."""
- unknown_types = {}
- for item in items:
- all_datatypes = ([JniParams.JavaToJni(param.datatype)
- for param in item.params] +
- [JniParams.JavaToJni(item.return_type)])
- for d in all_datatypes:
- if d.startswith(JniParams._UNKNOWN_JAVA_TYPE_PREFIX):
- unknown_types[d] = (unknown_types.get(d, []) +
- [item.name or 'Unable to parse'])
- return unknown_types
-
def ExtractJNINamespace(contents):
re_jni_namespace = re.compile('.*?@JNINamespace\("(.*?)"\)')
@@ -285,8 +248,10 @@ def ExtractNatives(contents):
def GetStaticCastForReturnType(return_type):
- if return_type == 'String':
+ if return_type in ['String', 'java/lang/String']:
return 'jstring'
+ elif return_type.endswith('[]'):
+ return 'jobjectArray'
return None
@@ -421,10 +386,11 @@ class JNIFromJavaP(object):
self.fully_qualified_class = re.match('.*?class (?P<class_name>.*?) ',
contents[1]).group('class_name')
self.fully_qualified_class = self.fully_qualified_class.replace('.', '/')
+ 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>\w+?) (?P<name>\w+?)'
+ re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
'\((?P<params>.*?)\)')
self.called_by_natives = []
for content in contents[2:]:
@@ -436,7 +402,7 @@ class JNIFromJavaP(object):
unchecked=False,
static='static' in match.group('prefix'),
java_class_name='',
- return_type=match.group('return_type'),
+ return_type=match.group('return_type').replace('.', '/'),
name=match.group('name'),
params=JniParams.Parse(match.group('params').replace('.', '/')))]
re_constructor = re.compile('.*? public ' +
@@ -479,6 +445,8 @@ class JNIFromJavaSource(object):
def __init__(self, contents, fully_qualified_class):
contents = self._RemoveComments(contents)
+ JniParams.SetFullyQualifiedClass(fully_qualified_class)
+ JniParams.ExtractImportsAndInnerClasses(contents)
jni_namespace = ExtractJNINamespace(contents)
natives = ExtractNatives(contents)
called_by_natives = ExtractCalledByNatives(contents)
@@ -529,8 +497,6 @@ class InlHeaderFileGenerator(object):
self.natives = natives
self.called_by_natives = called_by_natives
self.header_guard = fully_qualified_class.replace('/', '_') + '_JNI'
- JniParams.CheckUnknownDatatypes(self.fully_qualified_class,
- self.natives + self.called_by_natives)
def GetContent(self):
"""Returns the content of the JNI binding file."""
@@ -994,13 +960,7 @@ See SampleForTests.java for more details.
option_parser.add_option('--output_dir',
help='The output directory. Must be used with '
'--input')
- option_parser.add_option('--external_param_list',
- help='A file name containing a list with extra '
- 'fully-qualified param names. Can be used multiple '
- 'times.',
- action='append')
options, args = option_parser.parse_args(argv)
- JniParams.ReadExternalParamList(options.external_param_list)
if options.jar_file:
input_file = ExtractJarInputFile(options.jar_file, options.input_file,
options.output_dir)
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index 3dd9097..886b731 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -56,6 +56,7 @@ class TestGenerator(unittest.TestCase):
def testNatives(self):
test_data = """"
+ interface OnFrameAvailableListener {}
private native int nativeInit();
private native void nativeDestroy(int nativeChromeBrowserProvider);
private native long nativeAddBookmark(
@@ -82,6 +83,7 @@ class TestGenerator(unittest.TestCase):
int nativeDataFetcherImplAndroid,
double alpha, double beta, double gamma);
"""
+ jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
natives = jni_generator.ExtractNatives(test_data)
golden_natives = [
NativeMethod(return_type='int', static=False,
@@ -389,7 +391,7 @@ static bool RegisterNativesImpl(JNIEnv* env) {
{ "nativeGetInnerClass",
"("
")"
-"Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;",
+"Lorg/chromium/example/jni_generator/SampleForTests$OnFrameAvailableListener;",
reinterpret_cast<void*>(GetInnerClass) },
{ "nativeQueryBitmap",
"("
@@ -718,8 +720,14 @@ static bool RegisterNativesImpl(JNIEnv* env) {
def testCalledByNatives(self):
test_data = """"
+ import android.graphics.Bitmap;
+ import android.view.View;
+ import java.io.InputStream;
+
+ class InnerClass {}
+
@CalledByNative
- OnFrameAvailableListener showConfirmInfoBar(int nativeInfoBar,
+ InnerClass showConfirmInfoBar(int nativeInfoBar,
String buttonOk, String buttonCancel, String title, Bitmap icon) {
InfoBar infobar = new ConfirmInfoBar(nativeInfoBar, mContext,
buttonOk, buttonCancel,
@@ -727,7 +735,7 @@ static bool RegisterNativesImpl(JNIEnv* env) {
return infobar;
}
@CalledByNative
- OnFrameAvailableListener showAutoLoginInfoBar(int nativeInfoBar,
+ InnerClass showAutoLoginInfoBar(int nativeInfoBar,
String realm, String account, String args) {
AutoLoginInfoBar infobar = new AutoLoginInfoBar(nativeInfoBar, mContext,
realm, account, args);
@@ -762,10 +770,12 @@ static bool RegisterNativesImpl(JNIEnv* env) {
@CalledByNativeUnchecked
private void uncheckedCall(int iParam);
"""
+ jni_generator.JniParams.SetFullyQualifiedClass('org/chromium/Foo')
+ jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
called_by_natives = jni_generator.ExtractCalledByNatives(test_data)
golden_called_by_natives = [
CalledByNative(
- return_type='OnFrameAvailableListener',
+ return_type='InnerClass',
system_class=False,
static=False,
name='showConfirmInfoBar',
@@ -780,7 +790,7 @@ static bool RegisterNativesImpl(JNIEnv* env) {
unchecked=False,
),
CalledByNative(
- return_type='OnFrameAvailableListener',
+ return_type='InnerClass',
system_class=False,
static=False,
name='showAutoLoginInfoBar',
@@ -916,7 +926,7 @@ static ScopedJavaLocalRef<jobject> Java_TestJni_showConfirmInfoBar(JNIEnv* env,
"Ljava/lang/String;"
"Landroid/graphics/Bitmap;"
")"
-"Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;",
+"Lorg/chromium/Foo$InnerClass;",
&g_TestJni_showConfirmInfoBar);
jobject ret =
@@ -946,7 +956,7 @@ static ScopedJavaLocalRef<jobject> Java_TestJni_showAutoLoginInfoBar(JNIEnv*
"Ljava/lang/String;"
"Ljava/lang/String;"
")"
-"Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;",
+"Lorg/chromium/Foo$InnerClass;",
&g_TestJni_showAutoLoginInfoBar);
jobject ret =
@@ -1480,16 +1490,6 @@ static bool RegisterNativesImpl(JNIEnv* env) {
"""
jni_from_java = jni_generator.JNIFromJavaSource(test_data, 'foo/bar')
- def testRaisesOnUnknownDatatype(self):
- test_data = """
- class MyInnerClass {
- private native int nativeInit(AnUnknownDatatype p0);
- }
- """
- self.assertRaises(SyntaxError,
- jni_generator.JNIFromJavaSource,
- test_data, 'foo/bar')
-
def testRaisesOnNonJNIMethod(self):
test_data = """
class MyInnerClass {
@@ -1527,15 +1527,57 @@ static bool RegisterNativesImpl(JNIEnv* env) {
self.assertTrue(len(line) > 80,
('Expected #ifndef line to be > 80 chars: ', line))
- def testExternalParamList(self):
- script_dir = os.path.dirname(sys.argv[0])
- external_param_list = [os.path.join(script_dir, 'class_list.jni')]
- jni_generator.JniParams.ReadExternalParamList(external_param_list)
- self.assertTrue('Lorg/chromium/base/SystemMessageHandler' in
- jni_generator.JniParams._external_param_list)
- self.assertRaises(AssertionError,
- jni_generator.JniParams.ReadExternalParamList,
- external_param_list)
+ def testImports(self):
+ import_header = """
+// 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.
+
+package org.chromium.content.app;
+
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.util.ArrayList;
+
+import org.chromium.base.CalledByNative;
+import org.chromium.base.JNINamespace;
+import org.chromium.content.app.ContentMain;
+import org.chromium.content.browser.SandboxedProcessConnection;
+import org.chromium.content.common.ISandboxedProcessCallback;
+import org.chromium.content.common.ISandboxedProcessService;
+import org.chromium.content.common.SurfaceCallback;
+
+import static org.chromium.Bar.Zoo;
+
+class Foo {
+ public static class BookmarkNode implements Parcelable {
+ }
+ public interface PasswordListObserver {
+ }
+}
+ """
+ jni_generator.JniParams.SetFullyQualifiedClass(
+ 'org/chromium/content/app/Foo')
+ jni_generator.JniParams.ExtractImportsAndInnerClasses(import_header)
+ self.assertTrue('Lorg/chromium/content/common/ISandboxedProcessService' in
+ jni_generator.JniParams._imports)
+ self.assertTrue('Lorg/chromium/Bar/Zoo' in
+ jni_generator.JniParams._imports)
+ self.assertTrue('Lorg/chromium/content/app/Foo$BookmarkNode' in
+ jni_generator.JniParams._inner_classes)
+ self.assertTrue('Lorg/chromium/content/app/Foo$PasswordListObserver' in
+ jni_generator.JniParams._inner_classes)
+
if __name__ == '__main__':
unittest.main()