Merge commit '1940731af14148e5a80066fe0ff471f40b9182a5' into HEAD
diff --git a/base/android/jni_generator/golden_sample_for_tests_jni.h b/base/android/jni_generator/golden_sample_for_tests_jni.h
index 2c5f6c0..2767665 100644
--- a/base/android/jni_generator/golden_sample_for_tests_jni.h
+++ b/base/android/jni_generator/golden_sample_for_tests_jni.h
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 // This file is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     org/chromium/example/jni_generator/SampleForTests
 
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index de865d5..649182a 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -53,7 +53,7 @@
       assert type(self.params) is list
       assert type(self.params[0]) is Param
     if (self.params and
-        self.params[0].datatype == 'int' 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'):]
@@ -76,6 +76,7 @@
     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)
@@ -141,6 +142,11 @@
                                      inner]
 
   @staticmethod
+  def ParseJavaPSignature(signature_line):
+    prefix = 'Signature: '
+    return '"%s"' % signature_line[signature_line.index(prefix) + len(prefix):]
+
+  @staticmethod
   def JavaToJni(param):
     """Converts a java param into a JNI signature type."""
     pod_param_map = {
@@ -284,7 +290,7 @@
           os.path.splitext(os.path.basename(java_file_name))[0])
 
 
-def ExtractNatives(contents):
+def ExtractNatives(contents, ptr_type):
   """Returns a list of dict containing information about a native method."""
   contents = contents.replace('\n', '')
   natives = []
@@ -301,7 +307,8 @@
         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')))
+        params=JniParams.Parse(match.group('params')),
+        ptr_type=ptr_type)
     natives += [native]
   return natives
 
@@ -449,13 +456,16 @@
 class JNIFromJavaP(object):
   """Uses 'javap' to parse a .class file and generate the JNI header file."""
 
-  def __init__(self, contents, namespace):
+  def __init__(self, contents, options):
     self.contents = contents
-    self.namespace = namespace
+    self.namespace = options.namespace
     self.fully_qualified_class = re.match(
         '.*?(class|interface) (?P<class_name>.*?)( |{)',
         contents[1]).group('class_name')
     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:
@@ -463,7 +473,7 @@
     re_method = re.compile('(?P<prefix>.*?)(?P<return_type>\S+?) (?P<name>\w+?)'
                            '\((?P<params>.*?)\)')
     self.called_by_natives = []
-    for content in contents[2:]:
+    for lineno, content in enumerate(contents[2:], 2):
       match = re.match(re_method, content)
       if not match:
         continue
@@ -474,11 +484,12 @@
           java_class_name='',
           return_type=match.group('return_type').replace('.', '/'),
           name=match.group('name'),
-          params=JniParams.Parse(match.group('params').replace('.', '/')))]
-    re_constructor = re.compile('.*? public ' +
+          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 content in contents[2:]:
+    for lineno, content in enumerate(contents[2:], 2):
       match = re.match(re_constructor, content)
       if not match:
         continue
@@ -490,41 +501,44 @@
           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.inl_header_file_generator = InlHeaderFileGenerator(
-        self.namespace, self.fully_qualified_class, [], self.called_by_natives)
+        self.namespace, self.fully_qualified_class, [],
+        self.called_by_natives, options)
 
   def GetContent(self):
     return self.inl_header_file_generator.GetContent()
 
   @staticmethod
-  def CreateFromClass(class_file, namespace):
+  def CreateFromClass(class_file, options):
     class_name = os.path.splitext(os.path.basename(class_file))[0]
