jni_generator: Use shortened name for GEN_JNI when !is_java_debug

To save space in release, instead of using org.chromium.base.natives.GEN_JNI
use a short package/class name, J.N. Proguard won't do this for us because
we can't obfuscate any class that contains native methods.

Bug: 898261
Change-Id: I84ad6914912b5b0e0d390d53a88dbcf41633edbf
Reviewed-on: https://chromium-review.googlesource.com/c/1347034
Reviewed-by: agrieve <agrieve@chromium.org>
Reviewed-by: Eric Stevenson <estevenson@chromium.org>
Commit-Queue: agrieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610288}
diff --git a/base/android/jni_generator/golden/HashedSampleForAnnotationProcessor_jni.golden b/base/android/jni_generator/golden/HashedSampleForAnnotationProcessor_jni.golden
index b83aaf1..545c0508 100644
--- a/base/android/jni_generator/golden/HashedSampleForAnnotationProcessor_jni.golden
+++ b/base/android/jni_generator/golden/HashedSampleForAnnotationProcessor_jni.golden
@@ -26,7 +26,7 @@
 static void JNI_SampleForAnnotationProcessor_Foo(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT void Java_org_chromium_base_natives_GEN_1JNI_MygCV2jQ(
+JNI_GENERATOR_EXPORT void Java_J_N_MygCV2jQ(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_Foo(env, base::android::JavaParamRef<jclass>(env,
@@ -37,7 +37,7 @@
     const base::android::JavaParamRef<jclass>& jcaller,
     const base::android::JavaParamRef<jobject>& sample);
 
-JNI_GENERATOR_EXPORT jobject Java_org_chromium_base_natives_GEN_1JNI_MHuqnmXT(
+JNI_GENERATOR_EXPORT jobject Java_J_N_MHuqnmXT(
     JNIEnv* env,
     jclass jcaller,
     jobject sample) {
@@ -49,7 +49,7 @@
     env, const base::android::JavaParamRef<jclass>& jcaller,
     const base::android::JavaParamRef<jstring>& stringToReverse);
 
-JNI_GENERATOR_EXPORT jstring Java_org_chromium_base_natives_GEN_1JNI_MM5Xkwyy(
+JNI_GENERATOR_EXPORT jstring Java_J_N_MM5Xkwyy(
     JNIEnv* env,
     jclass jcaller,
     jstring stringToReverse) {
@@ -62,7 +62,7 @@
     base::android::JavaParamRef<jclass>& jcaller,
     const base::android::JavaParamRef<jobjectArray>& strs);
 
-JNI_GENERATOR_EXPORT jobjectArray Java_org_chromium_base_natives_GEN_1JNI_MAC2QhR9(
+JNI_GENERATOR_EXPORT jobjectArray Java_J_N_MAC2QhR9(
     JNIEnv* env,
     jclass jcaller,
     jobjectArray strs) {
@@ -75,7 +75,7 @@
     base::android::JavaParamRef<jclass>& jcaller,
     const base::android::JavaParamRef<jobjectArray>& strs);
 
-JNI_GENERATOR_EXPORT jobjectArray Java_org_chromium_base_natives_GEN_1JNI_MGhRh4Nd(
+JNI_GENERATOR_EXPORT jobjectArray Java_J_N_MGhRh4Nd(
     JNIEnv* env,
     jclass jcaller,
     jobjectArray strs) {
@@ -87,7 +87,7 @@
 static jboolean JNI_SampleForAnnotationProcessor_HasPhalange(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jboolean Java_org_chromium_base_natives_GEN_1JNI_MW0aEs4h(
+JNI_GENERATOR_EXPORT jboolean Java_J_N_MW0aEs4h(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_HasPhalange(env, base::android::JavaParamRef<jclass>(env,
@@ -114,7 +114,7 @@
     jboolean zbool,
     const base::android::JavaParamRef<jbooleanArray>& bools);
 
-JNI_GENERATOR_EXPORT jintArray Java_org_chromium_base_natives_GEN_1JNI_MlVFI4RX(
+JNI_GENERATOR_EXPORT jintArray Java_J_N_MlVFI4RX(
     JNIEnv* env,
     jclass jcaller,
     jint zint,
@@ -158,7 +158,7 @@
     const base::android::JavaParamRef<jobject>& obj,
     const base::android::JavaParamRef<jobjectArray>& objects);
 
-JNI_GENERATOR_EXPORT void Java_org_chromium_base_natives_GEN_1JNI_MqOnlud7(
+JNI_GENERATOR_EXPORT void Java_J_N_MqOnlud7(
     JNIEnv* env,
     jclass jcaller,
     jclass clazz,
@@ -188,7 +188,7 @@
     JNI_SampleForAnnotationProcessor_ReturnThrowable(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jthrowable Java_org_chromium_base_natives_GEN_1JNI_MuZc76Vt(
+JNI_GENERATOR_EXPORT jthrowable Java_J_N_MuZc76Vt(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnThrowable(env,
@@ -199,7 +199,7 @@
     JNI_SampleForAnnotationProcessor_ReturnThrowables(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jobjectArray Java_org_chromium_base_natives_GEN_1JNI_MAD53J7V(
+JNI_GENERATOR_EXPORT jobjectArray Java_J_N_MAD53J7V(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnThrowables(env,
@@ -210,7 +210,7 @@
     JNI_SampleForAnnotationProcessor_ReturnClass(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jclass Java_org_chromium_base_natives_GEN_1JNI_M_00024ZgOi4g(
+JNI_GENERATOR_EXPORT jclass Java_J_N_M_00024ZgOi4g(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnClass(env, base::android::JavaParamRef<jclass>(env,
@@ -221,7 +221,7 @@
     JNI_SampleForAnnotationProcessor_ReturnClasses(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jobjectArray Java_org_chromium_base_natives_GEN_1JNI_M_00024hL1577(
+JNI_GENERATOR_EXPORT jobjectArray Java_J_N_M_00024hL1577(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnClasses(env,
@@ -232,7 +232,7 @@
     JNI_SampleForAnnotationProcessor_ReturnString(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jstring Java_org_chromium_base_natives_GEN_1JNI_M0k1OjBK(
+JNI_GENERATOR_EXPORT jstring Java_J_N_M0k1OjBK(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnString(env, base::android::JavaParamRef<jclass>(env,
@@ -243,7 +243,7 @@
     JNI_SampleForAnnotationProcessor_ReturnStrings(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jobjectArray Java_org_chromium_base_natives_GEN_1JNI_Mssfs54E(
+JNI_GENERATOR_EXPORT jobjectArray Java_J_N_Mssfs54E(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnStrings(env,
@@ -254,7 +254,7 @@
     JNI_SampleForAnnotationProcessor_ReturnStruct(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jobject Java_org_chromium_base_natives_GEN_1JNI_MSzcel_1H(
+JNI_GENERATOR_EXPORT jobject Java_J_N_MSzcel_1H(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnStruct(env, base::android::JavaParamRef<jclass>(env,
@@ -265,7 +265,7 @@
     JNI_SampleForAnnotationProcessor_ReturnStructs(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jobjectArray Java_org_chromium_base_natives_GEN_1JNI_MIBrQLK4(
+JNI_GENERATOR_EXPORT jobjectArray Java_J_N_MIBrQLK4(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnStructs(env,
@@ -276,7 +276,7 @@
     JNI_SampleForAnnotationProcessor_ReturnObject(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jobject Java_org_chromium_base_natives_GEN_1JNI_M_00024hPywjv(
+JNI_GENERATOR_EXPORT jobject Java_J_N_M_00024hPywjv(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnObject(env, base::android::JavaParamRef<jclass>(env,
@@ -287,7 +287,7 @@
     JNI_SampleForAnnotationProcessor_ReturnObjects(JNIEnv* env, const
     base::android::JavaParamRef<jclass>& jcaller);
 
-JNI_GENERATOR_EXPORT jobjectArray Java_org_chromium_base_natives_GEN_1JNI_MPpCU1l5(
+JNI_GENERATOR_EXPORT jobjectArray Java_J_N_MPpCU1l5(
     JNIEnv* env,
     jclass jcaller) {
   return JNI_SampleForAnnotationProcessor_ReturnObjects(env,
diff --git a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
index 7378768c..587746e 100644
--- a/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
+++ b/base/android/jni_generator/java/src/org/chromium/jni_generator/JniProcessor.java
@@ -61,13 +61,12 @@
 public class JniProcessor extends AbstractProcessor {
     private static final Class<JniStaticNatives> JNI_STATIC_NATIVES_CLASS = JniStaticNatives.class;
 
-    static final String NATIVE_WRAPPER_CLASS_POSTFIX = "Jni";
+    private static final String NATIVE_WRAPPER_CLASS_POSTFIX = "Jni";
 
-    static final String NATIVE_CLASS_NAME_STR = "GEN_JNI";
-    static final String NATIVE_CLASS_PACKAGE_NAME = "org.chromium.base.natives";
-
-    static final ClassName NATIVE_CLASS_NAME =
-            ClassName.get(NATIVE_CLASS_PACKAGE_NAME, NATIVE_CLASS_NAME_STR);
+    // The native class name and package name used in debug.
+    private String mNativeClassStr = "GEN_JNI";
+    private String mNativeClassPackage = "org.chromium.base.natives";
+    private ClassName mNativeClassName;
 
     static final String NATIVE_TEST_FIELD_NAME = "TESTING_ENABLED";
     static final String NATIVE_REQUIRE_MOCK_FIELD_NAME = "REQUIRE_MOCK";
@@ -86,6 +85,7 @@
 
     // If true, native methods in GEN_JNI will be named as a hash of their descriptor.
     private static final boolean USE_HASH_FOR_METHODS = !ProcessorArgs.IS_JAVA_DEBUG;
+    private static final boolean USE_SHORTENED_NATIVE_CLASS = !ProcessorArgs.IS_JAVA_DEBUG;
 
     // Limits the number characters of the Base64 encoded hash
     // of the method descriptor used as name of the generated
@@ -112,6 +112,14 @@
     }
 
     public JniProcessor() {
+        // If non-debug we use shorter names to save space.
+        if (USE_SHORTENED_NATIVE_CLASS) {
+            // J.N
+            mNativeClassPackage = "J";
+            mNativeClassStr = "N";
+        }
+        mNativeClassName = ClassName.get(mNativeClassPackage, mNativeClassStr);
+
         FieldSpec.Builder testingFlagBuilder =
                 FieldSpec.builder(TypeName.BOOLEAN, NATIVE_TEST_FIELD_NAME)
                         .addModifiers(Modifier.STATIC, Modifier.PUBLIC);
@@ -128,7 +136,7 @@
         }
 
         // State of mNativesBuilder needs to be preserved between processing rounds.
-        mNativesBuilder = TypeSpec.classBuilder(NATIVE_CLASS_NAME)
+        mNativesBuilder = TypeSpec.classBuilder(mNativeClassName)
                                   .addAnnotation(createGeneratedAnnotation())
                                   .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                                   .addField(testingFlagBuilder.build())
@@ -215,7 +223,7 @@
             // Need to write NativeClass first because the wrapper classes
             // depend on it.
             JavaFile nativeClassFile =
-                    JavaFile.builder(NATIVE_CLASS_PACKAGE_NAME, mNativesBuilder.build()).build();
+                    JavaFile.builder(mNativeClassPackage, mNativesBuilder.build()).build();
 
             nativeClassFile.writeTo(processingEnv.getFiler());
 
@@ -394,12 +402,12 @@
                 MethodSpec.methodBuilder("get")
                         .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                         .returns(nativeInterfaceType)
-                        .beginControlFlow("if ($T.$N)", NATIVE_CLASS_NAME, NATIVE_TEST_FIELD_NAME)
+                        .beginControlFlow("if ($T.$N)", mNativeClassName, NATIVE_TEST_FIELD_NAME)
                         .beginControlFlow("if ($N != null)", testTarget)
                         .addStatement("return $N", testTarget)
                         .endControlFlow()
                         .beginControlFlow(
-                                "if ($T.$N)", NATIVE_CLASS_NAME, NATIVE_REQUIRE_MOCK_FIELD_NAME)
+                                "if ($T.$N)", mNativeClassName, NATIVE_REQUIRE_MOCK_FIELD_NAME)
                         .addStatement("throw new UnsupportedOperationException($S)",
                                 noMockExceptionString)
                         .endControlFlow()
@@ -466,7 +474,7 @@
         }
 
         // Make call to native function.
-        builder.addCode("$T.$N(", NATIVE_CLASS_NAME, staticNativeMethod);
+        builder.addCode("$T.$N(", mNativeClassName, staticNativeMethod);
 
         // Add params to native call.
         ArrayList<String> paramNames = new ArrayList<>();
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 46da542..ae22725 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -46,18 +46,6 @@
     r'^\s*(?:@(?:\w+\.)*\w+\s+)*@MainDex\b',
     re.MULTILINE)
 
-# 'Proxy' native methods are declared in an @JniStaticNatives interface without
-# a native qualifier and indicate that the JNI annotation processor should
-# generate code to link between the equivalent native method as if it were
-# declared statically.
-# Under the hood the annotation processor generates the actual native method
-# declaration in another another class (org.chromium.base.natives.GEN_JNI)
-# but generates wrapper code so it can be called through the declaring class.
-NATIVE_PROXY_CLASS_NAME = 'GEN_JNI'
-NATIVE_PROXY_PACKAGE_NAME = 'org/chromium/base/natives'
-NATIVE_PROXY_QUALIFIED_NAME = '%s/%s' % (NATIVE_PROXY_PACKAGE_NAME,
-                                         NATIVE_PROXY_CLASS_NAME)
-
 # Matches on method declarations unlike _EXTRACT_NATIVES_REGEX
 # doesn't require name to be prefixed with native, and does not
 # require a native qualifier.
@@ -828,9 +816,35 @@
     return jni_from_javap
 
 
-class NativeProxyHelpers(object):
+# 'Proxy' native methods are declared in an @JniStaticNatives interface without
+# a native qualifier and indicate that the JNI annotation processor should
+# generate code to link between the equivalent native method as if it were
+# declared statically.
+# Under the hood the annotation processor generates the actual native method
+# declaration in another class (org.chromium.base.natives.GEN_JNI)
+# but generates wrapper code so it can be called through the declaring class.
+class ProxyHelpers(object):
+  NATIVE_PROXY_CLASS_NAME = 'GEN_JNI'
+  NATIVE_PROXY_PACKAGE_NAME = 'org/chromium/base/natives'
+
   MAX_CHARS_FOR_HASHED_NATIVE_METHODS = 8
-  ESCAPED_NATIVE_PROXY_CLASS = EscapeClassName(NATIVE_PROXY_QUALIFIED_NAME)
+
+  @staticmethod
+  def GetClass(use_hash):
+    if use_hash:
+      return 'N'
+    return ProxyHelpers.NATIVE_PROXY_CLASS_NAME
+
+  @staticmethod
+  def GetPackage(use_hash):
+    if use_hash:
+      return 'J'
+    return ProxyHelpers.NATIVE_PROXY_PACKAGE_NAME
+
+  @staticmethod
+  def GetQualifiedClass(use_hash):
+    return '%s/%s' % (ProxyHelpers.GetPackage(use_hash),
+                      ProxyHelpers.GetClass(use_hash))
 
   @staticmethod
   def CreateHashedMethodName(fully_qualified_class_name, method_name):
@@ -840,14 +854,14 @@
     m.update(descriptor)
     hash = m.digest()
     hashed_name = ('M' + base64.b64encode(hash, altchars='$_')).rstrip('=')
-    return hashed_name[0:NativeProxyHelpers.MAX_CHARS_FOR_HASHED_NATIVE_METHODS]
+    return hashed_name[0:ProxyHelpers.MAX_CHARS_FOR_HASHED_NATIVE_METHODS]
 
   @staticmethod
   def CreateProxyMethodName(fully_qualified_class, old_name, use_hash=False):
     """Returns the literal method name for the corresponding proxy method"""
     if use_hash:
-      hashed_name = NativeProxyHelpers.CreateHashedMethodName(
-          fully_qualified_class, old_name)
+      hashed_name = ProxyHelpers.CreateHashedMethodName(fully_qualified_class,
+                                                        old_name)
       return hashed_name
 
     # The annotation processor currently uses a method name
@@ -871,7 +885,7 @@
         params = JniParams.Parse(method.group('params'), use_proxy_types=True)
         return_type = JavaTypeToProxyCast(method.group('return_type'))
 
-        unescaped_proxy_name = NativeProxyHelpers.CreateProxyMethodName(
+        unescaped_proxy_name = ProxyHelpers.CreateProxyMethodName(
             fully_qualified_class, name, use_hash)
         native = NativeMethod(
             static=True,
@@ -898,7 +912,7 @@
     natives = ExtractNatives(contents, options.ptr_type)
     called_by_natives = ExtractCalledByNatives(self.jni_params, contents)
 
-    natives += NativeProxyHelpers.ExtractStaticProxyNatives(
+    natives += ProxyHelpers.ExtractStaticProxyNatives(
         fully_qualified_class, contents, options.ptr_type,
         options.use_proxy_hash)
 
@@ -924,9 +938,10 @@
 class HeaderFileGeneratorHelper(object):
   """Include helper methods for header generators."""
 
-  def __init__(self, class_name, fully_qualified_class):
+  def __init__(self, class_name, fully_qualified_class, use_proxy_hash):
     self.class_name = class_name
     self.fully_qualified_class = fully_qualified_class
+    self.use_proxy_hash = use_proxy_hash
 
   def GetStubName(self, native):
     """Return the name of the stub function for this native method.
@@ -939,8 +954,8 @@
     """
     if native.is_proxy:
       method_name = EscapeClassName(native.proxy_name)
-      return 'Java_%s_%s' % (EscapeClassName(NATIVE_PROXY_QUALIFIED_NAME),
-                             method_name)
+      return 'Java_%s_%s' % (EscapeClassName(
+          ProxyHelpers.GetQualifiedClass(self.use_proxy_hash)), method_name)
 
     template = Template('Java_${JAVA_NAME}_native${NAME}')
 
@@ -955,7 +970,8 @@
     ret = {}
     for entry in origin:
       if isinstance(entry, NativeMethod) and entry.is_proxy:
-        ret[NATIVE_PROXY_CLASS_NAME] = NATIVE_PROXY_QUALIFIED_NAME
+        ret[ProxyHelpers.GetClass(self.use_proxy_hash)] \
+          = ProxyHelpers.GetQualifiedClass(self.use_proxy_hash)
         continue
       ret[self.class_name] = self.fully_qualified_class
 
@@ -988,7 +1004,7 @@
       }
       # Since all proxy methods use the same class, defining this in every
       # header file would result in duplicated extern initializations.
-      if full_clazz != NATIVE_PROXY_QUALIFIED_NAME:
+      if full_clazz != ProxyHelpers.GetQualifiedClass(self.use_proxy_hash):
         ret += [template.substitute(values)]
 
     class_getter = """\
@@ -1016,7 +1032,7 @@
       }
       # Since all proxy methods use the same class, defining this in every
       # header file would result in duplicated extern initializations.
-      if full_clazz != NATIVE_PROXY_QUALIFIED_NAME:
+      if full_clazz != ProxyHelpers.GetQualifiedClass(self.use_proxy_hash):
         ret += [template.substitute(values)]
 
     return ''.join(ret)
@@ -1037,7 +1053,7 @@
     self.jni_params = jni_params
     self.options = options
     self.helper = HeaderFileGeneratorHelper(
-        self.class_name, fully_qualified_class)
+        self.class_name, fully_qualified_class, self.options.use_proxy_hash)
 
 
   def GetContent(self):
@@ -1525,7 +1541,8 @@
       '--use_proxy_hash',
       action='store_true',
       help='Hashes the native declaration of methods used '
-      'in an @JniNatives interface')
+      'in @JniNatives interface. And uses a shorter name and package'
+      ' than GEN_JNI.')
   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 f4e8aae93..e6763c3 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -344,11 +344,16 @@
                                               TestOptions())
     self.AssertGoldenTextEquals(h1.GetContent())
     h2 = jni_registration_generator.HeaderGenerator(
-        '', 'org/chromium/TestJni', natives, jni_params, True)
+        '',
+        'org/chromium/TestJni',
+        natives,
+        jni_params,
+        True,
+        use_proxy_hash=False)
     content = TestGenerator._MergeRegistrationForTests([h2.Generate()])
 
     self.AssertGoldenTextEquals(
-        jni_registration_generator.CreateFromDict(content),
+        jni_registration_generator.CreateFromDict(content, use_hash=False),
         suffix='Registrations')
 
   def testInnerClassNatives(self):
@@ -430,11 +435,16 @@
     self.AssertGoldenTextEquals(h.GetContent())
 
     h2 = jni_registration_generator.HeaderGenerator(
-        '', 'org/chromium/TestJni', natives, jni_params, True)
+        '',
+        'org/chromium/TestJni',
+        natives,
+        jni_params,
+        True,
+        use_proxy_hash=False)
     content = TestGenerator._MergeRegistrationForTests([h2.Generate()])
 
     self.AssertGoldenTextEquals(
-        jni_registration_generator.CreateFromDict(content),
+        jni_registration_generator.CreateFromDict(content, use_hash=False),
         suffix='Registrations')
 
   def testCalledByNatives(self):
@@ -1244,7 +1254,7 @@
     """
     qualified_clazz = 'org/chromium/example/SampleProxyJni'
 
-    natives = jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
+    natives = jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
         qualified_clazz, test_data, 'long')
 
     golden_natives = [
@@ -1296,7 +1306,7 @@
     qualified_clazz = 'test/foo/Foo'
     jni_params = TestOptions()
 
-    natives = jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
+    natives = jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
         qualified_clazz, test_data, 'long')
 
     golden_natives = [
@@ -1315,26 +1325,36 @@
 
     jni_params = jni_generator.JniParams(qualified_clazz)
     main_dex_header = jni_registration_generator.HeaderGenerator(
-        '', qualified_clazz, natives, jni_params, main_dex=True).Generate()
+        '',
+        qualified_clazz,
+        natives,
+        jni_params,
+        main_dex=True,
+        use_proxy_hash=False).Generate()
     content = TestGenerator._MergeRegistrationForTests([main_dex_header])
 
     self.AssertGoldenTextEquals(
-        jni_registration_generator.CreateFromDict(content))
+        jni_registration_generator.CreateFromDict(content, use_hash=False))
 
     other_qualified_clazz = 'test/foo/Bar'
-    other_natives = jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
+    other_natives = jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
         other_qualified_clazz, non_main_dex_test_data, 'long')
 
     jni_params = jni_generator.JniParams(other_qualified_clazz)
     non_main_dex_header = jni_registration_generator.HeaderGenerator(
-        '', other_qualified_clazz, other_natives, jni_params,
-        main_dex=False).Generate()
+        '',
+        other_qualified_clazz,
+        other_natives,
+        jni_params,
+        main_dex=False,
+        use_proxy_hash=False).Generate()
 
     content = TestGenerator._MergeRegistrationForTests([main_dex_header] +
                                                        [non_main_dex_header])
 
     self.AssertGoldenTextEquals(
-        jni_registration_generator.CreateFromDict(content), 'AndNonMainDex')
+        jni_registration_generator.CreateFromDict(content, use_hash=False),
+        'AndNonMainDex')
 
   def testProxyNatives(self):
     test_data = """
@@ -1369,9 +1389,9 @@
 
     qualified_clazz = 'org/chromium/example/SampleProxyJni'
 
-    natives = jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
+    natives = jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
         qualified_clazz, test_data, 'long')
-    bad_spacing_natives = jni_generator.NativeProxyHelpers \
+    bad_spacing_natives = jni_generator.ProxyHelpers \
       .ExtractStaticProxyNatives(qualified_clazz, bad_spaced_test_data, 'long')
     golden_natives = [
         NativeMethod(
@@ -1415,8 +1435,8 @@
     h1 = jni_generator.InlHeaderFileGenerator('', qualified_clazz, natives, [],
                                               [], jni_params, TestOptions())
     self.AssertGoldenTextEquals(h1.GetContent())
-    h2 = jni_registration_generator.HeaderGenerator('', qualified_clazz,
-                                                    natives, jni_params, False)
+    h2 = jni_registration_generator.HeaderGenerator(
+        '', qualified_clazz, natives, jni_params, False, use_proxy_hash=False)
     content = TestGenerator._MergeRegistrationForTests([h2.Generate()])
 
     proxy_opts = jni_registration_generator.ProxyOptions()
@@ -1425,7 +1445,7 @@
         suffix='Java')
 
     self.AssertGoldenTextEquals(
-        jni_registration_generator.CreateFromDict(content),
+        jni_registration_generator.CreateFromDict(content, proxy_opts.use_hash),
         suffix='Registrations')
 
   def testProxyHashedExample(self):
@@ -1446,7 +1466,8 @@
 
     proxy_opts = jni_registration_generator.ProxyOptions()
     self.AssertGoldenTextEquals(
-        jni_registration_generator.CreateProxyJavaFromDict(reg_dict, proxy_opts),
+        jni_registration_generator.CreateProxyJavaFromDict(
+            reg_dict, proxy_opts),
         golden_file='HashedSampleForAnnotationProcessorGenJni.golden')
 
   def testProxyJniExample(self):
diff --git a/base/android/jni_generator/jni_registration_generator.py b/base/android/jni_generator/jni_registration_generator.py
index b9c450c..61035c7 100755
--- a/base/android/jni_generator/jni_registration_generator.py
+++ b/base/android/jni_generator/jni_registration_generator.py
@@ -3,7 +3,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-"""Generates GEN_JNI.java and helper for manual JNI registration.
+"""Generates GEN_JNI.java (or N.java) and helper for manual JNI registration.
 
 Creates a header file with two static functions: RegisterMainDexNatives() and
 RegisterNonMainDexNatives(). Together, these will use manual JNI registration
@@ -77,7 +77,7 @@
     combined_dict['HEADER_GUARD'] = \
         os.path.splitext(header_path)[0].replace('/', '_').upper() + '_'
     combined_dict['NAMESPACE'] = namespace
-    header_content = CreateFromDict(combined_dict)
+    header_content = CreateFromDict(combined_dict, proxy_opts.use_hash)
     with build_utils.AtomicOutput(header_path) as f:
       f.write(header_content)
 
@@ -85,7 +85,8 @@
     with zipfile.ZipFile(f, 'w') as srcjar:
       build_utils.AddToZipHermetic(
           srcjar,
-          'org/chromium/base/natives/GEN_JNI.java',
+          '%s.java' % jni_generator.ProxyHelpers.GetQualifiedClass(
+              proxy_opts.use_hash),
           data=CreateProxyJavaFromDict(combined_dict, proxy_opts))
 
 
@@ -99,7 +100,7 @@
       path, contents)
   natives = jni_generator.ExtractNatives(contents, 'long')
 
-  natives += jni_generator.NativeProxyHelpers.ExtractStaticProxyNatives(
+  natives += jni_generator.ProxyHelpers.ExtractStaticProxyNatives(
       fully_qualified_class=fully_qualified_class,
       contents=contents,
       ptr_type='long',
@@ -111,10 +112,11 @@
   jni_params.ExtractImportsAndInnerClasses(contents)
   is_main_dex = jni_generator.IsMainDexJavaClass(contents)
   header_generator = HeaderGenerator(namespace, fully_qualified_class, natives,
-                                     jni_params, is_main_dex)
+                                     jni_params, is_main_dex, use_proxy_hash)
   return header_generator.Generate()
 
-def _SetProxyRegistrationFields(registration_dict):
+
+def _SetProxyRegistrationFields(registration_dict, use_hash):
   registration_template = string.Template("""\
 
 static const JNINativeMethod kMethods_${ESCAPED_PROXY_CLASS}[] = {
@@ -148,14 +150,15 @@
 
   sub_dict = {
       'ESCAPED_PROXY_CLASS':
-          jni_generator.NativeProxyHelpers.ESCAPED_NATIVE_PROXY_CLASS,
+          jni_generator.EscapeClassName(
+              jni_generator.ProxyHelpers.GetQualifiedClass(use_hash)),
       'PROXY_CLASS':
-          jni_generator.NATIVE_PROXY_QUALIFIED_NAME,
+          jni_generator.ProxyHelpers.GetQualifiedClass(use_hash),
       'KMETHODS':
           registration_dict['PROXY_NATIVE_METHOD_ARRAY'],
       'REGISTRATION_NAME':
           jni_generator.GetRegistrationFunctionName(
-              jni_generator.NATIVE_PROXY_QUALIFIED_NAME)
+              jni_generator.ProxyHelpers.GetQualifiedClass(use_hash)),
   }
 
   if registration_dict['PROXY_NATIVE_METHOD_ARRAY']:
@@ -201,15 +204,21 @@
 """)
 
   return template.substitute({
-      'TESTING_ENABLED': str(proxy_opts.enable_mocks).lower(),
-      'REQUIRE_MOCK': str(proxy_opts.require_mocks).lower(),
-      'CLASS_NAME': jni_generator.NATIVE_PROXY_CLASS_NAME,
-      'PACKAGE': jni_generator.NATIVE_PROXY_PACKAGE_NAME.replace('/', '.'),
-      'SIGNATURES': registration_dict['PROXY_NATIVE_SIGNATURES']
+      'TESTING_ENABLED':
+          str(proxy_opts.enable_mocks).lower(),
+      'REQUIRE_MOCK':
+          str(proxy_opts.require_mocks).lower(),
+      'CLASS_NAME':
+          jni_generator.ProxyHelpers.GetClass(proxy_opts.use_hash),
+      'PACKAGE':
+          jni_generator.ProxyHelpers.GetPackage(proxy_opts.use_hash).replace(
+              '/', '.'),
+      'SIGNATURES':
+          registration_dict['PROXY_NATIVE_SIGNATURES']
   })
 
 
-def CreateFromDict(registration_dict):
+def CreateFromDict(registration_dict, use_hash):
   """Returns the content of the header file."""
 
   template = string.Template("""\
@@ -264,7 +273,7 @@
 
 #endif  // ${HEADER_GUARD}
 """)
-  _SetProxyRegistrationFields(registration_dict)
+  _SetProxyRegistrationFields(registration_dict, use_hash)
 
   if len(registration_dict['FORWARD_DECLARATIONS']) == 0:
     return ''
@@ -276,7 +285,7 @@
   """Generates an inline header file for JNI registration."""
 
   def __init__(self, namespace, fully_qualified_class, natives, jni_params,
-               main_dex):
+               main_dex, use_proxy_hash):
     self.namespace = namespace
     self.natives = natives
     self.proxy_natives = [n for n in natives if n.is_proxy]
@@ -286,7 +295,8 @@
     self.class_name = self.fully_qualified_class.split('/')[-1]
     self.main_dex = main_dex
     self.helper = jni_generator.HeaderFileGeneratorHelper(
-        self.class_name, fully_qualified_class)
+        self.class_name, fully_qualified_class, use_proxy_hash)
+    self.use_proxy_hash = use_proxy_hash
     self.registration_dict = None
 
   def Generate(self):
@@ -422,7 +432,7 @@
 
     for clazz, full_clazz in all_classes.iteritems():
       if not sub_proxy:
-        if clazz == jni_generator.NATIVE_PROXY_CLASS_NAME:
+        if clazz == jni_generator.ProxyHelpers.GetClass(self.use_proxy_hash):
           continue
 
       kmethods = self._GetKMethodsString(clazz)
@@ -529,7 +539,8 @@
   arg_parser.add_argument(
       '--srcjar-path',
       required=True,
-      help='Path to output srcjar for GEN_JNI.java.')
+      help='Path to output srcjar for GEN_JNI.java (Or J/N.java if proxy'
+      ' hash is enabled).')
   arg_parser.add_argument(
       '--sources-blacklist',
       default=[],
@@ -551,12 +562,12 @@
       default=False,
       action='store_true',
       help='Requires all used native implementations to have a mock set when '
-           'called. Otherwise an exception will be thrown.')
+      'called. Otherwise an exception will be thrown.')
   arg_parser.add_argument(
       '--use_proxy_hash',
       action='store_true',
       help='Enables hashing of the native declaration for methods in '
-           'an @JniNatives interface')
+      'an @JniNatives interface')
   args = arg_parser.parse_args(build_utils.ExpandFileArgs(argv[1:]))
 
   if not args.enable_proxy_mocks and args.require_mocks:
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index ea79cb1..3175d35 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1762,6 +1762,7 @@
         jar_excluded_patterns = []
       }
       jar_excluded_patterns += [
+        "*J/N.class",
         "*/GEN_JNI.class",
         "*/R.class",
         "*/R\$*.class",