-    p = subprocess.Popen(args=['javap', class_name],
+    p = subprocess.Popen(args=['javap', '-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'), namespace)
+    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."""
 
-  def __init__(self, contents, fully_qualified_class):
+  def __init__(self, contents, fully_qualified_class, options):
     contents = self._RemoveComments(contents)
     JniParams.SetFullyQualifiedClass(fully_qualified_class)
     JniParams.ExtractImportsAndInnerClasses(contents)
     jni_namespace = ExtractJNINamespace(contents)
-    natives = ExtractNatives(contents)
+    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)
+        jni_namespace, fully_qualified_class, natives, called_by_natives,
+        options)
     self.content = inl_header_file_generator.GetContent()
 
   def _RemoveComments(self, contents):
@@ -549,24 +563,25 @@
     return self.content
 
   @staticmethod
-  def CreateFromFile(java_file_name):
+  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)
+    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):
+               called_by_natives, 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.script_name = options.script_name
 
   def GetContent(self):
     """Returns the content of the JNI binding file."""
@@ -613,11 +628,8 @@
 $CLOSE_NAMESPACE
 #endif  // ${HEADER_GUARD}
 """)
-    script_components = os.path.abspath(sys.argv[0]).split(os.path.sep)
-    base_index = script_components.index('base')
-    script_name = os.sep.join(script_components[base_index:])
     values = {
-        'SCRIPT_NAME': script_name,
+        'SCRIPT_NAME': self.script_name,
         'FULLY_QUALIFIED_CLASS': self.fully_qualified_class,
         'CLASS_PATH_DEFINITIONS': self.GetClassPathDefinitionsString(),
         'FORWARD_DECLARATIONS': self.GetForwardDeclarationsString(),
@@ -928,14 +940,18 @@
     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',
-        'JNI_SIGNATURE': JniParams.Signature(called_by_native.params,
-                                             jni_return_type,
-                                             True)
+        'JNI_SIGNATURE': signature,
     }
     return template.substitute(values)
 
@@ -990,13 +1006,14 @@
   return extracted_file_name
 
 
-def GenerateJNIHeader(input_file, output_file, namespace, skip_if_same):
+def GenerateJNIHeader(input_file, output_file, options):
   try:
     if os.path.splitext(input_file)[1] == '.class':
-      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, namespace)
+      jni_from_javap = JNIFromJavaP.CreateFromClass(input_file, options)
       content = jni_from_javap.GetContent()
     else:
-      jni_from_java_source = JNIFromJavaSource.CreateFromFile(input_file)
+      jni_from_java_source = JNIFromJavaSource.CreateFromFile(
+          input_file, options)
       content = jni_from_java_source.GetContent()
   except ParseError, e:
     print e
@@ -1004,7 +1021,7 @@
   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 skip_if_same and os.path.exists(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:
@@ -1015,6 +1032,16 @@
     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:])
+
+
 def main(argv):
   usage = """usage: %prog [OPTIONS]
 This script will parse the given java source code extracting the native
@@ -1044,12 +1071,24 @@
                            'not changed.')
   option_parser.add_option('--jarjar',
                            help='Path to optional jarjar rules file.')
+  option_parser.add_option('--script_name', default=GetScriptName(),
+                           help='The name of this script in the generated '
+                           'header.')
+  option_parser.add_option('--ptr_type', default='int',
+                           type='choice', choices=['int', 'long'],
+                           help='The type used to represent native pointers in '
+                           'Java code. For 32-bit, use int; '
+                           'for 64-bit, use long.')
   options, args = option_parser.parse_args(argv)
   if options.jar_file:
     input_file = ExtractJarInputFile(options.jar_file, options.input_file,
                                      options.output_dir)
-  else:
+  elif options.input_file:
     input_file = options.input_file
+  else:
+    option_parser.print_help()
+    print '\nError: Must specify --jar_file or --input_file.'
+    return 1
   output_file = None
   if options.output_dir:
     root_name = os.path.splitext(os.path.basename(input_file))[0]
@@ -1057,8 +1096,7 @@
   if options.jarjar:
     with open(options.jarjar) as f:
       JniParams.SetJarJarMappings(f.read())
-  GenerateJNIHeader(input_file, output_file, options.namespace,
-                    options.optimize_generation)
+  GenerateJNIHeader(input_file, output_file, options)
 
 
 if __name__ == '__main__':
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index f008f39..cb32501 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -19,6 +19,18 @@
 from jni_generator import CalledByNative, JniParams, NativeMethod, Param
 
 
+SCRIPT_NAME = 'base/android/jni_generator/jni_generator.py'
+
+
+class TestOptions(object):
+  """The mock options object which is passed to the jni_generator.py script."""
+
+  def __init__(self):
+    self.namespace = None
+    self.script_name = SCRIPT_NAME
+    self.ptr_type = 'int'
+
+
 class TestGenerator(unittest.TestCase):
   def assertObjEquals(self, first, second):
     dict_first = first.__dict__
@@ -84,7 +96,7 @@
             double alpha, double beta, double gamma);
     """
     jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
-    natives = jni_generator.ExtractNatives(test_data)
+    natives = jni_generator.ExtractNatives(test_data, 'int')
     golden_natives = [
         NativeMethod(return_type='int', static=False,
                      name='Init',
@@ -206,14 +218,14 @@
     ]
     self.assertListEquals(golden_natives, natives)
     h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
-                                             natives, [])
+                                             natives, [], TestOptions())
     golden_content = """\
 // 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 is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     org/chromium/TestJni
 
@@ -434,7 +446,7 @@
       private native int nativeInit();
     }
     """
-    natives = jni_generator.ExtractNatives(test_data)
+    natives = jni_generator.ExtractNatives(test_data, 'int')
     golden_natives = [
         NativeMethod(return_type='int', static=False,
                      name='Init', params=[],
@@ -443,14 +455,14 @@
     ]
     self.assertListEquals(golden_natives, natives)
     h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
-                                             natives, [])
+                                             natives, [], TestOptions())
     golden_content = """\
 // 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 is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     org/chromium/TestJni
 
@@ -517,7 +529,7 @@
       private native int nativeInit();
     }
     """
-    natives = jni_generator.ExtractNatives(test_data)
+    natives = jni_generator.ExtractNatives(test_data, 'int')
     golden_natives = [
         NativeMethod(return_type='int', static=False,
                      name='Init', params=[],
@@ -530,14 +542,14 @@
     ]
     self.assertListEquals(golden_natives, natives)
     h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
-                                             natives, [])
+                                             natives, [], TestOptions())
     golden_content = """\
 // 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 is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     org/chromium/TestJni
 
@@ -623,7 +635,7 @@
       }
     }
     """
-    natives = jni_generator.ExtractNatives(test_data)
+    natives = jni_generator.ExtractNatives(test_data, 'int')
     golden_natives = [
         NativeMethod(return_type='int', static=False,
                      name='Init', params=[],
@@ -636,14 +648,14 @@
     ]
     self.assertListEquals(golden_natives, natives)
     h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
-                                             natives, [])
+                                             natives, [], TestOptions())
     golden_content = """\
 // 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 is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     org/chromium/TestJni
 
@@ -1024,14 +1036,15 @@
     ]
     self.assertListEquals(golden_called_by_natives, called_by_natives)
     h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
-                                             [], called_by_natives)
+                                             [], called_by_natives,
+                                             TestOptions())
     golden_content = """\
 // 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 is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     org/chromium/TestJni
 
@@ -1566,23 +1579,137 @@
                    datatype='java/lang/String'),],
              'java/io/InputStream'))
 
-  def testFromJavaP(self):
+  def testFromJavaPGenerics(self):
     contents = """
-public abstract class java.io.InputStream extends java.lang.Object
-      implements java.io.Closeable{
-    public java.io.InputStream();
-    public int available()       throws java.io.IOException;
-    public void close()       throws java.io.IOException;
-    public void mark(int);
-    public boolean markSupported();
-    public abstract int read()       throws java.io.IOException;
-    public int read(byte[])       throws java.io.IOException;
-    public int read(byte[], int, int)       throws java.io.IOException;
-    public synchronized void reset()       throws java.io.IOException;
-    public long skip(long)       throws java.io.IOException;
+public abstract class java.util.HashSet<T> extends java.util.AbstractSet<E>
+      implements java.util.Set<E>, java.lang.Cloneable, java.io.Serializable {
+    public void dummy();
+  Signature: ()V
 }
 """
-    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'), None)
+    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                TestOptions())
+    self.assertEquals(1, len(jni_from_javap.called_by_natives))
+    golden_content = """\
+// 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 is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     java/util/HashSet
+
+#ifndef java_util_HashSet_JNI
+#define java_util_HashSet_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kHashSetClassPath[] = "java/util/HashSet";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_HashSet_clazz = NULL;
+}  // namespace
+
+namespace JNI_HashSet {
+
+// Step 2: method stubs.
+
+static base::subtle::AtomicWord g_HashSet_dummy = 0;
+static void Java_HashSet_dummy(JNIEnv* env, jobject obj) __attribute__
+    ((unused));
+static void Java_HashSet_dummy(JNIEnv* env, jobject obj) {
+  /* Must call RegisterNativesImpl()  */
+  DCHECK(g_HashSet_clazz);
+  jmethodID method_id =
+      base::android::MethodID::LazyGet<
+      base::android::MethodID::TYPE_INSTANCE>(
+      env, g_HashSet_clazz,
+      "dummy",
+"()V",
+      &g_HashSet_dummy);
+
+  env->CallVoidMethod(obj,
+      method_id);
+  base::android::CheckException(env);
+
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_HashSet_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kHashSetClassPath).obj()));
+  return true;
+}
+}  // namespace JNI_HashSet
+
+#endif  // java_util_HashSet_JNI
+"""
+    self.assertTextEquals(golden_content, jni_from_javap.GetContent())
+
+  def testSnippnetJavap6_7(self):
+    content_javap6 = """
+public class java.util.HashSet {
+public boolean add(java.lang.Object);
+ Signature: (Ljava/lang/Object;)Z
+}
+"""
+
+    content_javap7 = """
+public class java.util.HashSet {
+public boolean add(E);
+  Signature: (Ljava/lang/Object;)Z
+}
+"""
+    jni_from_javap6 = jni_generator.JNIFromJavaP(content_javap6.split('\n'),
+                                                 TestOptions())
+    jni_from_javap7 = jni_generator.JNIFromJavaP(content_javap7.split('\n'),
+                                                 TestOptions())
+    self.assertTrue(jni_from_javap6.GetContent())
+    self.assertTrue(jni_from_javap7.GetContent())
+    # Ensure the javap7 is correctly parsed and uses the Signature field rather
+    # than the "E" parameter.
+    self.assertTextEquals(jni_from_javap6.GetContent(),
+                          jni_from_javap7.GetContent())
+
+  def testFromJavaP(self):
+    contents = """
+public abstract class java.io.InputStream extends
+  java.lang.Object implements java.io.Closeable{
+public java.io.InputStream();
+  Signature: ()V
+public int available()   throws java.io.IOException;
+  Signature: ()I
+public void close()   throws java.io.IOException;
+  Signature: ()V
+public void mark(int);
+  Signature: (I)V
+public boolean markSupported();
+  Signature: ()Z
+public abstract int read()   throws java.io.IOException;
+  Signature: ()I
+public int read(byte[])   throws java.io.IOException;
+  Signature: ([B)I
+public int read(byte[], int, int)   throws java.io.IOException;
+  Signature: ([BII)I
+public synchronized void reset()   throws java.io.IOException;
+  Signature: ()V
+public long skip(long)   throws java.io.IOException;
+  Signature: (J)J
+}
+"""
+    jni_from_javap = jni_generator.JNIFromJavaP(contents.split('\n'),
+                                                TestOptions())
     self.assertEquals(10, len(jni_from_javap.called_by_natives))
     golden_content = """\
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
@@ -1590,7 +1717,7 @@
 // found in the LICENSE file.
 
 // This file is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     java/io/InputStream
 
@@ -1628,10 +1755,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "available",
-
-"("
-")"
-"I",
+"()I",
       &g_InputStream_available);
 
   jint ret =
@@ -1652,10 +1776,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "close",
-
-"("
-")"
-"V",
+"()V",
       &g_InputStream_close);
 
   env->CallVoidMethod(obj,
@@ -1675,11 +1796,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "mark",
-
-"("
-"I"
-")"
-"V",
+"(I)V",
       &g_InputStream_mark);
 
   env->CallVoidMethod(obj,
@@ -1699,10 +1816,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "markSupported",
-
-"("
-")"
-"Z",
+"()Z",
       &g_InputStream_markSupported);
 
   jboolean ret =
@@ -1723,10 +1837,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "read",
-
-"("
-")"
-"I",
+"()I",
       &g_InputStream_readI);
 
   jint ret =
@@ -1747,11 +1858,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "read",
-
-"("
-"[B"
-")"
-"I",
+"([B)I",
       &g_InputStream_readI_AB);
 
   jint ret =
@@ -1777,13 +1884,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "read",
-
-"("
-"[B"
-"I"
-"I"
-")"
-"I",
+"([BII)I",
       &g_InputStream_readI_AB_I_I);
 
   jint ret =
@@ -1804,10 +1905,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "reset",
-
-"("
-")"
-"V",
+"()V",
       &g_InputStream_reset);
 
   env->CallVoidMethod(obj,
@@ -1827,11 +1925,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "skip",
-
-"("
-"J"
-")"
-"J",
+"(J)J",
       &g_InputStream_skip);
 
   jlong ret =
@@ -1852,10 +1946,7 @@
       base::android::MethodID::TYPE_INSTANCE>(
       env, g_InputStream_clazz,
       "<init>",
-
-"("
-")"
-"V",
+"()V",
       &g_InputStream_Constructor);
 
   jobject ret =
@@ -1896,7 +1987,8 @@
     private native void nativeSyncSetupEnded(
         int nativeAndroidSyncSetupFlowHandler);
     """
-    jni_from_java = jni_generator.JNIFromJavaSource(test_data, 'foo/bar')
+    jni_from_java = jni_generator.JNIFromJavaSource(
+        test_data, 'foo/bar', TestOptions())
 
   def testRaisesOnNonJNIMethod(self):
     test_data = """
@@ -1907,7 +1999,7 @@
     """
     self.assertRaises(SyntaxError,
                       jni_generator.JNIFromJavaSource,
-                      test_data, 'foo/bar')
+                      test_data, 'foo/bar', TestOptions())
 
   def testJniSelfDocumentingExample(self):
     script_dir = os.path.dirname(sys.argv[0])
@@ -1917,7 +2009,8 @@
     golden_content = file(os.path.join(script_dir,
                                        'golden_sample_for_tests_jni.h')).read()
     jni_from_java = jni_generator.JNIFromJavaSource(
-        content, 'org/chromium/example/jni_generator/SampleForTests')
+        content, 'org/chromium/example/jni_generator/SampleForTests',
+        TestOptions())
     self.assertTextEquals(golden_content, jni_from_java.GetContent())
 
   def testNoWrappingPreprocessorLines(self):
@@ -1930,7 +2023,8 @@
     """
     jni_from_java = jni_generator.JNIFromJavaSource(
         test_data, ('com/google/lookhowextremelylongiam/snarf/'
-                    'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'))
+                    'icankeepthisupallday/ReallyLongClassNamesAreAllTheRage'),
+        TestOptions())
     jni_lines = jni_from_java.GetContent().split('\n')
     line = filter(lambda line: line.lstrip().startswith('#ifndef'),
                   jni_lines)[0]
@@ -1951,7 +2045,7 @@
         """rule org.chromium.example.** com.test.@1
         rule org.chromium.example2.** org.test2.@0""")
     jni_from_java = jni_generator.JNIFromJavaSource(
-        test_data, 'org/chromium/example/jni_generator/Example')
+        test_data, 'org/chromium/example/jni_generator/Example', TestOptions())
     jni_generator.JniParams.SetJarJarMappings('')
     golden_content = """\
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
@@ -1959,7 +2053,7 @@
 // found in the LICENSE file.
 
 // This file is autogenerated by
-//     base/android/jni_generator/jni_generator_tests.py
+//     base/android/jni_generator/jni_generator.py
 // For
 //     org/chromium/example/jni_generator/Example
 
@@ -2079,6 +2173,93 @@
     self.assertTextEquals(
         '[Ljava/nio/ByteBuffer;', JniParams.JavaToJni('java/nio/ByteBuffer[]'))
 
+  def testNativesLong(self):
+    test_options = TestOptions()
+    test_options.ptr_type = 'long'
+    test_data = """"
+    private native void nativeDestroy(long nativeChromeBrowserProvider);
+    """
+    jni_generator.JniParams.ExtractImportsAndInnerClasses(test_data)
+    natives = jni_generator.ExtractNatives(test_data, test_options.ptr_type)
+    golden_natives = [
+        NativeMethod(return_type='void', static=False, name='Destroy',
+                     params=[Param(datatype='long',
+                                   name='nativeChromeBrowserProvider')],
+                     java_class_name=None,
+                     type='method',
+                     p0_type='ChromeBrowserProvider',
+                     ptr_type=test_options.ptr_type),
+    ]
+    self.assertListEquals(golden_natives, natives)
+    h = jni_generator.InlHeaderFileGenerator('', 'org/chromium/TestJni',
+                                             natives, [], test_options)
+    golden_content = """\
+// 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 is autogenerated by
+//     base/android/jni_generator/jni_generator.py
+// For
+//     org/chromium/TestJni
+
+#ifndef org_chromium_TestJni_JNI
+#define org_chromium_TestJni_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+using base::android::ScopedJavaLocalRef;
+
+// Step 1: forward declarations.
+namespace {
+const char kTestJniClassPath[] = "org/chromium/TestJni";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+jclass g_TestJni_clazz = NULL;
+}  // namespace
+
+// Step 2: method stubs.
+static void Destroy(JNIEnv* env, jobject obj,
+    jlong nativeChromeBrowserProvider) {
+  DCHECK(nativeChromeBrowserProvider) << "Destroy";
+  ChromeBrowserProvider* native =
+      reinterpret_cast<ChromeBrowserProvider*>(nativeChromeBrowserProvider);
+  return native->Destroy(env, obj);
+}
+
+// Step 3: RegisterNatives.
+
+static bool RegisterNativesImpl(JNIEnv* env) {
+
+  g_TestJni_clazz = reinterpret_cast<jclass>(env->NewGlobalRef(
+      base::android::GetClass(env, kTestJniClassPath).obj()));
+  static const JNINativeMethod kMethodsTestJni[] = {
+    { "nativeDestroy",
+"("
+"J"
+")"
+"V", reinterpret_cast<void*>(Destroy) },
+  };
+  const int kMethodsTestJniSize = arraysize(kMethodsTestJni);
+
+  if (env->RegisterNatives(g_TestJni_clazz,
+                           kMethodsTestJni,
+                           kMethodsTestJniSize) < 0) {
+    LOG(ERROR) << "RegisterNatives failed in " << __FILE__;
+    return false;
+  }
+
+  return true;
+}
+
+#endif  // org_chromium_TestJni_JNI
+"""
+    self.assertTextEquals(golden_content, h.GetContent())
+
 
 if __name__ == '__main__':
   unittest.main()