Bug 1116589 - Use templated JNI classes in generated bindings; r=snorp
authorJim Chen <nchen@mozilla.com>
Fri, 09 Jan 2015 19:33:57 -0500
changeset 223154 e706eac29b226646543cbab604a976b28352930a
parent 223153 69654c281aaac7e1724080995386a674847d9c8a
child 223155 5f6cebc36e84fb574d5809ac91bb1a42190658f4
push id10769
push usercbook@mozilla.com
push dateMon, 12 Jan 2015 14:15:52 +0000
treeherderfx-team@0e9765732906 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssnorp
bugs1116589
milestone37.0a1
Bug 1116589 - Use templated JNI classes in generated bindings; r=snorp
CLOBBER
build/annotationProcessors/AnnotationInfo.java
build/annotationProcessors/AnnotationProcessor.java
build/annotationProcessors/CodeGenerator.java
build/annotationProcessors/SDKProcessor.java
build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
build/annotationProcessors/utils/GeneratableElementIterator.java
build/annotationProcessors/utils/Utils.java
dom/ipc/ContentParent.cpp
dom/media/fmp4/android/AndroidDecoderModule.cpp
dom/media/fmp4/android/AndroidDecoderModule.h
dom/plugins/base/android/ANPSystem.cpp
dom/plugins/base/nsNPAPIPlugin.cpp
dom/plugins/base/nsNPAPIPluginInstance.cpp
dom/plugins/base/nsPluginInstanceOwner.cpp
dom/system/android/AndroidLocationProvider.cpp
dom/system/android/nsHapticFeedback.cpp
gfx/gl/AndroidSurfaceTexture.cpp
gfx/gl/AndroidSurfaceTexture.h
hal/android/AndroidGamepad.cpp
hal/android/AndroidHal.cpp
hal/android/AndroidSensor.cpp
ipc/glue/MessagePump.cpp
mobile/android/base/GeckoAppShell.java
mobile/android/components/build/nsAndroidHistory.cpp
mobile/android/components/build/nsShellService.cpp
mozglue/android/jni-stubs.inc
netwerk/base/src/Tickler.cpp
netwerk/protocol/device/CameraStreamImpl.cpp
netwerk/system/android/nsAndroidNetworkLinkService.cpp
toolkit/components/alerts/nsAlertsService.cpp
toolkit/components/downloads/nsDownloadManager.cpp
toolkit/components/jsdownloads/src/DownloadPlatform.cpp
toolkit/components/parentalcontrols/nsParentalControlsServiceAndroid.cpp
toolkit/xre/nsAndroidStartup.cpp
toolkit/xre/nsAppRunner.cpp
tools/profiler/TableTicker.cpp
tools/profiler/platform.cpp
uriloader/exthandler/android/nsAndroidHandlerApp.cpp
uriloader/exthandler/android/nsExternalSharingAppService.cpp
uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
widget/android/APZCCallbackHandler.cpp
widget/android/APZCCallbackHandler.h
widget/android/AndroidBridge.cpp
widget/android/AndroidBridge.h
widget/android/AndroidJNI.cpp
widget/android/AndroidJavaWrappers.cpp
widget/android/GeneratedJNIWrappers.cpp
widget/android/GeneratedJNIWrappers.h
widget/android/nsAndroidProtocolHandler.cpp
widget/android/nsAppShell.cpp
widget/android/nsClipboard.cpp
widget/android/nsIMEPicker.cpp
widget/android/nsLookAndFeel.cpp
widget/android/nsScreenManagerAndroid.cpp
widget/android/nsWindow.cpp
xpcom/base/nsSystemInfo.cpp
xpcom/components/ManifestParser.cpp
xpcom/io/nsLocalFileUnix.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1056337 - Change default compiler for B2G ICS builds.
+Bug 1116589 - Clobber needed to update autogenerated Android library bindings.
--- a/build/annotationProcessors/AnnotationInfo.java
+++ b/build/annotationProcessors/AnnotationInfo.java
@@ -17,14 +17,14 @@ public class AnnotationInfo {
     public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded,
                           boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) {
         wrapperName = aWrapperName;
         isMultithreaded = aIsMultithreaded;
         noThrow = aNoThrow;
         narrowChars = aNarrowChars;
         catchException = aCatchException;
 
-        if (!noThrow && catchException) {
+        if (noThrow && catchException) {
             // It doesn't make sense to have these together
             throw new IllegalArgumentException("noThrow and catchException are not allowed together");
         }
     }
 }
--- a/build/annotationProcessors/AnnotationProcessor.java
+++ b/build/annotationProcessors/AnnotationProcessor.java
@@ -15,19 +15,21 @@ import java.util.Arrays;
 import java.util.Iterator;
 
 public class AnnotationProcessor {
     public static final String OUTFILE = "GeneratedJNIWrappers.cpp";
     public static final String HEADERFILE = "GeneratedJNIWrappers.h";
 
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
-            "// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
-            "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
-            "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
 
     public static void main(String[] args) {
         // We expect a list of jars on the commandline. If missing, whinge about it.
         if (args.length <= 1) {
             System.err.println("Usage: java AnnotationProcessor jarfiles ...");
             System.exit(1);
         }
 
@@ -39,54 +41,47 @@ public class AnnotationProcessor {
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
         Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
 
         StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
-        headerFile.append("#ifndef GeneratedJNIWrappers_h__\n" +
-                          "#define GeneratedJNIWrappers_h__\n\n" +
-                          "#include \"nsXPCOMStrings.h\"\n" +
-                          "#include \"AndroidJavaWrappers.h\"\n" +
-                          "\n" +
-                          "namespace mozilla {\n" +
-                          "namespace widget {\n" +
-                          "namespace android {\n" +
-                          "void InitStubs(JNIEnv *env);\n\n");
+        headerFile.append(
+                "#ifndef GeneratedJNIWrappers_h__\n" +
+                "#define GeneratedJNIWrappers_h__\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
 
         StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
-        implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" +
-                                  "#include \"AndroidBridgeUtilities.h\"\n" +
-                                  "#include \"nsXPCOMStrings.h\"\n" +
-                                  "#include \"AndroidBridge.h\"\n" +
-                                  "\n" +
-                                  "namespace mozilla {\n" +
-                                  "namespace widget {\n" +
-                                  "namespace android {\n");
-
-        // Used to track the calls to the various class-specific initialisation functions.
-        StringBuilder stubInitialiser = new StringBuilder();
-        stubInitialiser.append("void InitStubs(JNIEnv *env) {\n");
+        implementationFile.append(
+                "#include \"GeneratedJNIWrappers.h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "\n");
 
         while (jarClassIterator.hasNext()) {
             ClassWithOptions aClassTuple = jarClassIterator.next();
 
             CodeGenerator generatorInstance;
 
             // Get an iterator over the appropriately generated methods of this class
             Iterator<AnnotatableEntity> methodIterator = new GeneratableElementIterator(aClassTuple.wrappedClass);
 
             if (!methodIterator.hasNext()) {
                 continue;
             }
-            generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName);
-
-            stubInitialiser.append("    ").append(aClassTuple.generatedName).append("::InitStubs(env);\n");
+            generatorInstance = new CodeGenerator(aClassTuple);
 
             // Iterate all annotated members in this class..
             while (methodIterator.hasNext()) {
                 AnnotatableEntity aElementTuple = methodIterator.next();
                 switch (aElementTuple.mEntityType) {
                     case METHOD:
                         generatorInstance.generateMethod(aElementTuple);
                         break;
@@ -98,28 +93,26 @@ public class AnnotationProcessor {
                         break;
                 }
             }
 
             headerFile.append(generatorInstance.getHeaderFileContents());
             implementationFile.append(generatorInstance.getWrapperFileContents());
         }
 
-        implementationFile.append('\n');
-        stubInitialiser.append("}");
-        implementationFile.append(stubInitialiser);
+        implementationFile.append(
+                "\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
 
-        implementationFile.append("\n} /* android */\n" +
-                                    "} /* widget */\n" +
-                                    "} /* mozilla */\n");
-
-        headerFile.append("\n} /* android */\n" +
-                            "} /* widget */\n" +
-                            "} /* mozilla */\n" +
-                            "#endif\n");
+        headerFile.append(
+                "\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif // GeneratedJNIWrappers_h__\n");
 
         writeOutputFiles(headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("Annotation processing complete in " + (e - s) + "ms");
     }
 
     private static void writeOutputFiles(StringBuilder aHeaderFile, StringBuilder aImplementationFile) {
         FileOutputStream headerStream = null;
@@ -153,9 +146,9 @@ public class AnnotationProcessor {
                     outStream.close();
                 } catch (IOException e) {
                     System.err.println("Unable to close outStream due to "+e);
                     e.printStackTrace(System.err);
                 }
             }
         }
     }
-}
\ No newline at end of file
+}
--- a/build/annotationProcessors/CodeGenerator.java
+++ b/build/annotationProcessors/CodeGenerator.java
@@ -1,693 +1,462 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.annotationProcessors;
 
 import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
+import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
 import org.mozilla.gecko.annotationProcessors.utils.Utils;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.HashMap;
 import java.util.HashSet;
 
 public class CodeGenerator {
     private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
-    private static final Annotation[][] GETTER_ARGUMENT_ANNOTATIONS = new Annotation[0][0];
-    private static final Annotation[][] SETTER_ARGUMENT_ANNOTATIONS = new Annotation[1][0];
 
     // Buffers holding the strings to ultimately be written to the output files.
-    private final StringBuilder zeroingCode = new StringBuilder();
-    private final StringBuilder wrapperStartupCode = new StringBuilder();
-    private final StringBuilder wrapperMethodBodies = new StringBuilder();
-    private final StringBuilder headerPublic = new StringBuilder();
-    private final StringBuilder headerProtected = new StringBuilder();
+    private final StringBuilder cpp = new StringBuilder();
+    private final StringBuilder header = new StringBuilder();
+
+    private final Class<?> cls;
+    private final String clsName;
 
-    private final HashSet<String> seenClasses = new HashSet<String>();
+    private final HashSet<String> takenMethodNames = new HashSet<String>();
 
-    private final String mCClassName;
-
-    private final Class<?> mClassToWrap;
+    public CodeGenerator(ClassWithOptions annotatedClass) {
+        this.cls = annotatedClass.wrappedClass;
+        this.clsName = annotatedClass.generatedName;
 
-    private boolean mHasEncounteredDefaultConstructor;
+        header.append(
+                "class " + clsName + " : public mozilla::jni::Class<" + clsName + "> {\n" +
+                "\n" +
+                "public:\n" +
+                "    typedef mozilla::jni::Ref<" + clsName + "> Ref;\n" +
+                "    typedef mozilla::jni::LocalRef<" + clsName + "> LocalRef;\n" +
+                "    typedef mozilla::jni::GlobalRef<" + clsName + "> GlobalRef;\n" +
+                "    typedef const typename mozilla::jni::Param<" + clsName + ">::Type& Param;\n" +
+                "\n" +
+                "    static constexpr char name[] =\n" +
+                "            \"" + cls.getName().replace('.', '/') + "\";\n" +
+                "\n" +
+                "protected:\n" +
+                "    " + clsName + "(jobject instance) : Class(instance) {}\n" +
+                "\n");
 
-    // Used for creating unique names for method ID fields in the face of
-    private final HashMap<Member, String> mMembersToIds = new HashMap<Member, String>();
-    private final HashSet<String> mTakenMemberNames = new HashSet<String>();
-    private int mNameMunger;
+        cpp.append(
+                "constexpr char " + clsName + "::name[];\n" +
+                "\n");
+    }
 
-    private final boolean mLazyInit;
+    private String getTraitsName(String uniqueName, boolean includeScope) {
+        return (includeScope ? clsName + "::" : "") + uniqueName + "_t";
+    }
 
-    public CodeGenerator(Class<?> aClass, String aGeneratedName) {
-        this(aClass, aGeneratedName, false);
+    private String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        if (type == cls) {
+            return clsName + "::Param";
+        }
+        return Utils.getNativeParameterType(type, info);
     }
 
-    public CodeGenerator(Class<?> aClass, String aGeneratedName, boolean aLazyInit) {
-        mClassToWrap = aClass;
-        mCClassName = aGeneratedName;
-        mLazyInit = aLazyInit;
+    private String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        if (type == cls) {
+            return clsName + "::LocalRef";
+        }
+        return Utils.getNativeReturnType(type, info);
+    }
 
-        // Write the file header things. Includes and so forth.
-        // GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with
-        // wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic
-        // with headerProtected.
-        wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *env) {\n");
+    private void generateMember(AnnotationInfo info, Member member,
+                                String uniqueName, Class<?> type) {
+        header.append(
+                "public:\n" +
+                "    struct " + getTraitsName(uniqueName, /* includeScope */ false) + " {\n" +
+                "        typedef " + clsName + " Owner;\n" +
+                "        typedef " + getNativeReturnType(type, info) + " ReturnType;\n" +
+                "        typedef " + getNativeParameterType(type, info) + " SetterType;\n" +
+                "        static constexpr char name[] = \"" +
+                        Utils.getMemberName(member) + "\";\n" +
+                "        static constexpr char signature[] =\n" +
+                "                \"" + Utils.getSignature(member) + "\";\n" +
+                "        static const bool isStatic = " + Utils.isStatic(member) + ";\n" +
+                "        static const bool isMultithreaded = " + info.isMultithreaded + ";\n" +
+                "        static const mozilla::jni::ExceptionMode exceptionMode = " + (
+                        info.catchException ? "mozilla::jni::ExceptionMode::NSRESULT" :
+                        info.noThrow ?        "mozilla::jni::ExceptionMode::IGNORE" :
+                                              "mozilla::jni::ExceptionMode::ABORT") + ";\n" +
+                "    };\n" +
+                "\n");
 
-        // Now we write the various GetStaticMethodID calls here...
-        headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" +
-                            "public:\n" +
-                            "    static void InitStubs(JNIEnv *env);\n");
-        headerProtected.append("protected:");
+        cpp.append(
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::name[];\n" +
+                "constexpr char " + getTraitsName(uniqueName, /* includeScope */ true) +
+                        "::signature[];\n" +
+                "\n");
+    }
 
-        generateWrapperMethod();
+    private String getUniqueMethodName(String basename) {
+        String newName = basename;
+        int index = 1;
+
+        while (takenMethodNames.contains(newName)) {
+            newName = basename + (++index);
+        }
+
+        takenMethodNames.add(newName);
+        return newName;
     }
 
     /**
-     * Emit a static method which takes an instance of the class being wrapped and returns an instance
-     * of the C++ wrapper class backed by that object.
+     * Generate a method prototype that includes return and argument types,
+     * without specifiers (static, const, etc.).
      */
-    private void generateWrapperMethod() {
-        headerPublic.append("    static ").append(mCClassName).append("* Wrap(jobject obj);\n" +
-                "    ").append(mCClassName).append("(jobject obj, JNIEnv* env) : AutoGlobalWrappedJavaObject(obj, env) {};\n");
+    private String generatePrototype(String name, Class<?>[] argTypes,
+                                     Class<?> returnType, AnnotationInfo info,
+                                     boolean includeScope, boolean includeArgName) {
+
+        final StringBuilder proto = new StringBuilder();
+        int argIndex = 0;
+
+        if (info.catchException) {
+            proto.append("nsresult ");
+        } else {
+            proto.append(getNativeReturnType(returnType, info)).append(' ');
+        }
+
+        if (includeScope) {
+            proto.append(clsName).append("::");
+        }
+
+        proto.append(name).append('(');
 
-        wrapperMethodBodies.append("\n").append(mCClassName).append("* ").append(mCClassName).append("::Wrap(jobject obj) {\n" +
-                "    JNIEnv *env = GetJNIForThread();\n" +
-                "    ").append(mCClassName).append("* ret = new ").append(mCClassName).append("(obj, env);\n" +
-                "    env->DeleteLocalRef(obj);\n" +
-                "    return ret;\n" +
-                "}\n");
+        for (Class<?> argType : argTypes) {
+            proto.append(getNativeParameterType(argType, info));
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (info.catchException && returnType != void.class) {
+            proto.append(getNativeReturnType(returnType, info)).append('*');
+            if (includeArgName) {
+                proto.append(" a").append(argIndex++);
+            }
+            proto.append(", ");
+        }
+
+        if (proto.substring(proto.length() - 2).equals(", ")) {
+            proto.setLength(proto.length() - 2);
+        }
+
+        return proto.append(')').toString();
+    }
+
+    /**
+     * Generate a method declaration that includes the prototype with specifiers,
+     * but without the method body.
+     */
+    private String generateDeclaration(String name, Class<?>[] argTypes,
+                                       Class<?> returnType, AnnotationInfo info,
+                                       boolean isStatic) {
+
+        return (isStatic ? "static " : "") +
+            generatePrototype(name, argTypes, returnType, info,
+                              /* includeScope */ false, /* includeArgName */ false) +
+            (isStatic ? ";" : " const;");
     }
 
-    private void generateMemberCommon(Member theMethod, String aCMethodName, Class<?> aClass) {
-        ensureClassHeaderAndStartup(aClass);
-        writeMemberIdField(theMethod, aCMethodName);
+    /**
+     * Generate a method definition that includes the prototype with specifiers,
+     * and with the method body.
+     */
+    private String generateDefinition(String accessorName, String name, Class<?>[] argTypes,
+                                      Class<?> returnType, AnnotationInfo info, boolean isStatic) {
+
+        final StringBuilder def = new StringBuilder(
+                generatePrototype(name, argTypes, returnType, info,
+                                  /* includeScope */ true, /* includeArgName */ true));
+
+        if (!isStatic) {
+            def.append(" const");
+        }
+        def.append("\n{\n");
+
+
+        // Generate code to handle the return value, if needed.
+        // We initialize rv to NS_OK instead of NS_ERROR_* because loading NS_OK (0) uses
+        // fewer instructions. We are guaranteed to set rv to the correct value later.
+
+        if (info.catchException && returnType == void.class) {
+            def.append(
+                    "    nsresult rv = NS_OK;\n" +
+                    "    ");
 
-        if (!mLazyInit) {
-            writeMemberInit(theMethod, wrapperStartupCode);
+        } else if (info.catchException) {
+            // Non-void return type
+            final String resultArg = "a" + argTypes.length;
+            def.append(
+                    "    MOZ_ASSERT(" + resultArg + ");\n" +
+                    "    nsresult rv = NS_OK;\n" +
+                    "    *" + resultArg + " = ");
+
+        } else {
+            def.append(
+                    "    return ");
         }
+
+
+        // Generate a call, e.g., Method<Traits>::Call(a0, a1, a2);
+
+        def.append(accessorName).append("(")
+           .append(isStatic ? "nullptr" : "this");
+
+        if (info.catchException) {
+            def.append(", &rv");
+        } else {
+            def.append(", nullptr");
+        }
+
+        // Generate the call argument list.
+        for (int argIndex = 0; argIndex < argTypes.length; argIndex++) {
+            def.append(", a").append(argIndex);
+        }
+
+        def.append(");\n");
+
+
+        if (info.catchException) {
+            def.append("    return rv;\n");
+        }
+
+        return def.append("}").toString();
     }
 
     /**
      * Append the appropriate generated code to the buffers for the method provided.
      *
-     * @param aMethodTuple The Java method, plus annotation data.
+     * @param annotatedMethod The Java method, plus annotation data.
      */
-    public void generateMethod(AnnotatableEntity aMethodTuple) {
+    public void generateMethod(AnnotatableEntity annotatedMethod) {
         // Unpack the tuple and extract some useful fields from the Method..
-        Method theMethod = aMethodTuple.getMethod();
-
-        String CMethodName = aMethodTuple.mAnnotationInfo.wrapperName;
-
-        generateMemberCommon(theMethod, CMethodName, mClassToWrap);
-
-        boolean isFieldStatic = Utils.isMemberStatic(theMethod);
-
-        Class<?>[] parameterTypes = theMethod.getParameterTypes();
-        Class<?> returnType = theMethod.getReturnType();
+        final Method method = annotatedMethod.getMethod();
+        final AnnotationInfo info = annotatedMethod.mAnnotationInfo;
+        final String uniqueName = getUniqueMethodName(info.wrapperName);
+        final Class<?> returnType = method.getReturnType();
 
-        // Get the C++ method signature for this method.
-        String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName,
-            mCClassName, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
-        String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType,
-            CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
-
-        // Add the header signature to the header file.
-        writeSignatureToHeader(headerSignature);
-
-        // Use the implementation signature to generate the method body...
-        writeMethodBody(implementationSignature, theMethod, mClassToWrap,
-                        aMethodTuple.mAnnotationInfo.isMultithreaded,
-                        aMethodTuple.mAnnotationInfo.noThrow,
-                        aMethodTuple.mAnnotationInfo.narrowChars,
-                        aMethodTuple.mAnnotationInfo.catchException);
-    }
-
-    private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
-        StringBuilder argumentContent = null;
-        Class<?> fieldType = aField.getType();
-
-        if (isSetter) {
-            Class<?>[] setterArguments = new Class<?>[]{fieldType};
-            // Marshall the argument..
-            argumentContent = getArgumentMarshalling(setterArguments);
+        if (method.isSynthetic()) {
+            return;
         }
 
-        if (mLazyInit) {
-            writeMemberInit(aField, wrapperMethodBodies);
-        }
+        generateMember(info, method, uniqueName, returnType);
+
+        final Class<?>[] argTypes = method.getParameterTypes();
+        final boolean isStatic = Utils.isStatic(method);
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, argTypes,
+                                             returnType, info, isStatic) + "\n" +
+                "\n");
+
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Method<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        info.wrapperName, argTypes, returnType, info, isStatic) + "\n" +
+                "\n");
+    }
 
-        boolean isObjectReturningMethod = Utils.isObjectType(fieldType);
-        wrapperMethodBodies.append("    ");
-        if (isSetter) {
-            wrapperMethodBodies.append("env->Set");
-        } else {
-            wrapperMethodBodies.append("return ");
+    private String getLiteral(Object val, AnnotationInfo info) {
+        final Class<?> type = val.getClass();
+
+        if (type == char.class || type == Character.class) {
+            final char c = (char) val;
+            if (c >= 0x20 && c < 0x7F) {
+                return "'" + c + '\'';
+            }
+            return "u'\\u" + Integer.toHexString(0x10000 | (int) c).substring(1) + '\'';
 
-            if (isObjectReturningMethod) {
-                wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(fieldType, aNarrowChars)).append(">(");
+        } else if (type == CharSequence.class || type == String.class) {
+            final CharSequence str = (CharSequence) val;
+            final StringBuilder out = new StringBuilder(info.narrowChars ? "u8\"" : "u\"");
+            for (int i = 0; i < str.length(); i++) {
+                final char c = str.charAt(i);
+                if (c >= 0x20 && c < 0x7F) {
+                    out.append(c);
+                } else {
+                    out.append("\\u").append(Integer.toHexString(0x10000 | (int) c).substring(1));
+                }
             }
-
-            wrapperMethodBodies.append("env->Get");
+            return out.append('"').toString();
         }
 
-        if (aIsFieldStatic) {
-            wrapperMethodBodies.append("Static");
-        }
-        wrapperMethodBodies.append(Utils.getFieldType(fieldType))
-                           .append("Field(");
-
-        // Static will require the class and the field id. Nonstatic, the object and the field id.
-        if (aIsFieldStatic) {
-            wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap));
-        } else {
-            wrapperMethodBodies.append("wrapped_obj");
-        }
-        wrapperMethodBodies.append(", j")
-                           .append(aFieldName);
-        if (isSetter) {
-            wrapperMethodBodies.append(argumentContent);
-        }
-
-        if (!isSetter && isObjectReturningMethod) {
-            wrapperMethodBodies.append(')');
-        }
-        wrapperMethodBodies.append(");\n" +
-                               "}\n");
+        return String.valueOf(val);
     }
 
-    public void generateField(AnnotatableEntity aFieldTuple) {
-        Field theField = aFieldTuple.getField();
+    public void generateField(AnnotatableEntity annotatedField) {
+        final Field field = annotatedField.getField();
+        final AnnotationInfo info = annotatedField.mAnnotationInfo;
+        final String uniqueName = info.wrapperName;
+        final Class<?> type = field.getType();
 
         // Handles a peculiar case when dealing with enum types. We don't care about this field.
         // It just gets in the way and stops our code from compiling.
-        if (theField.getName().equals("$VALUES")) {
+        if (field.isSynthetic() || field.getName().equals("$VALUES")) {
             return;
         }
 
-        String CFieldName = aFieldTuple.mAnnotationInfo.wrapperName;
+        final boolean isStatic = Utils.isStatic(field);
+        final boolean isFinal = Utils.isFinal(field);
 
-        Class<?> fieldType = theField.getType();
-
-        generateMemberCommon(theField, CFieldName, mClassToWrap);
+        if (isStatic && isFinal && (type.isPrimitive() || type == String.class)) {
+            Object val = null;
+            try {
+                val = field.get(null);
+            } catch (final IllegalAccessException e) {
+            }
 
-        boolean isFieldStatic = Utils.isMemberStatic(theField);
-        boolean isFieldFinal = Utils.isMemberFinal(theField);
+            if (val != null && type.isPrimitive()) {
+                // For static final primitive fields, we can use a "static const" declaration.
+                header.append(
+                    "public:\n" +
+                    "    static const " + Utils.getNativeReturnType(type, info) +
+                            ' ' + info.wrapperName + " = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+
+            } else if (val != null && type == String.class) {
+                final String nativeType = info.narrowChars ? "char" : "char16_t";
 
-        String getterName = "get" + CFieldName;
-        String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
-        String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
+                header.append(
+                    "public:\n" +
+                    "    static const " + nativeType + ' ' + info.wrapperName + "[];\n" +
+                    "\n");
 
-        writeSignatureToHeader(getterHeaderSignature);
-
-        writeFunctionStartupBoilerPlate(getterSignature, true);
+                cpp.append(
+                    "const " + nativeType + ' ' + clsName + "::" + info.wrapperName +
+                            "[] = " + getLiteral(val, info) + ";\n" +
+                    "\n");
+                return;
+            }
 
-        generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars);
+            // Fall back to using accessors if we encounter an exception.
+        }
+
+        generateMember(info, field, uniqueName, type);
 
-        // If field not final, also generate a setter function.
-        if (!isFieldFinal) {
-            String setterName = "set" + CFieldName;
+        final Class<?>[] getterArgs = EMPTY_CLASS_ARRAY;
 
-            Class<?>[] setterArguments = new Class<?>[]{fieldType};
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, getterArgs,
+                                             type, info, isStatic) + "\n" +
+                "\n");
 
-            String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
-            String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Get",
+                        info.wrapperName, getterArgs, type, info, isStatic) + "\n" +
+                "\n");
 
-            writeSignatureToHeader(setterHeaderSignature);
+        if (isFinal) {
+            return;
+        }
 
-            writeFunctionStartupBoilerPlate(setterSignature, true);
+        final Class<?>[] setterArgs = new Class<?>[] { type };
+
+        header.append(
+                "    " + generateDeclaration(info.wrapperName, setterArgs,
+                                             void.class, info, isStatic) + "\n" +
+                "\n");
 
-            generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars);
-        }
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Field<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Set",
+                        info.wrapperName, setterArgs, void.class, info, isStatic) + "\n" +
+                "\n");
     }
 
-    public void generateConstructor(AnnotatableEntity aCtorTuple) {
+    public void generateConstructor(AnnotatableEntity annotatedConstructor) {
         // Unpack the tuple and extract some useful fields from the Method..
-        Constructor<?> theCtor = aCtorTuple.getConstructor();
-        String CMethodName = mCClassName;
+        final Constructor<?> method = annotatedConstructor.getConstructor();
+        final AnnotationInfo info = annotatedConstructor.mAnnotationInfo;
+        final String wrapperName = "New";
+        final String uniqueName = getUniqueMethodName(wrapperName);
+        final Class<?> returnType = cls;
 
-        generateMemberCommon(theCtor, mCClassName, mClassToWrap);
+        if (method.isSynthetic()) {
+            return;
+        }
 
-        String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName,
-            mCClassName, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
-        String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName,
-            mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
+        generateMember(info, method, uniqueName, returnType);
 
-        // Slice off the "void " from the start of the constructor declaration.
-        headerSignature = headerSignature.substring(5);
-        implementationSignature = implementationSignature.substring(5);
+        final Class<?>[] argTypes = method.getParameterTypes();
 
-        // Add the header signatures to the header file.
-        writeSignatureToHeader(headerSignature);
+        header.append(
+                "    " + generateDeclaration(wrapperName, argTypes,
+                                             returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
 
-        // Use the implementation signature to generate the method body...
-        writeCtorBody(implementationSignature, theCtor,
-            aCtorTuple.mAnnotationInfo.isMultithreaded,
-            aCtorTuple.mAnnotationInfo.noThrow,
-            aCtorTuple.mAnnotationInfo.catchException);
-
-        if (theCtor.getParameterTypes().length == 0) {
-            mHasEncounteredDefaultConstructor = true;
-        }
+        cpp.append(
+                generateDefinition(
+                        "mozilla::jni::Constructor<" +
+                                getTraitsName(uniqueName, /* includeScope */ false) + ">::Call",
+                        wrapperName, argTypes, returnType, info, /* isStatic */ true) + "\n" +
+                "\n");
     }
 
     public void generateMembers(Member[] members) {
         for (Member m : members) {
             if (!Modifier.isPublic(m.getModifiers())) {
                 continue;
             }
 
-            String name = m.getName();
+            String name = Utils.getMemberName(m);
             name = name.substring(0, 1).toUpperCase() + name.substring(1);
 
-            AnnotationInfo info = new AnnotationInfo(name, true, true, true, true);
-            AnnotatableEntity entity = new AnnotatableEntity(m, info);
+            final AnnotationInfo info = new AnnotationInfo(name,
+                    /* multithread */ true, /* nothrow */ false,
+                    /* narrow */ false, /* catchException */ true);
+            final AnnotatableEntity entity = new AnnotatableEntity(m, info);
+
             if (m instanceof Constructor) {
                 generateConstructor(entity);
             } else if (m instanceof Method) {
                 generateMethod(entity);
             } else if (m instanceof Field) {
                 generateField(entity);
             } else {
-                throw new IllegalArgumentException("expected member to be Constructor, Method, or Field");
-            }
-        }
-    }
-
-    /**
-     * Writes the appropriate header and startup code to ensure the existence of a reference to the
-     * class specified. If this is already done, does nothing.
-     *
-     * @param aClass The target class.
-     */
-    private void ensureClassHeaderAndStartup(Class<?> aClass) {
-        String className = aClass.getCanonicalName();
-        if (seenClasses.contains(className)) {
-            return;
-        }
-
-        zeroingCode.append("jclass ")
-                   .append(mCClassName)
-                   .append("::")
-                   .append(Utils.getClassReferenceName(aClass))
-                   .append(" = 0;\n");
-
-        // Add a field to hold the reference...
-        headerProtected.append("\n    static jclass ")
-                       .append(Utils.getClassReferenceName(aClass))
-                       .append(";\n");
-
-        // Add startup code to populate it..
-        wrapperStartupCode.append(Utils.getStartupLineForClass(aClass));
-
-        seenClasses.add(className);
-    }
-
-    /**
-     * Writes code for getting the JNIEnv instance.
-     */
-    private void writeFunctionStartupBoilerPlate(String methodSignature, boolean aIsThreaded) {
-        // The start-of-function boilerplate. Does the bridge exist? Does the env exist? etc.
-        wrapperMethodBodies.append('\n')
-                           .append(methodSignature)
-                           .append(" {\n");
-
-        wrapperMethodBodies.append("    JNIEnv *env = ");
-        if (!aIsThreaded) {
-            wrapperMethodBodies.append("AndroidBridge::GetJNIEnv();\n");
-        } else {
-            wrapperMethodBodies.append("GetJNIForThread();\n");
-        }
-    }
-
-    /**
-     * Write out the appropriate JNI frame pushing boilerplate for a call to the member provided (
-     * which must be a constructor or method).
-     *
-     * @param aMethod A constructor/method being wrapped.
-     * @param aIsObjectReturningMethod Does the method being wrapped return an object?
-     */
-    private void writeFramePushBoilerplate(Member aMethod,
-            boolean aIsObjectReturningMethod, boolean aNoThrow) {
-        if (aMethod instanceof Field) {
-            throw new IllegalArgumentException("Tried to push frame for a FIELD?!");
-        }
-
-        Method m;
-        Constructor<?> c;
-
-        Class<?> returnType;
-
-        int localReferencesNeeded;
-        if (aMethod instanceof Method) {
-            m = (Method) aMethod;
-            returnType = m.getReturnType();
-            localReferencesNeeded = Utils.enumerateReferenceArguments(m.getParameterTypes());
-        } else {
-            c = (Constructor<?>) aMethod;
-            returnType = Void.class;
-            localReferencesNeeded = Utils.enumerateReferenceArguments(c.getParameterTypes());
-        }
-
-        // Determine the number of local refs required for our local frame..
-        // AutoLocalJNIFrame is not applicable here due to it's inability to handle return values.
-        if (aIsObjectReturningMethod) {
-            localReferencesNeeded++;
-        }
-        wrapperMethodBodies.append(
-                "    if (env->PushLocalFrame(").append(localReferencesNeeded).append(") != 0) {\n");
-        if (!aNoThrow) {
-            wrapperMethodBodies.append(
-                "        AndroidBridge::HandleUncaughtException(env);\n" +
-                "        MOZ_CRASH(\"Exception should have caused crash.\");\n");
-        } else {
-            wrapperMethodBodies.append(
-                "        return").append(Utils.getFailureReturnForType(returnType)).append(";\n");
-        }
-        wrapperMethodBodies.append(
-                "    }\n\n");
-    }
-
-    private StringBuilder getArgumentMarshalling(Class<?>[] argumentTypes) {
-        StringBuilder argumentContent = new StringBuilder();
-
-        // If we have >2 arguments, use the jvalue[] calling approach.
-        argumentContent.append(", ");
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append("    jvalue args[").append(argumentTypes.length).append("];\n");
-            for (int aT = 0; aT < argumentTypes.length; aT++) {
-                wrapperMethodBodies.append("    args[").append(aT).append("].")
-                                   .append(Utils.getArrayArgumentMashallingLine(argumentTypes[aT], "a" + aT));
-            }
-
-            // The only argument is the array of arguments.
-            argumentContent.append("args");
-            wrapperMethodBodies.append('\n');
-        } else {
-            // Otherwise, use the vanilla calling approach.
-            boolean needsNewline = false;
-            for (int aT = 0; aT < argumentTypes.length; aT++) {
-                // If the argument is a string-esque type, create a jstring from it, otherwise
-                // it can be passed directly.
-                if (Utils.isCharSequence(argumentTypes[aT])) {
-                    wrapperMethodBodies.append("    jstring j").append(aT).append(" = AndroidBridge::NewJavaString(env, a").append(aT).append(");\n");
-                    needsNewline = true;
-                    // Ensure we refer to the newly constructed Java string - not to the original
-                    // parameter to the wrapper function.
-                    argumentContent.append('j').append(aT);
-                } else {
-                    argumentContent.append('a').append(aT);
-                }
-                if (aT != argumentTypes.length - 1) {
-                    argumentContent.append(", ");
-                }
-            }
-            if (needsNewline) {
-                wrapperMethodBodies.append('\n');
+                throw new IllegalArgumentException(
+                        "expected member to be Constructor, Method, or Field");
             }
         }
-
-        return argumentContent;
-    }
-
-    private void writeCatchException() {
-        wrapperMethodBodies.append(
-            "    if (env->ExceptionCheck()) {\n" +
-            "        env->ExceptionClear();\n" +
-            "        if (aResult) {\n" +
-            "            *aResult = NS_ERROR_FAILURE;\n" +
-            "        }\n" +
-            "    } else if (aResult) {\n" +
-            "        *aResult = NS_OK;\n" +
-            "    }\n\n");
-    }
-
-    private void writeCtorBody(String implementationSignature, Constructor<?> theCtor,
-            boolean aIsThreaded, boolean aNoThrow, boolean aCatchException) {
-        Class<?>[] argumentTypes = theCtor.getParameterTypes();
-
-        writeFunctionStartupBoilerPlate(implementationSignature, aIsThreaded);
-
-        writeFramePushBoilerplate(theCtor, false, aNoThrow);
-
-        if (mLazyInit) {
-            writeMemberInit(theCtor, wrapperMethodBodies);
-        }
-
-        // Marshall arguments for this constructor, if any...
-        boolean hasArguments = argumentTypes.length != 0;
-
-        StringBuilder argumentContent = new StringBuilder();
-        if (hasArguments) {
-            argumentContent = getArgumentMarshalling(argumentTypes);
-        }
-
-        // The call into Java
-        wrapperMethodBodies.append("    Init(env->NewObject");
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append('A');
-        }
-
-        wrapperMethodBodies.append('(');
-
-
-        // Call takes class id, method id of constructor method, then arguments.
-        wrapperMethodBodies.append(Utils.getClassReferenceName(mClassToWrap)).append(", ");
-
-        wrapperMethodBodies.append(mMembersToIds.get(theCtor))
-        // Tack on the arguments, if any..
-                           .append(argumentContent)
-                           .append("), env);\n");
-
-        // Check for exception and set aResult
-        if (aCatchException) {
-            writeCatchException();
-        }
-
-        wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n}\n");
-    }
-
-    /**
-     * Generates the method body of the C++ wrapper function for the Java method indicated.
-     *
-     * @param methodSignature The previously-generated C++ method signature for the method to be
-     *                        generated.
-     * @param aMethod         The Java method to be wrapped by the C++ method being generated.
-     * @param aClass          The Java class to which the method belongs.
-     */
-    private void writeMethodBody(String methodSignature, Method aMethod,
-                                 Class<?> aClass, boolean aIsMultithreaded,
-                                 boolean aNoThrow, boolean aNarrowChars,
-                                 boolean aCatchException) {
-        Class<?>[] argumentTypes = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
-
-        writeFunctionStartupBoilerPlate(methodSignature, aIsMultithreaded);
-
-        boolean isObjectReturningMethod = !returnType.getCanonicalName().equals("void") && Utils.isObjectType(returnType);
-
-        writeFramePushBoilerplate(aMethod, isObjectReturningMethod, aNoThrow);
-
-        if (mLazyInit) {
-            writeMemberInit(aMethod, wrapperMethodBodies);
-        }
-
-        // Marshall arguments, if we have any.
-        boolean hasArguments = argumentTypes.length != 0;
-
-        // We buffer the arguments to the call separately to avoid needing to repeatedly iterate the
-        // argument list while building this line. In the coming code block, we simultaneously
-        // construct any argument marshalling code (Creation of jstrings, placement of arguments
-        // into an argument array, etc. and the actual argument list passed to the function (in
-        // argumentContent).
-        StringBuilder argumentContent = new StringBuilder();
-        if (hasArguments) {
-            argumentContent = getArgumentMarshalling(argumentTypes);
-        }
-
-        // Allocate a temporary variable to hold the return type from Java.
-        wrapperMethodBodies.append("    ");
-        if (!returnType.getCanonicalName().equals("void")) {
-            if (isObjectReturningMethod) {
-                wrapperMethodBodies.append("jobject");
-            } else {
-                wrapperMethodBodies.append(Utils.getCReturnType(returnType, aNarrowChars));
-            }
-            wrapperMethodBodies.append(" temp = ");
-        }
-
-        boolean isStaticJavaMethod = Utils.isMemberStatic(aMethod);
-
-        // The call into Java
-        wrapperMethodBodies.append("env->")
-                           .append(Utils.getCallPrefix(returnType, isStaticJavaMethod));
-        if (argumentTypes.length > 2) {
-            wrapperMethodBodies.append('A');
-        }
-
-        wrapperMethodBodies.append('(');
-        // If the underlying Java method is nonstatic, we provide the target object to the JNI.
-        if (!isStaticJavaMethod) {
-            wrapperMethodBodies.append("wrapped_obj, ");
-        } else {
-            // If this is a static underlying Java method, we need to use the class reference in our
-            // call.
-            wrapperMethodBodies.append(Utils.getClassReferenceName(aClass)).append(", ");
-        }
-
-        wrapperMethodBodies.append(mMembersToIds.get(aMethod));
-
-        // Tack on the arguments, if any..
-        wrapperMethodBodies.append(argumentContent)
-                           .append(");\n");
-
-        // Check for exception and crash if any...
-        if (!aNoThrow) {
-            wrapperMethodBodies.append("    AndroidBridge::HandleUncaughtException(env);\n");
-        }
-
-        // Check for exception and set aResult
-        if (aCatchException) {
-            writeCatchException();
-        }
-
-        // If we're returning an object, pop the callee's stack frame extracting our ref as the return
-        // value.
-        if (isObjectReturningMethod) {
-            wrapperMethodBodies.append("    ")
-                               .append(Utils.getCReturnType(returnType, aNarrowChars))
-                               .append(" ret = static_cast<").append(Utils.getCReturnType(returnType, aNarrowChars)).append(">(env->PopLocalFrame(temp));\n" +
-                                       "    return ret;\n");
-        } else if (!returnType.getCanonicalName().equals("void")) {
-            // If we're a primitive-returning function, just return the directly-obtained primative
-            // from the call to Java.
-            wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n" +
-                                       "    return temp;\n");
-        } else {
-            // If we don't return anything, just pop the stack frame and move on with life.
-            wrapperMethodBodies.append("    env->PopLocalFrame(nullptr);\n");
-        }
-        wrapperMethodBodies.append("}\n");
-    }
-
-    /**
-     * Generates the code to get the id of the given member on startup or in the member body if lazy init
-     * is requested.
-     *
-     * @param aMember         The Java member being wrapped.
-     */
-    private void writeMemberInit(Member aMember, StringBuilder aOutput) {
-        if (mLazyInit) {
-            aOutput.append("    if (!" + mMembersToIds.get(aMember) + ") {\n    ");
-        }
-
-        aOutput.append("    " + mMembersToIds.get(aMember)).append(" = AndroidBridge::Get");
-        if (Utils.isMemberStatic(aMember)) {
-            aOutput.append("Static");
-        }
-
-        boolean isField = aMember instanceof Field;
-        if (isField) {
-            aOutput.append("FieldID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
-        } else {
-            aOutput.append("MethodID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
-        }
-
-        if (aMember instanceof Constructor) {
-            aOutput.append("<init>");
-        } else {
-            aOutput.append(aMember.getName());
-        }
-
-        aOutput.append("\", \"")
-                          .append(Utils.getTypeSignatureStringForMember(aMember))
-                          .append("\");\n");
-
-        if (mLazyInit) {
-            aOutput.append("    }\n\n");
-        }
-    }
-
-    private void writeZeroingFor(Member aMember, final String aMemberName) {
-        if (aMember instanceof Field) {
-            zeroingCode.append("jfieldID ");
-        } else {
-            zeroingCode.append("jmethodID ");
-        }
-        zeroingCode.append(mCClassName)
-                   .append("::")
-                   .append(aMemberName)
-                   .append(" = 0;\n");
-    }
-
-    /**
-     * Write the field declaration for the C++ id field of the given member.
-     *
-     * @param aMember Member for which an id field needs to be generated.
-     */
-    private void writeMemberIdField(Member aMember, final String aCMethodName) {
-        String memberName = 'j'+ aCMethodName;
-
-        if (aMember instanceof Field) {
-            headerProtected.append("    static jfieldID ");
-        } else {
-            headerProtected.append("    static jmethodID ");
-        }
-
-        while(mTakenMemberNames.contains(memberName)) {
-            memberName = 'j' + aCMethodName + mNameMunger;
-            mNameMunger++;
-        }
-
-        writeZeroingFor(aMember, memberName);
-        mMembersToIds.put(aMember, memberName);
-        mTakenMemberNames.add(memberName);
-
-        headerProtected.append(memberName)
-                       .append(";\n");
-    }
-
-    /**
-     * Helper function to add a provided method signature to the public section of the generated header.
-     *
-     * @param aSignature The header to add.
-     */
-    private void writeSignatureToHeader(String aSignature) {
-        headerPublic.append("    ")
-                    .append(aSignature)
-                    .append(";\n");
     }
 
     /**
      * Get the finalised bytes to go into the generated wrappers file.
      *
      * @return The bytes to be written to the wrappers file.
      */
     public String getWrapperFileContents() {
-        wrapperStartupCode.append("}\n");
-        zeroingCode.append(wrapperStartupCode)
-                   .append(wrapperMethodBodies);
-        wrapperMethodBodies.setLength(0);
-        wrapperStartupCode.setLength(0);
-        return zeroingCode.toString();
+        return cpp.toString();
     }
 
     /**
      * Get the finalised bytes to go into the generated header file.
      *
      * @return The bytes to be written to the header file.
      */
     public String getHeaderFileContents() {
-        if (!mHasEncounteredDefaultConstructor) {
-            headerPublic.append("    ").append(mCClassName).append("() : AutoGlobalWrappedJavaObject() {};\n");
-        }
-        headerProtected.append("};\n\n");
-        headerPublic.append(headerProtected);
-        headerProtected.setLength(0);
-        return headerPublic.toString();
+        header.append(
+                "};\n" +
+                "\n");
+        return header.toString();
     }
 }
--- a/build/annotationProcessors/SDKProcessor.java
+++ b/build/annotationProcessors/SDKProcessor.java
@@ -31,19 +31,21 @@ import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 
 public class SDKProcessor {
     public static final String GENERATED_COMMENT =
             "// GENERATED CODE\n" +
-            "// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
-            "// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
-            "// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
+            "// Generated by the Java program at /build/annotationProcessors at compile time\n" +
+            "// from annotations on Java methods. To update, change the annotations on the\n" +
+            "// corresponding Javamethods and rerun the build. Manually updating this file\n" +
+            "// will cause your build to fail.\n" +
+            "\n";
 
     private static ApiLookup sApiLookup;
     private static int sMaxSdkVersion;
 
     public static void main(String[] args) throws Exception {
         // We expect a list of jars on the commandline. If missing, whinge about it.
         if (args.length < 5) {
             System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
@@ -63,74 +65,65 @@ public class SDKProcessor {
 
         // Start the clock!
         long s = System.currentTimeMillis();
 
         // Get an iterator over the classes in the jar files given...
         // Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
 
         StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
-        headerFile.append("#ifndef " + generatedFilePrefix + "_h__\n" +
-                          "#define " + generatedFilePrefix + "_h__\n" +
-                          "#include \"nsXPCOMStrings.h\"\n" +
-                          "#include \"AndroidJavaWrappers.h\"\n" +
-                          "\n" +
-                          "namespace mozilla {\n" +
-                          "namespace widget {\n" +
-                          "namespace android {\n" +
-                          "namespace sdk {\n" +
-                          "void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv);\n\n");
+        headerFile.append(
+                "#ifndef " + generatedFilePrefix + "_h__\n" +
+                "#define " + generatedFilePrefix + "_h__\n" +
+                "\n" +
+                "#include \"mozilla/jni/Refs.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
 
         StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
-        implementationFile.append("#include \"" + generatedFilePrefix + ".h\"\n" +
-                                  "#include \"AndroidBridgeUtilities.h\"\n" +
-                                  "#include \"nsXPCOMStrings.h\"\n" +
-                                  "#include \"AndroidBridge.h\"\n" +
-                                  "\n" +
-                                  "namespace mozilla {\n" +
-                                  "namespace widget {\n" +
-                                  "namespace android {\n" +
-                                  "namespace sdk {\n");
+        implementationFile.append(
+                "#include \"" + generatedFilePrefix + ".h\"\n" +
+                "#include \"mozilla/jni/Accessors.h\"\n" +
+                "\n" +
+                "namespace mozilla {\n" +
+                "namespace widget {\n" +
+                "namespace sdk {\n" +
+                "\n");
 
         // Used to track the calls to the various class-specific initialisation functions.
-        StringBuilder stubInitializer = new StringBuilder();
-        stubInitializer.append("void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv) {\n");
-
         ClassLoader loader = null;
         try {
             loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
                                                 SDKProcessor.class.getClassLoader());
         } catch (Exception e) {
-            System.out.println(e);
+            throw new RuntimeException(e.toString());
         }
 
         for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
             String className = i.next();
             System.out.println("Looking up: " + className);
 
             generateClass(Class.forName(className, true, loader),
-                          stubInitializer,
                           implementationFile,
                           headerFile);
         }
 
-        implementationFile.append('\n');
-        stubInitializer.append("}");
-        implementationFile.append(stubInitializer);
+        implementationFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n");
 
-        implementationFile.append("\n} /* sdk */\n" +
-                                    "} /* android */\n" +
-                                    "} /* widget */\n" +
-                                    "} /* mozilla */\n");
-
-        headerFile.append("\n} /* sdk */\n" +
-                            "} /* android */\n" +
-                            "} /* widget */\n" +
-                            "} /* mozilla */\n" +
-                            "#endif\n");
+        headerFile.append(
+                "} /* sdk */\n" +
+                "} /* widget */\n" +
+                "} /* mozilla */\n" +
+                "#endif\n");
 
         writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
         long e = System.currentTimeMillis();
         System.out.println("SDK processing complete in " + (e - s) + "ms");
     }
 
     private static Member[] sortAndFilterMembers(Member[] members) {
         Arrays.sort(members, new Comparator<Member>() {
@@ -140,22 +133,23 @@ public class SDKProcessor {
             }
         });
 
         ArrayList<Member> list = new ArrayList<>();
         for (Member m : members) {
             int version = 0;
 
             if (m instanceof Method || m instanceof Constructor) {
-                version = sApiLookup.getCallVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
-                                                    m.getName(),
-                                                    Utils.getTypeSignatureStringForMember(m));
+                version = sApiLookup.getCallVersion(
+                        Utils.getClassDescriptor(m.getDeclaringClass()),
+                        m.getName(),
+                        Utils.getSignature(m));
             } else if (m instanceof Field) {
-                version = sApiLookup.getFieldVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
-                                                     m.getName());
+                version = sApiLookup.getFieldVersion(
+                        Utils.getClassDescriptor(m.getDeclaringClass()), m.getName());
             } else {
                 throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
             }
 
             if (version > sMaxSdkVersion) {
                 System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
                     ", version " + version + " > " + sMaxSdkVersion);
                 continue;
@@ -163,23 +157,21 @@ public class SDKProcessor {
 
             list.add(m);
         }
 
         return list.toArray(new Member[list.size()]);
     }
 
     private static void generateClass(Class<?> clazz,
-                                      StringBuilder stubInitializer,
                                       StringBuilder implementationFile,
                                       StringBuilder headerFile) {
         String generatedName = clazz.getSimpleName();
 
-        CodeGenerator generator = new CodeGenerator(clazz, generatedName, true);
-        stubInitializer.append("    ").append(generatedName).append("::InitStubs(jEnv);\n");
+        CodeGenerator generator = new CodeGenerator(new ClassWithOptions(clazz, generatedName));
 
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors()));
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods()));
         generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields()));
 
         headerFile.append(generator.getHeaderFileContents());
         implementationFile.append(generator.getWrapperFileContents());
     }
--- a/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
+++ b/build/annotationProcessors/utils/AlphabeticAnnotatableEntityComparator.java
@@ -52,26 +52,26 @@ public class AlphabeticAnnotatableEntity
         String rName = aRhs.getName();
 
         int ret = lName.compareTo(rName);
         if (ret != 0) {
             return ret;
         }
 
         // The names were the same, so we need to compare signatures to find their uniqueness..
-        lName = Utils.getTypeSignatureStringForMethod(aLhs);
-        rName = Utils.getTypeSignatureStringForMethod(aRhs);
+        lName = Utils.getSignature(aLhs);
+        rName = Utils.getSignature(aRhs);
 
         return lName.compareTo(rName);
     }
 
     private static int compare(Constructor<?> aLhs, Constructor<?> aRhs) {
         // The names will be the same, so we need to compare signatures to find their uniqueness..
-        String lName = Utils.getTypeSignatureString(aLhs);
-        String rName = Utils.getTypeSignatureString(aRhs);
+        String lName = Utils.getSignature(aLhs);
+        String rName = Utils.getSignature(aRhs);
 
         return lName.compareTo(rName);
     }
 
     private static int compare(Field aLhs, Field aRhs) {
         // Compare field names..
         String lName = aLhs.getName();
         String rName = aRhs.getName();
--- a/build/annotationProcessors/utils/GeneratableElementIterator.java
+++ b/build/annotationProcessors/utils/GeneratableElementIterator.java
@@ -114,32 +114,35 @@ public class GeneratableElementIterator 
                     } catch (InvocationTargetException e) {
                         System.err.println("InvocationTargetException reading fields on WrapElementForJNI annotation. This really shouldn't happen.");
                         e.printStackTrace(System.err);
                         System.exit(5);
                     }
 
                     // If the method name was not explicitly given in the annotation generate one...
                     if (stubName.isEmpty()) {
-                        String aMethodName = candidateElement.getName();
-                        stubName = aMethodName.substring(0, 1).toUpperCase() + aMethodName.substring(1);
+                        stubName = Utils.getNativeName(candidateElement);
                     }
 
                     AnnotationInfo annotationInfo = new AnnotationInfo(
                         stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
                     mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
                     return;
                 }
             }
 
-            // If no annotation found, we might be expected to generate anyway using default arguments,
-            // thanks to the "Generate everything" annotation.
+            // If no annotation found, we might be expected to generate anyway
+            // using default arguments, thanks to the "Generate everything" annotation.
             if (mIterateEveryEntry) {
                 AnnotationInfo annotationInfo = new AnnotationInfo(
-                    candidateElement.getName(), false, false, false, false);
+                    Utils.getNativeName(candidateElement),
+                    /* multithreaded */ true,
+                    /* noThrow */ false,
+                    /* narrowChars */ false,
+                    /* catchException */ false);
                 mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
                 return;
             }
         }
         mNextReturnValue = null;
     }
 
     @Override
--- a/build/annotationProcessors/utils/Utils.java
+++ b/build/annotationProcessors/utils/Utils.java
@@ -1,664 +1,247 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.annotationProcessors.utils;
 
-import java.lang.annotation.Annotation;
+import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
+
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.HashMap;
 
 /**
  * A collection of utility methods used by CodeGenerator. Largely used for translating types.
  */
 public class Utils {
 
     // A collection of lookup tables to simplify the functions to follow...
-    private static final HashMap<String, String> sBasicCTypes = new HashMap<String, String>();
-
-    static {
-        sBasicCTypes.put("void", "void");
-        sBasicCTypes.put("int", "int32_t");
-        sBasicCTypes.put("boolean", "bool");
-        sBasicCTypes.put("long", "int64_t");
-        sBasicCTypes.put("double", "jdouble");
-        sBasicCTypes.put("float", "jfloat");
-        sBasicCTypes.put("char", "uint16_t");
-        sBasicCTypes.put("byte", "int8_t");
-        sBasicCTypes.put("short", "int16_t");
-    }
-
-    private static final HashMap<String, String> sArrayCTypes = new HashMap<String, String>();
+    private static final HashMap<String, String> NATIVE_TYPES = new HashMap<String, String>();
 
     static {
-        sArrayCTypes.put("int", "jintArray");
-        sArrayCTypes.put("boolean", "jbooleanArray");
-        sArrayCTypes.put("long", "jlongArray");
-        sArrayCTypes.put("double", "jdoubleArray");
-        sArrayCTypes.put("float", "jfloatArray");
-        sArrayCTypes.put("char", "jcharArray");
-        sArrayCTypes.put("byte", "jbyteArray");
-        sArrayCTypes.put("short", "jshortArray");
-    }
-
-    private static final HashMap<String, String> sStaticCallTypes = new HashMap<String, String>();
-
-    static {
-        sStaticCallTypes.put("void", "CallStaticVoidMethod");
-        sStaticCallTypes.put("int", "CallStaticIntMethod");
-        sStaticCallTypes.put("boolean", "CallStaticBooleanMethod");
-        sStaticCallTypes.put("long", "CallStaticLongMethod");
-        sStaticCallTypes.put("double", "CallStaticDoubleMethod");
-        sStaticCallTypes.put("float", "CallStaticFloatMethod");
-        sStaticCallTypes.put("char", "CallStaticCharMethod");
-        sStaticCallTypes.put("byte", "CallStaticByteMethod");
-        sStaticCallTypes.put("short", "CallStaticShortMethod");
-    }
-
-    private static final HashMap<String, String> sInstanceCallTypes = new HashMap<String, String>();
-
-    static {
-        sInstanceCallTypes.put("void", "CallVoidMethod");
-        sInstanceCallTypes.put("int", "CallIntMethod");
-        sInstanceCallTypes.put("boolean", "CallBooleanMethod");
-        sInstanceCallTypes.put("long", "CallLongMethod");
-        sInstanceCallTypes.put("double", "CallDoubleMethod");
-        sInstanceCallTypes.put("float", "CallFloatMethod");
-        sInstanceCallTypes.put("char", "CallCharMethod");
-        sInstanceCallTypes.put("byte", "CallByteMethod");
-        sInstanceCallTypes.put("short", "CallShortMethod");
+        NATIVE_TYPES.put("void", "void");
+        NATIVE_TYPES.put("boolean", "bool");
+        NATIVE_TYPES.put("byte", "int8_t");
+        NATIVE_TYPES.put("char", "char16_t");
+        NATIVE_TYPES.put("short", "int16_t");
+        NATIVE_TYPES.put("int", "int32_t");
+        NATIVE_TYPES.put("long", "int64_t");
+        NATIVE_TYPES.put("float", "float");
+        NATIVE_TYPES.put("double", "double");
     }
 
-    private static final HashMap<String, String> sFieldTypes = new HashMap<String, String>();
+    private static final HashMap<String, String> NATIVE_ARRAY_TYPES = new HashMap<String, String>();
 
     static {
-        sFieldTypes.put("int", "Int");
-        sFieldTypes.put("boolean", "Boolean");
-        sFieldTypes.put("long", "Long");
-        sFieldTypes.put("double", "Double");
-        sFieldTypes.put("float", "Float");
-        sFieldTypes.put("char", "Char");
-        sFieldTypes.put("byte", "Byte");
-        sFieldTypes.put("short", "Short");
-    }
-
-    private static final HashMap<String, String> sFailureReturns = new HashMap<String, String>();
-
-    static {
-        sFailureReturns.put("java.lang.Void", "");
-        sFailureReturns.put("void", "");
-        sFailureReturns.put("int", " 0");
-        sFailureReturns.put("boolean", " false");
-        sFailureReturns.put("long", " 0");
-        sFailureReturns.put("double", " 0.0");
-        sFailureReturns.put("float", " 0.0");
-        sFailureReturns.put("char", " 0");
-        sFailureReturns.put("byte", " 0");
-        sFailureReturns.put("short", " 0");
+        NATIVE_ARRAY_TYPES.put("boolean", "mozilla::jni::BooleanArray");
+        NATIVE_ARRAY_TYPES.put("byte", "mozilla::jni::ByteArray");
+        NATIVE_ARRAY_TYPES.put("char", "mozilla::jni::CharArray");
+        NATIVE_ARRAY_TYPES.put("short", "mozilla::jni::ShortArray");
+        NATIVE_ARRAY_TYPES.put("int", "mozilla::jni::IntArray");
+        NATIVE_ARRAY_TYPES.put("long", "mozilla::jni::LongArray");
+        NATIVE_ARRAY_TYPES.put("float", "mozilla::jni::FloatArray");
+        NATIVE_ARRAY_TYPES.put("double", "mozilla::jni::DoubleArray");
     }
 
-    private static final HashMap<String, String> sCanonicalSignatureParts = new HashMap<String, String>();
+    private static final HashMap<String, String> CLASS_DESCRIPTORS = new HashMap<String, String>();
 
     static {
-        sCanonicalSignatureParts.put("java/lang/Void", "V");
-        sCanonicalSignatureParts.put("void", "V");
-        sCanonicalSignatureParts.put("int", "I");
-        sCanonicalSignatureParts.put("boolean", "Z");
-        sCanonicalSignatureParts.put("long", "J");
-        sCanonicalSignatureParts.put("double", "D");
-        sCanonicalSignatureParts.put("float", "F");
-        sCanonicalSignatureParts.put("char", "C");
-        sCanonicalSignatureParts.put("byte", "B");
-        sCanonicalSignatureParts.put("short", "S");
-    }
-
-
-    private static final HashMap<String, String> sDefaultParameterValues = new HashMap<String, String>();
-
-    static {
-        sDefaultParameterValues.put("int", "0");
-        sDefaultParameterValues.put("boolean", "false");
-        sDefaultParameterValues.put("long", "0");
-        sDefaultParameterValues.put("double", "0");
-        sDefaultParameterValues.put("float", "0.0");
-        sDefaultParameterValues.put("char", "0");
-        sDefaultParameterValues.put("byte", "0");
-        sDefaultParameterValues.put("short", "0");
+        CLASS_DESCRIPTORS.put("void", "V");
+        CLASS_DESCRIPTORS.put("boolean", "Z");
+        CLASS_DESCRIPTORS.put("byte", "B");
+        CLASS_DESCRIPTORS.put("char", "C");
+        CLASS_DESCRIPTORS.put("short", "S");
+        CLASS_DESCRIPTORS.put("int", "I");
+        CLASS_DESCRIPTORS.put("long", "J");
+        CLASS_DESCRIPTORS.put("float", "F");
+        CLASS_DESCRIPTORS.put("double", "D");
     }
 
     /**
-     * Get the C type corresponding to the provided type parameter. Used for generating argument
-     * types for the wrapper method.
+     * Get the C++ type corresponding to the provided type parameter.
      *
      * @param type Class to determine the corresponding JNI type for.
-     * @return true if the type an object type, false otherwise.
+     * @return C++ type as a String
      */
-    public static String getCParameterType(Class<?> type, boolean aNarrowChars) {
-        String name = type.getCanonicalName();
-        if (sBasicCTypes.containsKey(name)) {
-            return sBasicCTypes.get(name);
-        }
-        // Are we dealing with an array type?
-        int len = name.length();
-        if (name.endsWith("[]")) {
-            // Determine if it is a 2D array - these map to jobjectArrays
-            name = name.substring(0, len - 2);
-            if (name.endsWith("[]")) {
-                return "jobjectArray";
-            } else {
-                // Which flavour of Array is it?
-                if (sArrayCTypes.containsKey(name)) {
-                    return sArrayCTypes.get(name);
-                }
-                return "jobjectArray";
-            }
-        }
-        // Not an array type, check the remaining possibilities before we fall back to jobject
+    public static String getNativeParameterType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
 
-        // Check for CharSequences (Strings and things that are string-like)
-        if (isCharSequence(type)) {
-            if (aNarrowChars) {
-                return "const nsACString&";
-            }
-            return "const nsAString&";
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
         }
 
-        if (name.equals("java.lang.Class")) {
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::Param";
+            }
+            return "mozilla::jni::ObjectArray::Param";
+        }
+
+        if (type == String.class || type == CharSequence.class) {
+            return "mozilla::jni::String::Param";
+        }
+
+        if (type == Class.class) {
             // You're doing reflection on Java objects from inside C, returning Class objects
             // to C, generating the corresponding code using this Java program. Really?!
-            return "jclass";
-        }
-        if (name.equals("java.lang.Throwable")) {
-            return "jthrowable";
-        }
-        return "jobject";
-    }
-
-    /**
-     * For a given Java type, get the corresponding C++ type if we're returning it from a function.
-     *
-     * @param type The Java return type.
-     * @return A string representation of the C++ return type.
-     */
-     public static String getCReturnType(Class<?> type, boolean aNarrowChars) {
-        if (type.getCanonicalName().equals("java.lang.Void")) {
-            return "void";
+            return "mozilla::jni::ClassObject::Param";
         }
-        String cParameterType = getCParameterType(type, aNarrowChars);
-        if (cParameterType.equals("const nsAString&") || cParameterType.equals("const nsACString&")) {
-            return "jstring";
-        } else {
-            return cParameterType;
-        }
-    }
 
-    /**
-     * Gets the type-specific part of the  JNI function to use to get or set a field of a given type.
-     *
-     * @param aFieldType The Java type of the field.
-     * @return A string representation of the JNI call function substring to use.
-     */
-    public static String getFieldType(Class<?> aFieldType) {
-        String name = aFieldType.getCanonicalName();
+        if (type == Throwable.class) {
+            return "mozilla::jni::Throwable::Param";
+        }
 
-        if (sFieldTypes.containsKey(name)) {
-            return sFieldTypes.get(name);
-        }
-        return "Object";
+        return "mozilla::jni::Object::Param";
     }
 
-    /**
-     * Gets the appropriate JNI call function to use to invoke a Java method with the given return
-     * type. This, plus a call postfix (Such as "A") forms a complete JNI call function name.
-     *
-     * @param aReturnType The Java return type of the method being generated.
-     * @param isStatic Boolean indicating if the underlying Java method is declared static.
-     * @return A string representation of the JNI call function prefix to use.
-     */
-    public static String getCallPrefix(Class<?> aReturnType, boolean isStatic) {
-        String name = aReturnType.getCanonicalName();
-        if (isStatic) {
-            if (sStaticCallTypes.containsKey(name)) {
-                return sStaticCallTypes.get(name);
-            }
-            return "CallStaticObjectMethod";
-        } else {
-            if (sInstanceCallTypes.containsKey(name)) {
-                return sInstanceCallTypes.get(name);
-            }
-            return "CallObjectMethod";
-        }
-    }
+    public static String getNativeReturnType(Class<?> type, AnnotationInfo info) {
+        final String name = type.getName().replace('.', '/');
 
-    /**
-     * On failure, the generated method returns a null-esque value. This helper method gets the
-     * appropriate failure return value for a given Java return type, plus a leading space.
-     *
-     * @param type Java return type of method being generated
-     * @return String representation of the failure return value to be used in the generated code.
-     */
-    public static String getFailureReturnForType(Class<?> type) {
-        String name = type.getCanonicalName();
-        if (sFailureReturns.containsKey(name)) {
-            return sFailureReturns.get(name);
+        if (NATIVE_TYPES.containsKey(name)) {
+            return NATIVE_TYPES.get(name);
         }
-        return " nullptr";
-    }
-
-    /**
-     * Helper method to get the type signature for methods, given argument and return type.
-     * Allows for the near-identical logic needed for constructors and methods to be shared.
-     * (Alas, constructor does not extend method)
-     *
-     * @param arguments Argument types of the underlying method.
-     * @param returnType Return type of the underlying method.
-     * @return The canonical Java type string for the method. eg. (IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;
-     */
-    private static String getTypeSignatureInternal(Class<?>[] arguments, Class<?> returnType) {
-        StringBuilder sb = new StringBuilder();
-        sb.append('(');
-
-        // For each argument, write its signature component to the buffer..
-        for (int i = 0; i < arguments.length; i++) {
-            writeTypeSignature(sb, arguments[i]);
-        }
-        sb.append(')');
 
-        // Write the return value's signature..
-        writeTypeSignature(sb, returnType);
-        return sb.toString();
-    }
-
-    /**
-     * Get the canonical JNI type signature for a Field.
-     *
-     * @param aField The field to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForField(Field aField) {
-        StringBuilder sb = new StringBuilder();
-        writeTypeSignature(sb, aField.getType());
-        return sb.toString();
-    }
-
-    /**
-     * Get the canonical JNI type signature for a method.
-     *
-     * @param aMethod The method to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForMethod(Method aMethod) {
-        Class<?>[] arguments = aMethod.getParameterTypes();
-        Class<?> returnType = aMethod.getReturnType();
-        return getTypeSignatureInternal(arguments, returnType);
-    }
-
-    /**
-     * Get the canonical JNI type signature for a Constructor.
-     *
-     * @param aConstructor The Constructor to generate a signature for.
-     * @return The canonical JNI type signature for this method.
-     */
-    protected static String getTypeSignatureStringForConstructor(Constructor<?> aConstructor) {
-        Class<?>[] arguments = aConstructor.getParameterTypes();
-        return getTypeSignatureInternal(arguments, Void.class);
-    }
-
-    public static String getTypeSignatureStringForMember(Member aMember) {
-        if (aMember instanceof Method) {
-            return getTypeSignatureStringForMethod((Method) aMember);
-        } else if (aMember instanceof Field) {
-            return getTypeSignatureStringForField((Field) aMember);
-        } else {
-            return getTypeSignatureStringForConstructor((Constructor<?>) aMember);
-        }
-    }
-
-    public static String getTypeSignatureStringForClass(Class<?> clazz) {
-        return clazz.getCanonicalName().replace('.', '/');
-    }
-
-    public static String getTypeSignatureString(Constructor<?> aConstructor) {
-        Class<?>[] arguments = aConstructor.getParameterTypes();
-        StringBuilder sb = new StringBuilder();
-        sb.append('(');
-
-        // For each argument, write its signature component to the buffer..
-        for (int i = 0; i < arguments.length; i++) {
-            writeTypeSignature(sb, arguments[i]);
+        if (type.isArray()) {
+            final String compName = type.getComponentType().getName();
+            if (NATIVE_ARRAY_TYPES.containsKey(compName)) {
+                return NATIVE_ARRAY_TYPES.get(compName) + "::LocalRef";
+            }
+            return "mozilla::jni::ObjectArray::LocalRef";
         }
 
-        // Constructors always return Void.
-        sb.append(")V");
-        return sb.toString();
+        if (type == String.class) {
+            return "mozilla::jni::String::LocalRef";
+        }
+
+        if (type == Class.class) {
+            // You're doing reflection on Java objects from inside C, returning Class objects
+            // to C, generating the corresponding code using this Java program. Really?!
+            return "mozilla::jni::ClassObject::LocalRef";
+        }
+
+        if (type == Throwable.class) {
+            return "mozilla::jni::Throwable::LocalRef";
+        }
+
+        return "mozilla::jni::Object::LocalRef";
     }
 
     /**
-     * Helper method used by getTypeSignatureStringForMethod to build the signature. Write the subsignature
-     * of a given type into the buffer.
+     * Get the JNI class descriptor corresponding to the provided type parameter.
      *
-     * @param sb The buffer to write into.
-     * @param c  The type of the element to write the subsignature of.
+     * @param type Class to determine the corresponding JNI descriptor for.
+     * @return Class descripor as a String
      */
-    private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
-        String name = Utils.getTypeSignatureStringForClass(c);
+    public static String getClassDescriptor(Class<?> type) {
+        final String name = type.getName().replace('.', '/');
 
-        // Determine if this is an array type and, if so, peel away the array operators..
-        int len = name.length();
-        while (name.endsWith("[]")) {
-            sb.append('[');
-            name = name.substring(0, len - 2);
-            len = len - 2;
+        if (CLASS_DESCRIPTORS.containsKey(name)) {
+            return CLASS_DESCRIPTORS.get(name);
         }
 
-        if (c.isArray()) {
-            c = c.getComponentType();
-        }
-
-        Class<?> containerClass = c.getDeclaringClass();
-        if (containerClass != null) {
-            // Is an inner class. Add the $ symbol.
-            final int lastSlash = name.lastIndexOf('/');
-            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
+        if (type.isArray()) {
+            // Array names are already in class descriptor form.
+            return name;
         }
 
-        // Look in the hashmap for the remainder...
-        if (sCanonicalSignatureParts.containsKey(name)) {
-            // It was a primitive type, so lookup was a success.
-            sb.append(sCanonicalSignatureParts.get(name));
-        } else {
-            // It was a reference type - generate.
-            sb.append('L');
-            sb.append(name);
-            sb.append(';');
-        }
+        return "L" + name + ';';
     }
 
     /**
-     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
-     * generating header files and method bodies.
+     * Get the JNI signaure for a member.
      *
-     * @param aArgumentTypes Argument types of the Java method being wrapped.
-     * @param aReturnType Return type of the Java method being wrapped.
-     * @param aCMethodName Name of the method to generate in the C++ class.
-     * @param aCClassName Name of the C++ class into which the method is declared.
-     * @return The C++ method implementation signature for the method described.
+     * @param member Member to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType,
-        String aCMethodName, String aCClassName, boolean aNarrowChars, boolean aCatchException) {
-        StringBuilder retBuffer = new StringBuilder();
-
-        retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
-        retBuffer.append(' ');
-        retBuffer.append(aCClassName);
-        retBuffer.append("::");
-        retBuffer.append(aCMethodName);
-        retBuffer.append('(');
-
-        // Write argument types...
-        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
-            retBuffer.append(" a");
-            // We, imaginatively, call our arguments a1, a2, a3...
-            // The only way to preserve the names from Java would be to parse the
-            // Java source, which would be computationally hard.
-            retBuffer.append(aT);
-            if (aT != aArgumentTypes.length - 1) {
-                retBuffer.append(", ");
-            }
-        }
-
-        if (aCatchException) {
-            if (aArgumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-            retBuffer.append("nsresult* aResult");
-        }
-
-        retBuffer.append(')');
-        return retBuffer.toString();
+    public static String getSignature(Member member) {
+        return member instanceof Field ?  getSignature((Field) member) :
+               member instanceof Method ? getSignature((Method) member) :
+                                          getSignature((Constructor<?>) member);
     }
 
     /**
-     * Produces a C method signature, sans semicolon, for the given Java Method. Useful for both
-     * generating header files and method bodies.
+     * Get the JNI signaure for a field.
      *
-     * @param aArgumentTypes Argument types of the Java method being wrapped.
-     * @param aArgumentAnnotations The annotations on the Java method arguments. Used to specify
-     *                             default values etc.
-     * @param aReturnType Return type of the Java method being wrapped.
-     * @param aCMethodName Name of the method to generate in the C++ class.
-     * @param aCClassName Name of the C++ class into which the method is declared.e
-     * @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
-     * @return The generated C++ header method signature for the method described.
+     * @param member Field to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType,
-        String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars, boolean aCatchException) {
-        StringBuilder retBuffer = new StringBuilder();
-
-        // Add the static keyword, if applicable.
-        if (aIsStaticStub) {
-            retBuffer.append("static ");
-        }
-
-        // Write return type..
-        retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
-        retBuffer.append(' ');
-        retBuffer.append(aCMethodName);
-        retBuffer.append('(');
+    public static String getSignature(Field member) {
+        return getClassDescriptor(member.getType());
+    }
 
-        // Write argument types...
-        for (int aT = 0; aT < aArgumentTypes.length; aT++) {
-            retBuffer.append(getCParameterType(aArgumentTypes[aT], aNarrowChars));
-            retBuffer.append(" a");
-            // We, imaginatively, call our arguments a1, a2, a3...
-            // The only way to preserve the names from Java would be to parse the
-            // Java source, which would be computationally hard.
-            retBuffer.append(aT);
-
-            // Append the default value, if there is one..
-            retBuffer.append(getDefaultValueString(aArgumentTypes[aT], aArgumentAnnotations[aT]));
-
-            if (aT != aArgumentTypes.length - 1) {
-                retBuffer.append(", ");
-            }
+    private static String getSignature(Class<?>[] args, Class<?> ret) {
+        final StringBuilder sig = new StringBuilder("(");
+        for (int i = 0; i < args.length; i++) {
+            sig.append(getClassDescriptor(args[i]));
         }
-
-        if (aCatchException) {
-            if (aArgumentTypes.length > 0) {
-                retBuffer.append(", ");
-            }
-            retBuffer.append("nsresult* aResult = nullptr");
-        }
-
-        retBuffer.append(')');
-        return retBuffer.toString();
+        return sig.append(')').append(getClassDescriptor(ret)).toString();
     }
 
     /**
-     * If the given Annotation[] contains an OptionalGeneratedParameter annotation then return a
-     * string assigning an argument of type aArgumentType to the default value for that type.
-     * Otherwise, return the empty string.
+     * Get the JNI signaure for a method.
      *
-     * @param aArgumentType        The type of the argument to consider.
-     * @param aArgumentAnnotations The annotations on the argument to consider.
-     * @return An appropriate string to append to the signature of this argument assigning it to a
-     *         default value (Or not, as applicable).
+     * @param member Method to get the signature for.
+     * @return JNI signature as a string
      */
-    public static String getDefaultValueString(Class<?> aArgumentType, Annotation[] aArgumentAnnotations) {
-        for (int i = 0; i < aArgumentAnnotations.length; i++) {
-            Class<? extends Annotation> annotationType = aArgumentAnnotations[i].annotationType();
-            final String annotationTypeName = annotationType.getName();
-            if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter")) {
-                return " = " + getDefaultParameterValueForType(aArgumentType);
-            }
-        }
-        return "";
+    public static String getSignature(Method member) {
+        return getSignature(member.getParameterTypes(), member.getReturnType());
     }
 
     /**
-     * Helper method to return an appropriate default parameter value for an argument of a given type.
-     * The lookup table contains values for primitive types and strings. All other object types default
-     * to null pointers.
+     * Get the JNI signaure for a constructor.
      *
-     * @param aArgumentType The parameter type for which a default value is desired.
-     * @return An appropriate string representation of the default value selected, for use in generated
-     *         C++ code.
+     * @param member Constructor to get the signature for.
+     * @return JNI signature as a string
      */
-    private static String getDefaultParameterValueForType(Class<?> aArgumentType) {
-        String typeName = aArgumentType.getCanonicalName();
-        if (sDefaultParameterValues.containsKey(typeName)) {
-            return sDefaultParameterValues.get(typeName);
-        } else if (isCharSequence(aArgumentType)) {
-            return "EmptyString()";
-        } else {
-            return "nullptr";
-        }
+    public static String getSignature(Constructor<?> member) {
+        return getSignature(member.getParameterTypes(), void.class);
     }
 
     /**
-     * Helper method that returns the number of reference types in the arguments of m.
+     * Get the C++ name for a member.
      *
-     * @param aArgs The method arguments to consider.
-     * @return How many of the arguments of m are nonprimitive.
+     * @param member Member to get the name for.
+     * @return JNI name as a string
      */
-    public static int enumerateReferenceArguments(Class<?>[] aArgs) {
-        int ret = 0;
-        for (int i = 0; i < aArgs.length; i++) {
-            String name = aArgs[i].getCanonicalName();
-            if (!sBasicCTypes.containsKey(name)) {
-                ret++;
-            }
-        }
-        return ret;
-    }
-
-    /**
-     * Helper method that returns true iff the given method has a string argument.
-     *
-     * @param m The method to consider.
-     * @return True if the given method has a string argument, false otherwise.
-     */
-    public static boolean hasStringArgument(Method m) {
-        Class<?>[] args = m.getParameterTypes();
-        for (int i = 0; i < args.length; i++) {
-            if (isCharSequence(args[i])) {
-                return true;
-            }
-        }
-        return false;
+    public static String getNativeName(Member member) {
+        final String name = getMemberName(member);
+        return name.substring(0, 1).toUpperCase() + name.substring(1);
     }
 
     /**
-     * Write the argument array assignment line for the given argument type. Does not support array
-     * types.
+     * Get the JNI name for a member.
      *
-     * @param type    Type of this argument according to the target Java method's signature.
-     * @param argName Wrapper function argument name corresponding to this argument.
+     * @param member Member to get the name for.
+     * @return JNI name as a string
      */
-    public static String getArrayArgumentMashallingLine(Class<?> type, String argName) {
-        StringBuilder sb = new StringBuilder();
-
-        String name = type.getCanonicalName();
-        if (sCanonicalSignatureParts.containsKey(name)) {
-            sb.append(sCanonicalSignatureParts.get(name).toLowerCase());
-            sb.append(" = ").append(argName).append(";\n");
-        } else {
-            if (isCharSequence(type)) {
-                sb.append("l = AndroidBridge::NewJavaString(env, ").append(argName).append(");\n");
-            } else {
-                sb.append("l = ").append(argName).append(";\n");
-            }
+    public static String getMemberName(Member member) {
+        if (member instanceof Constructor) {
+            return "<init>";
         }
-
-        return sb.toString();
-    }
-
-    /**
-     * Returns true if the type provided is an object type. Returns false otherwise
-     *
-     * @param aType The type to consider.
-     * @return true if the method provided is an object type, false otherwise.
-     */
-    public static boolean isObjectType(Class<?> aType) {
-        return !sBasicCTypes.containsKey(aType.getCanonicalName());
-    }
-
-    /**
-     * For a given Java class, get the name of the value in C++ which holds a reference to it.
-     *
-     * @param aClass Target Java class.
-     * @return The name of the C++ jclass entity referencing the given class.
-     */
-    public static String getClassReferenceName(Class<?> aClass) {
-        String className = aClass.getSimpleName();
-        return 'm' + className + "Class";
+        return member.getName();
     }
 
     /**
-     * Generate a line to get a global reference to the Java class given.
+     * Determine if a member is declared static.
      *
-     * @param aClass The target Java class.
-     * @return The generated code to populate the reference to the class.
+     * @param member The Member to check.
+     * @return true if the member is declared static, false otherwise.
      */
-    public static String getStartupLineForClass(Class<?> aClass) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("    ");
-        sb.append(getClassReferenceName(aClass));
-        sb.append(" = AndroidBridge::GetClassGlobalRef(env, \"");
-
-        String name = Utils.getTypeSignatureStringForClass(aClass);
-        Class<?> containerClass = aClass.getDeclaringClass();
-        if (containerClass != null) {
-            // Is an inner class. Add the $ symbol.
-            final int lastSlash = name.lastIndexOf('/');
-            name = name.substring(0, lastSlash) + '$' + name.substring(lastSlash+1);
-        }
-
-        sb.append(name);
-        sb.append("\");\n");
-        return sb.toString();
+    public static boolean isStatic(final Member member) {
+        return Modifier.isStatic(member.getModifiers());
     }
 
     /**
-     * Helper method to determine if this object implements CharSequence
-     * @param aClass Class to check for CharSequence-esqueness
-     * @return True if the given class implements CharSequence, false otherwise.
+     * Determine if a member is declared final.
+     *
+     * @param member The Member to check.
+     * @return true if the member is declared final, false otherwise.
      */
-    public static boolean isCharSequence(Class<?> aClass) {
-        if (aClass.getCanonicalName().equals("java.lang.CharSequence")) {
-            return true;
-        }
-        Class<?>[] interfaces = aClass.getInterfaces();
-        for (Class<?> c : interfaces) {
-            if (c.getCanonicalName().equals("java.lang.CharSequence")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Helper method to read the modifier bits of the given method to determine if it is static.
-     * @param aMember The Member to check.
-     * @return true of the method is declared static, false otherwise.
-     */
-    public static boolean isMemberStatic(Member aMember) {
-        int aMethodModifiers = aMember.getModifiers();
-        return Modifier.isStatic(aMethodModifiers);
-    }
-
-    /**
-     * Helper method to read the modifier bits of the given method to determine if it is static.
-     * @param aMember The Member to check.
-     * @return true of the method is declared static, false otherwise.
-     */
-    public static boolean isMemberFinal(Member aMember) {
-        int aMethodModifiers = aMember.getModifiers();
-        return Modifier.isFinal(aMethodModifiers);
+    public static boolean isFinal(final Member member) {
+        return Modifier.isFinal(member.getModifiers());
     }
 }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2488,17 +2488,17 @@ ContentParent::RecvGetIconForExtension(c
 bool
 ContentParent::RecvGetShowPasswordSetting(bool* showPassword)
 {
     // default behavior is to show the last password character
     *showPassword = true;
 #ifdef MOZ_WIDGET_ANDROID
     NS_ASSERTION(AndroidBridge::Bridge() != nullptr, "AndroidBridge is not available");
 
-    *showPassword = mozilla::widget::android::GeckoAppShell::GetShowPasswordSetting();
+    *showPassword = mozilla::widget::GeckoAppShell::GetShowPasswordSetting();
 #endif
     return true;
 }
 
 bool
 ContentParent::RecvFirstIdle()
 {
     // When the ContentChild goes idle, it sends us a FirstIdle message
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp
+++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp
@@ -19,35 +19,35 @@
 #include "nsThreadUtils.h"
 #include "nsAutoPtr.h"
 
 #include <jni.h>
 #include <string.h>
 
 using namespace mozilla;
 using namespace mozilla::gl;
-using namespace mozilla::widget::android::sdk;
+using namespace mozilla::widget::sdk;
 
 namespace mozilla {
 
-static MediaCodec* CreateDecoder(JNIEnv* aEnv, const char* aMimeType)
+static MediaCodec::LocalRef CreateDecoder(const char* aMimeType)
 {
   if (!aMimeType) {
     return nullptr;
   }
 
-  jobject decoder = MediaCodec::CreateDecoderByType(nsCString(aMimeType));
-
-  return new MediaCodec(decoder, aEnv);
+  MediaCodec::LocalRef codec;
+  NS_ENSURE_SUCCESS(MediaCodec::CreateDecoderByType(aMimeType, &codec), nullptr);
+  return codec;
 }
 
 class VideoDataDecoder : public MediaCodecDataDecoder {
 public:
   VideoDataDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
-                   MediaFormat* aFormat, MediaDataDecoderCallback* aCallback,
+                   MediaFormat::Param aFormat, MediaDataDecoderCallback* aCallback,
                    layers::ImageContainer* aImageContainer)
     : MediaCodecDataDecoder(MediaData::Type::VIDEO_DATA, aConfig.mime_type, aFormat, aCallback)
     , mImageContainer(aImageContainer)
     , mConfig(aConfig)
   {
 
   }
 
@@ -103,17 +103,17 @@ public:
     EGLImage eglImage = sEGLLibrary.fCreateImage(EGL_DISPLAY(), eglContext,
                                                  LOCAL_EGL_GL_TEXTURE_2D_KHR,
                                                  (EGLClientBuffer)tex, attribs);
     mGLContext->fDeleteTextures(1, &tex);
 
     return eglImage;
   }
 
-  virtual nsresult PostOutput(BufferInfo* aInfo, MediaFormat* aFormat, Microseconds aDuration) MOZ_OVERRIDE {
+  virtual nsresult PostOutput(BufferInfo::Param aInfo, MediaFormat::Param aFormat, Microseconds aDuration) MOZ_OVERRIDE {
     VideoInfo videoInfo;
     videoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
 
     EGLImage eglImage = CopySurface();
     if (!eglImage) {
       return NS_ERROR_FAILURE;
     }
 
@@ -138,23 +138,33 @@ public:
     data.mSync = eglSync;
     data.mOwns = true;
     data.mSize = gfx::IntSize(mConfig.display_width, mConfig.display_height);
     data.mOriginPos = gl::OriginPos::BottomLeft;
 
     layers::EGLImageImage* typedImg = static_cast<layers::EGLImageImage*>(img.get());
     typedImg->SetData(data);
 
-    bool isSync = !!(MediaCodec::getBUFFER_FLAG_SYNC_FRAME() & aInfo->getFlags());
+    nsresult rv;
+    int32_t flags;
+    NS_ENSURE_SUCCESS(rv = aInfo->Flags(&flags), rv);
+
+    bool isSync = !!(flags & MediaCodec::BUFFER_FLAG_SYNC_FRAME);
 
-    nsRefPtr<VideoData> v = VideoData::CreateFromImage(videoInfo, mImageContainer, aInfo->getOffset(),
-                                                       aInfo->getPresentationTimeUs(),
+    int32_t offset;
+    NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
+
+    int64_t presentationTimeUs;
+    NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
+
+    nsRefPtr<VideoData> v = VideoData::CreateFromImage(videoInfo, mImageContainer, offset,
+                                                       presentationTimeUs,
                                                        aDuration,
                                                        img, isSync,
-                                                       aInfo->getPresentationTimeUs(),
+                                                       presentationTimeUs,
                                                        gfx::IntRect(0, 0,
                                                          mConfig.display_width,
                                                          mConfig.display_height));
     mCallback->Output(v);
     return NS_OK;
   }
 
 protected:
@@ -169,129 +179,131 @@ protected:
 
   layers::ImageContainer* mImageContainer;
   const mp4_demuxer::VideoDecoderConfig& mConfig;
   RefPtr<AndroidSurfaceTexture> mSurfaceTexture;
   nsRefPtr<GLContext> mGLContext;
 };
 
 class AudioDataDecoder : public MediaCodecDataDecoder {
+private:
+  uint8_t csd0[2];
+
 public:
-  AudioDataDecoder(const char* aMimeType, MediaFormat* aFormat, MediaDataDecoderCallback* aCallback)
-  : MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aMimeType, aFormat, aCallback)
+  AudioDataDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig, MediaFormat::Param aFormat, MediaDataDecoderCallback* aCallback)
+    : MediaCodecDataDecoder(MediaData::Type::AUDIO_DATA, aConfig.mime_type, aFormat, aCallback)
   {
+    JNIEnv* env = GetJNIForThread();
+
+    jni::Object::LocalRef buffer(env);
+    NS_ENSURE_SUCCESS_VOID(aFormat->GetByteBuffer(NS_LITERAL_STRING("csd-0"), &buffer));
+
+    if (!buffer) {
+      csd0[0] = (*aConfig.audio_specific_config)[0];
+      csd0[1] = (*aConfig.audio_specific_config)[1];
+
+      buffer = jni::Object::LocalRef::Adopt(env, env->NewDirectByteBuffer(csd0, 2));
+      NS_ENSURE_SUCCESS_VOID(aFormat->SetByteBuffer(NS_LITERAL_STRING("csd-0"), buffer));
+    }
   }
 
-  nsresult Output(BufferInfo* aInfo, void* aBuffer, MediaFormat* aFormat, Microseconds aDuration) {
+  nsresult Output(BufferInfo::Param aInfo, void* aBuffer, MediaFormat::Param aFormat, Microseconds aDuration) {
     // The output on Android is always 16-bit signed
 
-    uint32_t numChannels = aFormat->GetInteger(NS_LITERAL_CSTRING("channel-count"));
-    uint32_t sampleRate = aFormat->GetInteger(NS_LITERAL_CSTRING("sample-rate"));
-    uint32_t numFrames = (aInfo->getSize() / numChannels) / 2;
+    nsresult rv;
+    int32_t numChannels;
+    NS_ENSURE_SUCCESS(rv =
+        aFormat->GetInteger(NS_LITERAL_STRING("channel-count"), &numChannels), rv);
+
+    int32_t sampleRate;
+    NS_ENSURE_SUCCESS(rv =
+        aFormat->GetInteger(NS_LITERAL_STRING("sample-rate"), &sampleRate), rv);
+
+    int32_t size;
+    NS_ENSURE_SUCCESS(rv = aInfo->Size(&size), rv);
 
-    AudioDataValue* audio = new AudioDataValue[aInfo->getSize()];
-    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), aInfo->getSize());
+    const int32_t numFrames = (size / numChannels) / 2;
+    AudioDataValue* audio = new AudioDataValue[size];
+    PodCopy(audio, static_cast<AudioDataValue*>(aBuffer), size);
 
-    nsRefPtr<AudioData> data = new AudioData(aInfo->getOffset(), aInfo->getPresentationTimeUs(),
+    int32_t offset;
+    NS_ENSURE_SUCCESS(rv = aInfo->Offset(&offset), rv);
+
+    int64_t presentationTimeUs;
+    NS_ENSURE_SUCCESS(rv = aInfo->PresentationTimeUs(&presentationTimeUs), rv);
+
+    nsRefPtr<AudioData> data = new AudioData(offset, presentationTimeUs,
                                              aDuration,
                                              numFrames,
                                              audio,
                                              numChannels,
                                              sampleRate);
     mCallback->Output(data);
     return NS_OK;
   }
 };
 
 
 bool AndroidDecoderModule::SupportsAudioMimeType(const char* aMimeType) {
-  JNIEnv* env = GetJNIForThread();
-  MediaCodec* decoder = CreateDecoder(env, aMimeType);
-  bool supports = (decoder != nullptr);
-  delete decoder;
-  return supports;
+  return static_cast<bool>(CreateDecoder(aMimeType));
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateVideoDecoder(
                                 const mp4_demuxer::VideoDecoderConfig& aConfig,
                                 layers::LayersBackend aLayersBackend,
                                 layers::ImageContainer* aImageContainer,
                                 MediaTaskQueue* aVideoTaskQueue,
                                 MediaDataDecoderCallback* aCallback)
 {
-  jobject jFormat = MediaFormat::CreateVideoFormat(nsCString(aConfig.mime_type),
-                                                   aConfig.display_width,
-                                                   aConfig.display_height);
+  MediaFormat::LocalRef format;
 
-  if (!jFormat) {
-    return nullptr;
-  }
-
-  MediaFormat* format = MediaFormat::Wrap(jFormat);
-
-  if (!format) {
-    return nullptr;
-  }
+  NS_ENSURE_SUCCESS(MediaFormat::CreateVideoFormat(
+      aConfig.mime_type,
+      aConfig.display_width,
+      aConfig.display_height,
+      &format), nullptr);
 
   nsRefPtr<MediaDataDecoder> decoder =
     new VideoDataDecoder(aConfig, format, aCallback, aImageContainer);
 
   return decoder.forget();
 }
 
 already_AddRefed<MediaDataDecoder>
 AndroidDecoderModule::CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
                                          MediaTaskQueue* aAudioTaskQueue,
                                          MediaDataDecoderCallback* aCallback)
 {
   MOZ_ASSERT(aConfig.bits_per_sample == 16, "We only handle 16-bit audio!");
 
-  jobject jFormat = MediaFormat::CreateAudioFormat(nsCString(aConfig.mime_type),
-                                                   aConfig.samples_per_second,
-                                                   aConfig.channel_count);
-
-  if (jFormat == nullptr)
-    return nullptr;
-
-  MediaFormat* format = MediaFormat::Wrap(jFormat);
-
-  if(format == nullptr)
-    return nullptr;
+  MediaFormat::LocalRef format;
 
-  JNIEnv* env = GetJNIForThread();
-
-  if (!format->GetByteBuffer(NS_LITERAL_CSTRING("csd-0"))) {
-    uint8_t* csd0 = new uint8_t[2];
-
-    csd0[0] = (*aConfig.audio_specific_config)[0];
-    csd0[1] = (*aConfig.audio_specific_config)[1];
-
-    jobject buffer = env->NewDirectByteBuffer(csd0, 2);
-    format->SetByteBuffer(NS_LITERAL_CSTRING("csd-0"), buffer);
-
-    env->DeleteLocalRef(buffer);
-  }
+  NS_ENSURE_SUCCESS(MediaFormat::CreateAudioFormat(
+      aConfig.mime_type,
+      aConfig.samples_per_second,
+      aConfig.channel_count,
+      &format), nullptr);
 
   nsRefPtr<MediaDataDecoder> decoder =
-    new AudioDataDecoder(aConfig.mime_type, format, aCallback);
+    new AudioDataDecoder(aConfig, format, aCallback);
 
   return decoder.forget();
 
 }
 
 
 nsresult AndroidDecoderModule::Shutdown()
 {
   return NS_OK;
 }
 
 MediaCodecDataDecoder::MediaCodecDataDecoder(MediaData::Type aType,
                                              const char* aMimeType,
-                                             MediaFormat* aFormat,
+                                             MediaFormat::Param aFormat,
                                              MediaDataDecoderCallback* aCallback)
   : mType(aType)
   , mMimeType(strdup(aMimeType))
   , mFormat(aFormat)
   , mCallback(aCallback)
   , mInputBuffers(nullptr)
   , mOutputBuffers(nullptr)
   , mMonitor("MediaCodecDataDecoder::mMonitor")
@@ -299,65 +311,38 @@ MediaCodecDataDecoder::MediaCodecDataDec
   , mDraining(false)
   , mStopping(false)
 {
 
 }
 
 MediaCodecDataDecoder::~MediaCodecDataDecoder()
 {
-  JNIEnv* env = GetJNIForThread();
-
   Shutdown();
-
-  if (mInputBuffers) {
-    env->DeleteGlobalRef(mInputBuffers);
-    mInputBuffers = nullptr;
-  }
-
-  if (mOutputBuffers) {
-    env->DeleteGlobalRef(mOutputBuffers);
-    mOutputBuffers = nullptr;
-  }
 }
 
 nsresult MediaCodecDataDecoder::Init()
 {
-  return InitDecoder();
+  return InitDecoder(nullptr);
 }
 
-nsresult MediaCodecDataDecoder::InitDecoder(jobject aSurface)
+nsresult MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
 {
-  JNIEnv* env = GetJNIForThread();
-  mDecoder = CreateDecoder(env, mMimeType);
+  mDecoder = CreateDecoder(mMimeType);
   if (!mDecoder) {
     mCallback->Error();
     return NS_ERROR_FAILURE;
   }
 
-  nsresult res;
-  mDecoder->Configure(mFormat->wrappedObject(), aSurface, nullptr, 0, &res);
-  if (NS_FAILED(res)) {
-    return res;
-  }
+  nsresult rv;
+  NS_ENSURE_SUCCESS(rv = mDecoder->Configure(mFormat, aSurface, nullptr, 0), rv);
+  NS_ENSURE_SUCCESS(rv = mDecoder->Start(), rv);
 
-  mDecoder->Start(&res);
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  res = ResetInputBuffers();
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  res = ResetOutputBuffers();
-  if (NS_FAILED(res)) {
-    return res;
-  }
+  NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv);
+  NS_ENSURE_SUCCESS(rv = ResetOutputBuffers(), rv);
 
   NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread),
                     NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop));
 
   return NS_OK;
 }
 
 // This is in usec, so that's 10ms
@@ -372,20 +357,20 @@ nsresult MediaCodecDataDecoder::InitDeco
 
 void MediaCodecDataDecoder::DecoderLoop()
 {
   bool outputDone = false;
 
   bool draining = false;
   bool waitingEOF = false;
 
-  JNIEnv* env = GetJNIForThread();
+  AutoLocalJNIFrame frame(GetJNIForThread(), 1);
   mp4_demuxer::MP4Sample* sample = nullptr;
 
-  nsAutoPtr<MediaFormat> outputFormat;
+  MediaFormat::LocalRef outputFormat(frame.GetEnv());
   nsresult res;
 
   for (;;) {
     {
       MonitorAutoLock lock(mMonitor);
       while (!mStopping && !mDraining && !mFlushing && mQueue.empty()) {
         if (mQueue.empty()) {
           // We could be waiting here forever if we don't signal that we need more input
@@ -415,80 +400,92 @@ void MediaCodecDataDecoder::DecoderLoop(
       if (!mQueue.empty()) {
         sample = mQueue.front();
       }
     }
 
     if (draining && !waitingEOF) {
       MOZ_ASSERT(!sample, "Shouldn't have a sample when pushing EOF frame");
 
-      int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res);
+      int32_t inputIndex;
+      res = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &inputIndex);
       HANDLE_DECODER_ERROR();
 
       if (inputIndex >= 0) {
-        mDecoder->QueueInputBuffer(inputIndex, 0, 0, 0, MediaCodec::getBUFFER_FLAG_END_OF_STREAM(), &res);
+        res = mDecoder->QueueInputBuffer(inputIndex, 0, 0, 0, MediaCodec::BUFFER_FLAG_END_OF_STREAM);
+        HANDLE_DECODER_ERROR();
+
         waitingEOF = true;
       }
     }
 
     if (sample) {
       // We have a sample, try to feed it to the decoder
-      int inputIndex = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &res);
+      int inputIndex;
+      res = mDecoder->DequeueInputBuffer(DECODER_TIMEOUT, &inputIndex);
       HANDLE_DECODER_ERROR();
 
       if (inputIndex >= 0) {
-        jobject buffer = env->GetObjectArrayElement(mInputBuffers, inputIndex);
-        void* directBuffer = env->GetDirectBufferAddress(buffer);
+        auto buffer = jni::Object::LocalRef::Adopt(
+            frame.GetEnv()->GetObjectArrayElement(mInputBuffers.Get(), inputIndex));
+        void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
 
-        // We're feeding this to the decoder, so remove it from the queue
-        mMonitor.Lock();
-        mQueue.pop();
-        mMonitor.Unlock();
+        MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->size,
+          "Decoder buffer is not large enough for sample");
 
-        MOZ_ASSERT(env->GetDirectBufferCapacity(buffer) >= sample->size,
-          "Decoder buffer is not large enough for sample");
+        {
+          // We're feeding this to the decoder, so remove it from the queue
+          MonitorAutoLock lock(mMonitor);
+          mQueue.pop();
+        }
 
         PodCopy((uint8_t*)directBuffer, sample->data, sample->size);
 
-        mDecoder->QueueInputBuffer(inputIndex, 0, sample->size, sample->composition_timestamp, 0, &res);
+        res = mDecoder->QueueInputBuffer(inputIndex, 0, sample->size,
+                                         sample->composition_timestamp, 0);
         HANDLE_DECODER_ERROR();
 
         mDurations.push(sample->duration);
-
         delete sample;
         sample = nullptr;
-
         outputDone = false;
-        env->DeleteLocalRef(buffer);
       }
     }
 
     if (!outputDone) {
-      BufferInfo bufferInfo;
+      BufferInfo::LocalRef bufferInfo;
+      res = BufferInfo::New(&bufferInfo);
+      HANDLE_DECODER_ERROR();
 
-      int outputStatus = mDecoder->DequeueOutputBuffer(bufferInfo.wrappedObject(), DECODER_TIMEOUT, &res);
+      int32_t outputStatus;
+      res = mDecoder->DequeueOutputBuffer(bufferInfo, DECODER_TIMEOUT, &outputStatus);
       HANDLE_DECODER_ERROR();
 
-      if (outputStatus == MediaCodec::getINFO_TRY_AGAIN_LATER()) {
+      if (outputStatus == MediaCodec::INFO_TRY_AGAIN_LATER) {
         // We might want to call mCallback->InputExhausted() here, but there seems to be
         // some possible bad interactions here with the threading
-      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_BUFFERS_CHANGED()) {
+      } else if (outputStatus == MediaCodec::INFO_OUTPUT_BUFFERS_CHANGED) {
         res = ResetOutputBuffers();
         HANDLE_DECODER_ERROR();
-      } else if (outputStatus == MediaCodec::getINFO_OUTPUT_FORMAT_CHANGED()) {
-        outputFormat = new MediaFormat(mDecoder->GetOutputFormat(), GetJNIForThread());
+      } else if (outputStatus == MediaCodec::INFO_OUTPUT_FORMAT_CHANGED) {
+        res = mDecoder->GetOutputFormat(ReturnTo(&outputFormat));
+        HANDLE_DECODER_ERROR();
       } else if (outputStatus < 0) {
         NS_WARNING("unknown error from decoder!");
         mCallback->Error();
 
         // Don't break here just in case it's recoverable. If it's not, others stuff will fail later and
         // we'll bail out.
       } else {
+        int32_t flags;
+        res = bufferInfo->Flags(&flags);
+        HANDLE_DECODER_ERROR();
+
         // We have a valid buffer index >= 0 here
-        if (bufferInfo.getFlags() & MediaCodec::getBUFFER_FLAG_END_OF_STREAM()) {
+        if (flags & MediaCodec::BUFFER_FLAG_END_OF_STREAM) {
           if (draining) {
             draining = false;
             waitingEOF = false;
 
             mMonitor.Lock();
             mDraining = false;
             mMonitor.Notify();
             mMonitor.Unlock();
@@ -506,42 +503,38 @@ void MediaCodecDataDecoder::DecoderLoop(
         MOZ_ASSERT(!mDurations.empty(), "Should have had a duration queued");
 
         Microseconds duration = 0;
         if (!mDurations.empty()) {
           duration = mDurations.front();
           mDurations.pop();
         }
 
-        jobject buffer = env->GetObjectArrayElement(mOutputBuffers, outputStatus);
+        auto buffer = jni::Object::LocalRef::Adopt(
+            frame.GetEnv()->GetObjectArrayElement(mOutputBuffers.Get(), outputStatus));
         if (buffer) {
           // The buffer will be null on Android L if we are decoding to a Surface
-          void* directBuffer = env->GetDirectBufferAddress(buffer);
-          Output(&bufferInfo, directBuffer, outputFormat, duration);
+          void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
+          Output(bufferInfo, directBuffer, outputFormat, duration);
         }
 
         // The Surface will be updated at this point (for video)
         mDecoder->ReleaseOutputBuffer(outputStatus, true);
 
-        PostOutput(&bufferInfo, outputFormat, duration);
-
-        if (buffer) {
-          env->DeleteLocalRef(buffer);
-        }
+        PostOutput(bufferInfo, outputFormat, duration);
       }
     }
   }
 
   Cleanup();
 
   // We're done
-  mMonitor.Lock();
+  MonitorAutoLock lock(mMonitor);
   mStopping = false;
   mMonitor.Notify();
-  mMonitor.Unlock();
 }
 
 void MediaCodecDataDecoder::ClearQueue()
 {
   mMonitor.AssertCurrentThreadOwns();
   while (!mQueue.empty()) {
     delete mQueue.front();
     mQueue.pop();
@@ -556,46 +549,22 @@ nsresult MediaCodecDataDecoder::Input(mp
   mQueue.push(aSample);
   lock.NotifyAll();
 
   return NS_OK;
 }
 
 nsresult MediaCodecDataDecoder::ResetInputBuffers()
 {
-  JNIEnv* env = GetJNIForThread();
-
-  if (mInputBuffers) {
-    env->DeleteGlobalRef(mInputBuffers);
-  }
-
-  nsresult res;
-  mInputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetInputBuffers(&res));
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  return NS_OK;
+  return mDecoder->GetInputBuffers(ReturnTo(&mInputBuffers));
 }
 
 nsresult MediaCodecDataDecoder::ResetOutputBuffers()
 {
-  JNIEnv* env = GetJNIForThread();
-
-  if (mOutputBuffers) {
-    env->DeleteGlobalRef(mOutputBuffers);
-  }
-
-  nsresult res;
-  mOutputBuffers = (jobjectArray) env->NewGlobalRef(mDecoder->GetOutputBuffers(&res));
-  if (NS_FAILED(res)) {
-    return res;
-  }
-
-  return NS_OK;
+  return mDecoder->GetOutputBuffers(ReturnTo(&mOutputBuffers));
 }
 
 nsresult MediaCodecDataDecoder::Flush() {
   MonitorAutoLock lock(mMonitor);
   mFlushing = true;
   lock.Notify();
 
   while (mFlushing) {
--- a/dom/media/fmp4/android/AndroidDecoderModule.h
+++ b/dom/media/fmp4/android/AndroidDecoderModule.h
@@ -12,28 +12,16 @@
 #include "mozilla/Monitor.h"
 
 #include <queue>
 
 namespace mozilla {
 
 typedef std::queue<mp4_demuxer::MP4Sample*> SampleQueue;
 
-namespace widget {
-namespace android {
-namespace sdk {
-  class MediaCodec;
-  class MediaFormat;
-  class ByteBuffer;
-}
-}
-}
-
-class MediaCodecDataDecoder;
-
 class AndroidDecoderModule : public PlatformDecoderModule {
 public:
   virtual nsresult Shutdown() MOZ_OVERRIDE;
 
   virtual already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
                      layers::LayersBackend aLayersBackend,
                      layers::ImageContainer* aImageContainer,
@@ -52,57 +40,57 @@ public:
   virtual bool SupportsAudioMimeType(const char* aMimeType) MOZ_OVERRIDE;
 };
 
 class MediaCodecDataDecoder : public MediaDataDecoder {
 public:
 
   MediaCodecDataDecoder(MediaData::Type aType,
                         const char* aMimeType,
-                        mozilla::widget::android::sdk::MediaFormat* aFormat,
+                        widget::sdk::MediaFormat::Param aFormat,
                         MediaDataDecoderCallback* aCallback);
 
   virtual ~MediaCodecDataDecoder();
 
   virtual nsresult Init() MOZ_OVERRIDE;
   virtual nsresult Flush() MOZ_OVERRIDE;
   virtual nsresult Drain() MOZ_OVERRIDE;
   virtual nsresult Shutdown() MOZ_OVERRIDE;
   virtual nsresult Input(mp4_demuxer::MP4Sample* aSample);
 
 protected:
   friend class AndroidDecoderModule;
 
   MediaData::Type mType;
 
   nsAutoPtr<char> mMimeType;
-  nsAutoPtr<mozilla::widget::android::sdk::MediaFormat> mFormat;
+  widget::sdk::MediaFormat::GlobalRef mFormat;
 
   MediaDataDecoderCallback* mCallback;
 
-  nsAutoPtr<mozilla::widget::android::sdk::MediaCodec> mDecoder;
+  widget::sdk::MediaCodec::GlobalRef mDecoder;
 
-  jobjectArray mInputBuffers;
-  jobjectArray mOutputBuffers;
+  jni::ObjectArray::GlobalRef mInputBuffers;
+  jni::ObjectArray::GlobalRef mOutputBuffers;
 
   nsCOMPtr<nsIThread> mThread;
 
   // Only these members are protected by mMonitor.
   Monitor mMonitor;
   bool mFlushing;
   bool mDraining;
   bool mStopping;
 
   SampleQueue mQueue;
   std::queue<Microseconds> mDurations;
 
-  virtual nsresult InitDecoder(jobject aSurface = nullptr);
+  virtual nsresult InitDecoder(widget::sdk::Surface::Param aSurface);
 
-  virtual nsresult Output(mozilla::widget::android::sdk::BufferInfo* aInfo, void* aBuffer, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
-  virtual nsresult PostOutput(mozilla::widget::android::sdk::BufferInfo* aInfo, mozilla::widget::android::sdk::MediaFormat* aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult Output(widget::sdk::BufferInfo::Param aInfo, void* aBuffer, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
+  virtual nsresult PostOutput(widget::sdk::BufferInfo::Param aInfo, widget::sdk::MediaFormat::Param aFormat, Microseconds aDuration) { return NS_OK; }
   virtual void Cleanup() {};
 
   nsresult ResetInputBuffers();
   nsresult ResetOutputBuffers();
 
   void DecoderLoop();
   virtual void ClearQueue();
 };
--- a/dom/plugins/base/android/ANPSystem.cpp
+++ b/dom/plugins/base/android/ANPSystem.cpp
@@ -45,30 +45,27 @@ anp_system_getApplicationDataDirectory(N
 }
 
 const char*
 anp_system_getApplicationDataDirectory()
 {
   return anp_system_getApplicationDataDirectory(nullptr);
 }
 
-jclass anp_system_loadJavaClass(NPP instance, const char* classNameStr)
+jclass anp_system_loadJavaClass(NPP instance, const char* className)
 {
   LOG("%s", __PRETTY_FUNCTION__);
 
   nsNPAPIPluginInstance* pinst = static_cast<nsNPAPIPluginInstance*>(instance->ndata);
   mozilla::PluginPRLibrary* lib = static_cast<mozilla::PluginPRLibrary*>(pinst->GetPlugin()->GetLibrary());
 
-  NS_ConvertUTF8toUTF16 className(classNameStr);
+  nsCString libName;
+  lib->GetLibraryPath(libName);
 
-  nsCString libNameUtf8;
-  lib->GetLibraryPath(libNameUtf8);
-  NS_ConvertUTF8toUTF16 libName(libNameUtf8);
-
-  return mozilla::widget::android::GeckoAppShell::LoadPluginClass(className, libName);
+  return mozilla::widget::GeckoAppShell::LoadPluginClass(className, libName).Forget();
 }
 
 void anp_system_setPowerState(NPP instance, ANPPowerState powerState)
 {
   nsNPAPIPluginInstance* pinst = nsNPAPIPluginInstance::GetFromNPP(instance);
 
   if (pinst) {
     pinst->SetWakeLock(powerState == kScreenOn_ANPPowerState);
--- a/dom/plugins/base/nsNPAPIPlugin.cpp
+++ b/dom/plugins/base/nsNPAPIPlugin.cpp
@@ -2264,22 +2264,21 @@ NPError
     case kSupportedDrawingModel_ANPGetValue: {
       LOG("get supported drawing model");
       uint32_t* bits = reinterpret_cast<uint32_t*>(result);
       *bits = kBitmap_ANPDrawingModel && kSurface_ANPDrawingModel;
       return NPERR_NO_ERROR;
     }
 
     case kJavaContext_ANPGetValue: {
-      jobject ret = mozilla::widget::android::GeckoAppShell::GetContext();
+      auto ret = widget::GeckoAppShell::GetContext();
       if (!ret)
         return NPERR_GENERIC_ERROR;
 
-      int32_t* i  = reinterpret_cast<int32_t*>(result);
-      *i = reinterpret_cast<int32_t>(ret);
+      *static_cast<jobject*>(result) = ret.Forget();
       return NPERR_NO_ERROR;
     }
 
     case kAudioTrackInterfaceV1_ANPGetValue: {
       LOG("get audio interface v1");
       ANPAudioTrackInterfaceV1 *i = (ANPAudioTrackInterfaceV1 *) result;
       InitAudioTrackInterfaceV1(i);
       return NPERR_NO_ERROR;
--- a/dom/plugins/base/nsNPAPIPluginInstance.cpp
+++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp
@@ -844,17 +844,17 @@ void nsNPAPIPluginInstance::NotifyFullSc
 
   if (RUNNING != mRunning || mFullScreen == aFullScreen)
     return;
 
   mFullScreen = aFullScreen;
   SendLifecycleEvent(this, mFullScreen ? kEnterFullScreen_ANPLifecycleAction : kExitFullScreen_ANPLifecycleAction);
 
   if (mFullScreen && mFullScreenOrientation != dom::eScreenOrientation_None) {
-    mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+    widget::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
   }
 }
 
 void nsNPAPIPluginInstance::NotifySize(nsIntSize size)
 {
   if (kOpenGL_ANPDrawingModel != GetANPDrawingModel() ||
       size == mCurrentSize)
     return;
@@ -901,21 +901,21 @@ void nsNPAPIPluginInstance::SetFullScree
 
   uint32_t oldOrientation = mFullScreenOrientation;
   mFullScreenOrientation = orientation;
 
   if (mFullScreen) {
     // We're already fullscreen so immediately apply the orientation change
 
     if (mFullScreenOrientation != dom::eScreenOrientation_None) {
-      mozilla::widget::android::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
+      widget::GeckoAppShell::LockScreenOrientation(mFullScreenOrientation);
     } else if (oldOrientation != dom::eScreenOrientation_None) {
       // We applied an orientation when we entered fullscreen, but
       // we don't want it anymore
-      mozilla::widget::android::GeckoAppShell::UnlockScreenOrientation();
+      widget::GeckoAppShell::UnlockScreenOrientation();
     }
   }
 }
 
 void nsNPAPIPluginInstance::PopPostedEvent(PluginEventRunnable* r)
 {
   mPostedEvents.RemoveElement(r);
 }
--- a/dom/plugins/base/nsPluginInstanceOwner.cpp
+++ b/dom/plugins/base/nsPluginInstanceOwner.cpp
@@ -1351,17 +1351,18 @@ bool nsPluginInstanceOwner::AddPluginVie
   return true;
 }
 
 void nsPluginInstanceOwner::RemovePluginView()
 {
   if (!mInstance || !mJavaView)
     return;
 
-  mozilla::widget::android::GeckoAppShell::RemovePluginView((jobject)mJavaView, mFullScreen);
+  widget::GeckoAppShell::RemovePluginView(
+      jni::Object::Ref::From(jobject(mJavaView)), mFullScreen);
   AndroidBridge::GetJNIEnv()->DeleteGlobalRef((jobject)mJavaView);
   mJavaView = nullptr;
 
   if (mFullScreen)
     sFullScreenInstance = nullptr;
 }
 
 void
--- a/dom/system/android/AndroidLocationProvider.cpp
+++ b/dom/system/android/AndroidLocationProvider.cpp
@@ -21,34 +21,34 @@ AndroidLocationProvider::AndroidLocation
 AndroidLocationProvider::~AndroidLocationProvider()
 {
     NS_IF_RELEASE(gLocationCallback);
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Startup()
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocation(true);
+    widget::GeckoAppShell::EnableLocation(true);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Watch(nsIGeolocationUpdate* aCallback)
 {
     NS_IF_RELEASE(gLocationCallback);
     gLocationCallback = aCallback;
     NS_IF_ADDREF(gLocationCallback);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::Shutdown()
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocation(false);
+    widget::GeckoAppShell::EnableLocation(false);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 AndroidLocationProvider::SetHighAccuracy(bool enable)
 {
-    mozilla::widget::android::GeckoAppShell::EnableLocationHighAccuracy(enable);
+    widget::GeckoAppShell::EnableLocationHighAccuracy(enable);
     return NS_OK;
 }
--- a/dom/system/android/nsHapticFeedback.cpp
+++ b/dom/system/android/nsHapticFeedback.cpp
@@ -9,11 +9,11 @@
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsHapticFeedback, nsIHapticFeedback)
 
 NS_IMETHODIMP
 nsHapticFeedback::PerformSimpleAction(int32_t aType)
 {
-    mozilla::widget::android::GeckoAppShell::PerformHapticFeedback(aType == LongPress);
+    widget::GeckoAppShell::PerformHapticFeedback(aType == LongPress);
     return NS_OK;
 }
--- a/gfx/gl/AndroidSurfaceTexture.cpp
+++ b/gfx/gl/AndroidSurfaceTexture.cpp
@@ -14,18 +14,19 @@
 #include "AndroidBridge.h"
 #include "nsThreadUtils.h"
 #include "mozilla/gfx/Matrix.h"
 #include "GeneratedJNIWrappers.h"
 #include "SurfaceTexture.h"
 #include "GLContext.h"
 
 using namespace mozilla;
-using namespace mozilla::widget::android;
-using namespace mozilla::widget::android::sdk;
+using namespace mozilla::jni;
+using namespace mozilla::widget;
+using namespace mozilla::widget::sdk;
 
 namespace mozilla {
 namespace gl {
 
 // UGH
 static std::map<int, AndroidSurfaceTexture*> sInstances;
 static int sNextID = 0;
 
@@ -98,19 +99,17 @@ AndroidSurfaceTexture::Attach(GLContext*
   }
 
   MOZ_ASSERT(aContext->IsOwningThreadCurrent(), "Trying to attach GLContext from different thread");
 
   mAttachedContext = aContext;
   mAttachedContext->MakeCurrent();
   aContext->fGenTextures(1, &mTexture);
 
-  nsresult res;
-  mSurfaceTexture->AttachToGLContext(mTexture, &res);
-  return res;
+  return mSurfaceTexture->AttachToGLContext(mTexture);
 }
 
 nsresult
 AndroidSurfaceTexture::Detach()
 {
   MonitorAutoLock lock(mMonitor);
 
   if (!IsDetachSupported() ||
@@ -131,81 +130,78 @@ AndroidSurfaceTexture::Detach()
 bool
 AndroidSurfaceTexture::Init(GLContext* aContext, GLuint aTexture)
 {
   if (!aTexture && !IsDetachSupported()) {
     // We have no texture and cannot initialize detached, bail out
     return false;
   }
 
-  nsresult res;
-  mSurfaceTexture = new SurfaceTexture(aTexture, &res);
-  if (NS_FAILED(res)) {
+  if (NS_WARN_IF(NS_FAILED(
+      SurfaceTexture::New(aTexture, ReturnTo(&mSurfaceTexture))))) {
     return false;
   }
 
   if (!aTexture) {
     mSurfaceTexture->DetachFromGLContext();
   }
 
   mAttachedContext = aContext;
 
-  mSurface = new Surface(mSurfaceTexture->wrappedObject(), &res);
-  if (NS_FAILED(res)) {
+  if (NS_WARN_IF(NS_FAILED(
+      Surface::New(mSurfaceTexture, ReturnTo(&mSurface))))) {
     return false;
   }
 
   mNativeWindow = AndroidNativeWindow::CreateFromSurface(GetJNIForThread(),
-                                                         mSurface->wrappedObject());
+                                                         mSurface.Get());
   MOZ_ASSERT(mNativeWindow, "Failed to create native window from surface");
 
   mID = ++sNextID;
   sInstances.insert(std::pair<int, AndroidSurfaceTexture*>(mID, this));
 
   return true;
 }
 
 AndroidSurfaceTexture::AndroidSurfaceTexture()
   : mTexture(0)
-  , mSurfaceTexture(nullptr)
-  , mSurface(nullptr)
+  , mSurfaceTexture()
+  , mSurface()
   , mMonitor("AndroidSurfaceTexture::mContextMonitor")
   , mAttachedContext(nullptr)
 {
 }
 
 AndroidSurfaceTexture::~AndroidSurfaceTexture()
 {
   sInstances.erase(mID);
 
   mFrameAvailableCallback = nullptr;
 
   if (mSurfaceTexture) {
-    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject());
+    GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
     mSurfaceTexture = nullptr;
   }
 }
 
 void
 AndroidSurfaceTexture::UpdateTexImage()
 {
   mSurfaceTexture->UpdateTexImage();
 }
 
 void
 AndroidSurfaceTexture::GetTransformMatrix(gfx::Matrix4x4& aMatrix)
 {
   JNIEnv* env = GetJNIForThread();
 
-  AutoLocalJNIFrame jniFrame(env);
-
-  jfloatArray jarray = env->NewFloatArray(16);
+  auto jarray = FloatArray::LocalRef::Adopt(env, env->NewFloatArray(16));
   mSurfaceTexture->GetTransformMatrix(jarray);
 
-  jfloat* array = env->GetFloatArrayElements(jarray, nullptr);
+  jfloat* array = env->GetFloatArrayElements(jarray.Get(), nullptr);
 
   aMatrix._11 = array[0];
   aMatrix._12 = array[1];
   aMatrix._13 = array[2];
   aMatrix._14 = array[3];
 
   aMatrix._21 = array[4];
   aMatrix._22 = array[5];
@@ -217,26 +213,26 @@ AndroidSurfaceTexture::GetTransformMatri
   aMatrix._33 = array[10];
   aMatrix._34 = array[11];
 
   aMatrix._41 = array[12];
   aMatrix._42 = array[13];
   aMatrix._43 = array[14];
   aMatrix._44 = array[15];
 
-  env->ReleaseFloatArrayElements(jarray, array, 0);
+  env->ReleaseFloatArrayElements(jarray.Get(), array, 0);
 }
 
 void
 AndroidSurfaceTexture::SetFrameAvailableCallback(nsIRunnable* aRunnable)
 {
   if (aRunnable) {
-    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject(), mID);
+    GeckoAppShell::RegisterSurfaceTextureFrameListener(mSurfaceTexture, mID);
   } else {
-     GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture->wrappedObject());
+     GeckoAppShell::UnregisterSurfaceTextureFrameListener(mSurfaceTexture);
   }
 
   mFrameAvailableCallback = aRunnable;
 }
 
 void
 AndroidSurfaceTexture::SetDefaultSize(mozilla::gfx::IntSize size)
 {
--- a/gfx/gl/AndroidSurfaceTexture.h
+++ b/gfx/gl/AndroidSurfaceTexture.h
@@ -82,26 +82,27 @@ public:
   // if the upstream callback is received on a different thread
   void SetFrameAvailableCallback(nsIRunnable* aRunnable);
 
   // Only should be called by AndroidJNI when we get a
   // callback from the underlying SurfaceTexture instance
   void NotifyFrameAvailable();
 
   GLuint Texture() { return mTexture; }
-  jobject JavaSurface() { return mSurface->wrappedObject(); }
+  const widget::sdk::Surface::Ref& JavaSurface() { return mSurface; }
+
 private:
   AndroidSurfaceTexture();
   ~AndroidSurfaceTexture();
 
   bool Init(GLContext* aContext, GLuint aTexture);
 
   GLuint mTexture;
-  nsAutoPtr<mozilla::widget::android::sdk::SurfaceTexture> mSurfaceTexture;
-  nsAutoPtr<mozilla::widget::android::sdk::Surface> mSurface;
+  widget::sdk::SurfaceTexture::GlobalRef mSurfaceTexture;
+  widget::sdk::Surface::GlobalRef mSurface;
 
   Monitor mMonitor;
   GLContext* mAttachedContext;
 
   RefPtr<AndroidNativeWindow> mNativeWindow;
   int mID;
   nsRefPtr<nsIRunnable> mFrameAvailableCallback;
 };
--- a/hal/android/AndroidGamepad.cpp
+++ b/hal/android/AndroidGamepad.cpp
@@ -9,19 +9,19 @@
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 StartMonitoringGamepadStatus()
 {
-  mozilla::widget::android::GeckoAppShell::StartMonitoringGamepad();
+  widget::GeckoAppShell::StartMonitoringGamepad();
 }
 
 void
 StopMonitoringGamepadStatus()
 {
-  mozilla::widget::android::GeckoAppShell::StopMonitoringGamepad();
+  widget::GeckoAppShell::StopMonitoringGamepad();
 }
 
 } // hal_impl
 } // mozilla
--- a/hal/android/AndroidHal.cpp
+++ b/hal/android/AndroidHal.cpp
@@ -9,17 +9,16 @@
 #include "AndroidBridge.h"
 #include "mozilla/dom/network/Constants.h"
 #include "mozilla/dom/ScreenOrientation.h"
 #include "nsIScreenManager.h"
 #include "nsServiceManagerUtils.h"
 
 using namespace mozilla::dom;
 using namespace mozilla::hal;
-using namespace mozilla::widget::android;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 Vibrate(const nsTArray<uint32_t> &pattern, const WindowIdentifier &)
 {
   // Ignore the WindowIdentifier parameter; it's here only because hal::Vibrate,
@@ -50,65 +49,65 @@ Vibrate(const nsTArray<uint32_t> &patter
   b->Vibrate(pattern);
 }
 
 void
 CancelVibrate(const WindowIdentifier &)
 {
   // Ignore WindowIdentifier parameter.
 
-  mozilla::widget::android::GeckoAppShell::CancelVibrate();
+  mozilla::widget::GeckoAppShell::CancelVibrate();
 }
 
 void
 EnableBatteryNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::EnableBatteryNotifications();
+  mozilla::widget::GeckoAppShell::EnableBatteryNotifications();
 }
 
 void
 DisableBatteryNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::DisableBatteryNotifications();
+  mozilla::widget::GeckoAppShell::DisableBatteryNotifications();
 }
 
 void
 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
   AndroidBridge::Bridge()->GetCurrentBatteryInformation(aBatteryInfo);
 }
 
 void
 EnableNetworkNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::EnableNetworkNotifications();
+  mozilla::widget::GeckoAppShell::EnableNetworkNotifications();
 }
 
 void
 DisableNetworkNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::DisableNetworkNotifications();
+  mozilla::widget::GeckoAppShell::DisableNetworkNotifications();
 }
 
 void
 GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
   AndroidBridge::Bridge()->GetCurrentNetworkInformation(aNetworkInfo);
 }
 
 void
 EnableScreenConfigurationNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::EnableScreenOrientationNotifications();
+  mozilla::widget::GeckoAppShell::EnableScreenOrientationNotifications();
 }
 
 void
 DisableScreenConfigurationNotifications()
 {
-  mozilla::widget::android::GeckoAppShell::DisableScreenOrientationNotifications();
+  mozilla::widget::GeckoAppShell::DisableScreenOrientationNotifications();
 }
 
 void
 GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
 {
   AndroidBridge* bridge = AndroidBridge::Bridge();
   if (!bridge) {
     return;
@@ -144,24 +143,24 @@ LockScreenOrientation(const ScreenOrient
     // The Android backend only supports these orientations.
     case eScreenOrientation_PortraitPrimary:
     case eScreenOrientation_PortraitSecondary:
     case eScreenOrientation_PortraitPrimary | eScreenOrientation_PortraitSecondary:
     case eScreenOrientation_LandscapePrimary:
     case eScreenOrientation_LandscapeSecondary:
     case eScreenOrientation_LandscapePrimary | eScreenOrientation_LandscapeSecondary:
     case eScreenOrientation_Default:
-      mozilla::widget::android::GeckoAppShell::LockScreenOrientation(aOrientation);
+      mozilla::widget::GeckoAppShell::LockScreenOrientation(aOrientation);
       return true;
     default:
       return false;
   }
 }
 
 void
 UnlockScreenOrientation()
 {
-  mozilla::widget::android::GeckoAppShell::UnlockScreenOrientation();
+  mozilla::widget::GeckoAppShell::UnlockScreenOrientation();
 }
 
 } // hal_impl
 } // mozilla
 
--- a/hal/android/AndroidSensor.cpp
+++ b/hal/android/AndroidSensor.cpp
@@ -8,18 +8,18 @@
 
 using namespace mozilla::hal;
 
 namespace mozilla {
 namespace hal_impl {
 
 void
 EnableSensorNotifications(SensorType aSensor) {
-  mozilla::widget::android::GeckoAppShell::EnableSensor(aSensor);
+  widget::GeckoAppShell::EnableSensor(aSensor);
 }
 
 void
 DisableSensorNotifications(SensorType aSensor) {
-  mozilla::widget::android::GeckoAppShell::DisableSensor(aSensor);
+  widget::GeckoAppShell::DisableSensor(aSensor);
 }
 
 } // hal_impl
 } // mozilla
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -105,17 +105,17 @@ MessagePump::Run(MessagePump::Delegate* 
     // equal priority, we sensitively rely on processing exactly one
     // Task per DoWorkRunnable XPCOM event.
 
 #ifdef MOZ_WIDGET_ANDROID
     // This processes messages in the Android Looper. Note that we only
     // get here if the normal Gecko event loop has been awoken above.
     // Bug 750713
     if (MOZ_LIKELY(AndroidBridge::HasEnv())) {
-        did_work |= mozilla::widget::android::GeckoAppShell::PumpMessageLoop();
+        did_work |= mozilla::widget::GeckoAppShell::PumpMessageLoop();
     }
 #endif
 
     did_work |= aDelegate->DoDelayedWork(&delayed_work_time_);
 
 if (did_work && delayed_work_time_.is_null()
 #ifdef MOZ_NUWA_PROCESS
     && (!IsNuwaReady() || !IsNuwaProcess())
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -250,17 +250,17 @@ public class GeckoAppShell
     static public final int LINK_TYPE_2G = 5;
     static public final int LINK_TYPE_3G = 6;
     static public final int LINK_TYPE_4G = 7;
 
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
     public static native void registerJavaUiThread();
-    public static native void nativeInit();
+    public static native void nativeInit(ClassLoader clsLoader);
 
     // helper methods
     public static native void onResume();
     public static void callObserver(String observerKey, String topic, String data) {
         sendEventToGecko(GeckoEvent.createCallObserverEvent(observerKey, topic, data));
     }
     public static void removeObserver(String observerKey) {
         sendEventToGecko(GeckoEvent.createRemoveObserverEvent(observerKey));
@@ -334,18 +334,18 @@ public class GeckoAppShell
                 idleMsg.obj = geckoHandler;
                 geckoHandler.sendMessageAtFrontOfQueue(idleMsg);
                 // Keep this IdleHandler
                 return true;
             }
         };
         Looper.myQueue().addIdleHandler(idleHandler);
 
-        // run gecko -- it will spawn its own thread
-        GeckoAppShell.nativeInit();
+        // Initialize AndroidBridge.
+        nativeInit(GeckoAppShell.class.getClassLoader());
 
         // First argument is the .apk path
         String combinedArgs = apkPath + " -greomni " + apkPath;
         if (args != null)
             combinedArgs += " " + args;
         if (url != null)
             combinedArgs += " -url " + url;
         if (type != null)
--- a/mobile/android/components/build/nsAndroidHistory.cpp
+++ b/mobile/android/components/build/nsAndroidHistory.cpp
@@ -72,17 +72,17 @@ nsAndroidHistory::RegisterVisitedCallbac
   nsTArray<Link*>* list = mListeners.Get(uriString);
   if (! list) {
     list = new nsTArray<Link*>();
     mListeners.Put(uriString, list);
   }
   list->AppendElement(aContent);
 
   if (AndroidBridge::HasEnv()) {
-    mozilla::widget::android::GeckoAppShell::CheckURIVisited(uriString);
+    widget::GeckoAppShell::CheckURIVisited(uriString);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHistory::UnregisterVisitedCallback(nsIURI *aURI, Link *aContent)
 {
@@ -198,17 +198,17 @@ void
 nsAndroidHistory::SaveVisitURI(nsIURI* aURI) {
   // Add the URI to our cache so we can take a fast path later
   AppendToRecentlyVisitedURIs(aURI);
 
   if (AndroidBridge::HasEnv()) {
     // Save this URI in our history
     nsAutoCString spec;
     (void)aURI->GetSpec(spec);
-    mozilla::widget::android::GeckoAppShell::MarkURIVisited(NS_ConvertUTF8toUTF16(spec));
+    widget::GeckoAppShell::MarkURIVisited(NS_ConvertUTF8toUTF16(spec));
   }
 
   // Finally, notify that we've been visited.
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   if (obsService) {
     obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nullptr);
   }
 }
@@ -283,17 +283,17 @@ nsAndroidHistory::SetURITitle(nsIURI *aU
     return NS_OK;
   }
 
   if (AndroidBridge::HasEnv()) {
     nsAutoCString uri;
     nsresult rv = aURI->GetSpec(uri);
     if (NS_FAILED(rv)) return rv;
     NS_ConvertUTF8toUTF16 uriString(uri);
-    mozilla::widget::android::GeckoAppShell::SetURITitle(uriString, aTitle);
+    widget::GeckoAppShell::SetURITitle(uriString, aTitle);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHistory::NotifyVisited(nsIURI *aURI)
 {
   if (aURI && sHistory) {
--- a/mobile/android/components/build/nsShellService.cpp
+++ b/mobile/android/components/build/nsShellService.cpp
@@ -3,28 +3,28 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsShellService.h"
 #include "nsString.h"
 
 #include "AndroidBridge.h"
 
-using namespace mozilla::widget::android;
+using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsShellService, nsIShellService)
 
 NS_IMETHODIMP
 nsShellService::SwitchTask()
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 nsShellService::CreateShortcut(const nsAString& aTitle, const nsAString& aURI,
                                 const nsAString& aIconData, const nsAString& aIntent)
 {
   if (!aTitle.Length() || !aURI.Length() || !aIconData.Length())
     return NS_ERROR_FAILURE;
 
-  mozilla::widget::android::GeckoAppShell::CreateShortcut(aTitle, aURI, aIconData);
+  widget::GeckoAppShell::CreateShortcut(aTitle, aURI, aIconData);
   return NS_OK;
 }
--- a/mozglue/android/jni-stubs.inc
+++ b/mozglue/android/jni-stubs.inc
@@ -72,26 +72,26 @@ Java_org_mozilla_gecko_GeckoAppShell_reg
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread", &f_Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread);
 #endif
 
 #ifdef JNI_STUBS
 
-typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t)(JNIEnv *, jclass);
+typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t)(JNIEnv *, jclass, jobject);
 static Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit;
 extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1) {
+Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv * arg0, jclass arg1, jobject arg2) {
     if (!f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit) {
         arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"),
                        "JNI Function called before it was loaded");
         return ;
     }
-     f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit(arg0, arg1);
+     f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit(arg0, arg1, arg2);
 }
 #endif
 
 #ifdef JNI_BINDINGS
   xul_dlsym("Java_org_mozilla_gecko_GeckoAppShell_nativeInit", &f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit);
 #endif
 
 #ifdef JNI_STUBS
--- a/netwerk/base/src/Tickler.cpp
+++ b/netwerk/base/src/Tickler.cpp
@@ -76,17 +76,17 @@ Tickler::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mTimer);
   MOZ_ASSERT(!mActive);
   MOZ_ASSERT(!mThread);
   MOZ_ASSERT(!mFD);
 
   if (AndroidBridge::HasEnv()) {
-      mozilla::widget::android::GeckoAppShell::EnableNetworkNotifications();
+      widget::GeckoAppShell::EnableNetworkNotifications();
   }
 
   mFD = PR_OpenUDPSocket(PR_AF_INET);
   if (!mFD)
     return NS_ERROR_FAILURE;
 
   // make sure new socket has a ttl of 1
   // failure is not fatal.
--- a/netwerk/protocol/device/CameraStreamImpl.cpp
+++ b/netwerk/protocol/device/CameraStreamImpl.cpp
@@ -85,14 +85,14 @@ bool CameraStreamImpl::Init(const nsCStr
 {
     mCallback = aCallback;
     mWidth = width;
     mHeight = height;
     return AndroidBridge::Bridge()->InitCamera(contentType, camera, &mWidth, &mHeight, &mFps);
 }
 
 void CameraStreamImpl::Close() {
-    mozilla::widget::android::GeckoAppShell::CloseCamera();
+    mozilla::widget::GeckoAppShell::CloseCamera();
     mCallback = nullptr;
 }
 
 } // namespace net
 } // namespace mozilla
--- a/netwerk/system/android/nsAndroidNetworkLinkService.cpp
+++ b/netwerk/system/android/nsAndroidNetworkLinkService.cpp
@@ -5,18 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAndroidNetworkLinkService.h"
 #include "nsServiceManagerUtils.h"
 #include "mozilla/Services.h"
 
 #include "AndroidBridge.h"
 
-using namespace mozilla::widget::android;
-
 NS_IMPL_ISUPPORTS(nsAndroidNetworkLinkService,
                   nsINetworkLinkService)
 
 nsAndroidNetworkLinkService::nsAndroidNetworkLinkService()
 {
 }
 
 nsAndroidNetworkLinkService::~nsAndroidNetworkLinkService()
@@ -28,36 +26,36 @@ nsAndroidNetworkLinkService::GetIsLinkUp
 {
   if (!mozilla::AndroidBridge::Bridge()) {
     // Fail soft here and assume a connection exists
     NS_WARNING("GetIsLinkUp is not supported without a bridge connection");
     *aIsUp = true;
     return NS_OK;
   }
 
-  *aIsUp = mozilla::widget::android::GeckoAppShell::IsNetworkLinkUp();
+  *aIsUp = mozilla::widget::GeckoAppShell::IsNetworkLinkUp();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidNetworkLinkService::GetLinkStatusKnown(bool *aIsKnown)
 {
   NS_ENSURE_TRUE(mozilla::AndroidBridge::Bridge(), NS_ERROR_NOT_IMPLEMENTED);
 
-  *aIsKnown = mozilla::widget::android::GeckoAppShell::IsNetworkLinkKnown();
+  *aIsKnown = mozilla::widget::GeckoAppShell::IsNetworkLinkKnown();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidNetworkLinkService::GetLinkType(uint32_t *aLinkType)
 {
   NS_ENSURE_ARG_POINTER(aLinkType);
 
   if (!mozilla::AndroidBridge::Bridge()) {
     // Fail soft here and assume a connection exists
     NS_WARNING("GetLinkType is not supported without a bridge connection");
     *aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
     return NS_OK;
   }
 
-  *aLinkType = mozilla::widget::android::GeckoAppShell::NetworkLinkType();
+  *aLinkType = mozilla::widget::GeckoAppShell::NetworkLinkType();
   return NS_OK;
 }
--- a/toolkit/components/alerts/nsAlertsService.cpp
+++ b/toolkit/components/alerts/nsAlertsService.cpp
@@ -6,17 +6,16 @@
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 #include "nsXULAppAPI.h"
 
 #include "nsAlertsService.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
-using namespace mozilla::widget::android;
 #else
 
 #include "nsXPCOM.h"
 #include "nsIServiceManager.h"
 #include "nsIDOMWindow.h"
 #include "nsPromiseFlatString.h"
 #include "nsToolkitCompsCID.h"
 
@@ -131,17 +130,17 @@ NS_IMETHODIMP nsAlertsService::CloseAler
 {
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     ContentChild* cpc = ContentChild::GetSingleton();
     cpc->SendCloseAlert(nsAutoString(aAlertName), IPC::Principal(aPrincipal));
     return NS_OK;
   }
 
 #ifdef MOZ_WIDGET_ANDROID
-  mozilla::widget::android::GeckoAppShell::CloseNotification(aAlertName);
+  widget::GeckoAppShell::CloseNotification(aAlertName);
   return NS_OK;
 #else
 
   // Try the system notification service.
   nsCOMPtr<nsIAlertsService> sysAlerts(do_GetService(NS_SYSTEMALERTSERVICE_CONTRACTID));
   if (sysAlerts) {
     return sysAlerts->CloseAlert(aAlertName, nullptr);
   }
@@ -152,26 +151,26 @@ NS_IMETHODIMP nsAlertsService::CloseAler
 
 
 NS_IMETHODIMP nsAlertsService::OnProgress(const nsAString & aAlertName,
                                           int64_t aProgress,
                                           int64_t aProgressMax,
                                           const nsAString & aAlertText)
 {
 #ifdef MOZ_WIDGET_ANDROID
-  mozilla::widget::android::GeckoAppShell::AlertsProgressListener_OnProgress(aAlertName,
-                                                                             aProgress, aProgressMax,
-                                                                             aAlertText);
+  widget::GeckoAppShell::AlertsProgressListener_OnProgress(aAlertName,
+                                                           aProgress, aProgressMax,
+                                                           aAlertText);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif // !MOZ_WIDGET_ANDROID
 }
 
 NS_IMETHODIMP nsAlertsService::OnCancel(const nsAString & aAlertName)
 {
 #ifdef MOZ_WIDGET_ANDROID
-  mozilla::widget::android::GeckoAppShell::CloseNotification(aAlertName);
+  widget::GeckoAppShell::CloseNotification(aAlertName);
   return NS_OK;
 #else
   return NS_ERROR_NOT_IMPLEMENTED;
 #endif // !MOZ_WIDGET_ANDROID
 }
--- a/toolkit/components/downloads/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
@@ -52,17 +52,16 @@
 #endif
 
 #ifdef XP_MACOSX
 #include <CoreFoundation/CoreFoundation.h>
 #endif
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
-using namespace mozilla::widget::android;
 #endif
 
 #ifdef MOZ_WIDGET_GTK
 #include <gtk/gtk.h>
 #endif
 
 using namespace mozilla;
 using mozilla::downloads::GenerateGUID;
@@ -2782,17 +2781,17 @@ nsDownload::SetState(DownloadState aStat
           if (addToRecentDocs) {
             nsCOMPtr<nsIMIMEInfo> mimeInfo;
             nsAutoCString contentType;
             GetMIMEInfo(getter_AddRefs(mimeInfo));
 
             if (mimeInfo)
               mimeInfo->GetMIMEType(contentType);
 
-            mozilla::widget::android::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(contentType));
+            mozilla::widget::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(contentType));
           }
 #else
           if (addToRecentDocs && !mPrivate) {
 #ifdef XP_WIN
             ::SHAddToRecentDocs(SHARD_PATHW, path.get());
 #elif defined(MOZ_WIDGET_GTK)
             GtkRecentManager* manager = gtk_recent_manager_get_default();
 
--- a/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
+++ b/toolkit/components/jsdownloads/src/DownloadPlatform.cpp
@@ -79,17 +79,17 @@ nsresult DownloadPlatform::DownloadDone(
   if (aTarget && NS_SUCCEEDED(aTarget->GetPath(path))) {
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_ANDROID)
     // On Windows and Gtk, add the download to the system's "recent documents"
     // list, with a pref to disable.
     {
       bool addToRecentDocs = Preferences::GetBool(PREF_BDM_ADDTORECENTDOCS);
 #ifdef MOZ_WIDGET_ANDROID
       if (addToRecentDocs) {
-        mozilla::widget::android::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(aContentType));
+        mozilla::widget::DownloadsIntegration::ScanMedia(path, NS_ConvertUTF8toUTF16(aContentType));
       }
 #else
       if (addToRecentDocs && !aIsPrivate) {
 #ifdef XP_WIN
         ::SHAddToRecentDocs(SHARD_PATHW, path.get());
 #elif defined(MOZ_WIDGET_GTK)
         GtkRecentManager* manager = gtk_recent_manager_get_default();
 
--- a/toolkit/components/parentalcontrols/nsParentalControlsServiceAndroid.cpp
+++ b/toolkit/components/parentalcontrols/nsParentalControlsServiceAndroid.cpp
@@ -9,17 +9,17 @@
 #include "nsIFile.h"
 
 NS_IMPL_ISUPPORTS(nsParentalControlsService, nsIParentalControlsService)
 
 nsParentalControlsService::nsParentalControlsService() :
   mEnabled(false)
 {
   if (mozilla::AndroidBridge::HasEnv()) {
-    mEnabled = mozilla::widget::android::RestrictedProfiles::IsUserRestricted();
+    mEnabled = mozilla::widget::RestrictedProfiles::IsUserRestricted();
   }
 }
 
 nsParentalControlsService::~nsParentalControlsService()
 {
 }
 
 NS_IMETHODIMP
@@ -85,15 +85,15 @@ nsParentalControlsService::IsAllowed(int
 
   if (mozilla::AndroidBridge::HasEnv()) {
     nsAutoCString url;
     if (aUri) {
       rv = aUri->GetSpec(url);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
-    *_retval = mozilla::widget::android::RestrictedProfiles::IsAllowed(aAction,
+    *_retval = mozilla::widget::RestrictedProfiles::IsAllowed(aAction,
                                                     NS_ConvertUTF8toUTF16(url));
     return rv;
   }
 
   return NS_ERROR_NOT_AVAILABLE;
 }
--- a/toolkit/xre/nsAndroidStartup.cpp
+++ b/toolkit/xre/nsAndroidStartup.cpp
@@ -70,14 +70,14 @@ GeckoStart(void *data, const nsXREAppDat
     }
     targs.AppendElement(static_cast<char *>(nullptr));
 
     int result = XRE_main(targs.Length() - 1, targs.Elements(), appData, 0);
 
     if (result)
         LOG("XRE_main returned %d", result);
 
-    mozilla::widget::android::GeckoAppShell::NotifyXreExit();
+    mozilla::widget::GeckoAppShell::NotifyXreExit();
 
     free(targs[0]);
     nsMemory::Free(data);
     return;
 }
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1696,17 +1696,17 @@ static nsresult LaunchChild(nsINativeApp
     gRestartArgc = 1;
     gRestartArgv[gRestartArgc] = nullptr;
 #endif
   }
 
   SaveToEnv("MOZ_LAUNCHED_CHILD=1");
 
 #if defined(MOZ_WIDGET_ANDROID)
-  mozilla::widget::android::GeckoAppShell::ScheduleRestart();
+  mozilla::widget::GeckoAppShell::ScheduleRestart();
 #else
 #if defined(XP_MACOSX)
   CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
   uint32_t restartMode = 0;
   restartMode = gRestartMode;
   LaunchChildMac(gRestartArgc, gRestartArgv, restartMode);
 #else
   nsCOMPtr<nsIFile> lf;
@@ -1834,17 +1834,17 @@ ProfileLockedDialog(nsIFile* aProfileDir
 
     nsCOMPtr<nsIPromptService> ps
       (do_GetService(NS_PROMPTSERVICE_CONTRACTID));
     NS_ENSURE_TRUE(ps, NS_ERROR_FAILURE);
 
     if (aUnlocker) {
       int32_t button;
 #ifdef MOZ_WIDGET_ANDROID
-      mozilla::widget::android::GeckoAppShell::KillAnyZombies();
+      mozilla::widget::GeckoAppShell::KillAnyZombies();
       button = 0;
 #else
       const uint32_t flags =
         (nsIPromptService::BUTTON_TITLE_IS_STRING *
          nsIPromptService::BUTTON_POS_0) +
         (nsIPromptService::BUTTON_TITLE_CANCEL *
          nsIPromptService::BUTTON_POS_1);
 
@@ -1863,17 +1863,17 @@ ProfileLockedDialog(nsIFile* aProfileDir
 
         SaveFileToEnv("XRE_PROFILE_PATH", aProfileDir);
         SaveFileToEnv("XRE_PROFILE_LOCAL_PATH", aProfileLocalDir);
 
         return LaunchChild(aNative);
       }
     } else {
 #ifdef MOZ_WIDGET_ANDROID
-      if (mozilla::widget::android::GeckoAppShell::UnlockProfile()) {
+      if (mozilla::widget::GeckoAppShell::UnlockProfile()) {
         return NS_LockProfilePath(aProfileDir, aProfileLocalDir, 
                                   nullptr, aResult);
       }
 #else
       rv = ps->Alert(nullptr, killTitle, killMessage);
       NS_ENSURE_SUCCESS_LOG(rv, rv);
 #endif
     }
--- a/tools/profiler/TableTicker.cpp
+++ b/tools/profiler/TableTicker.cpp
@@ -268,17 +268,17 @@ void BuildJavaThreadJSObject(JSStreamWri
             }
             break;
           }
           // the first time around, open the sample object and frames array
           if (firstRun) {
             firstRun = false;
 
             double sampleTime =
-              mozilla::widget::android::GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
+              mozilla::widget::GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
 
             b.BeginObject();
               b.NameValue("time", sampleTime);
 
               b.Name("frames");
               b.BeginArray();
           }
           // add a frame to the sample
@@ -345,21 +345,21 @@ void TableTicker::StreamJSObject(JSStrea
         if (os) {
           nsRefPtr<ProfileSaveEvent> pse = new ProfileSaveEvent(SubProcessCallback, &closure);
           os->NotifyObservers(pse, "profiler-subprocess", nullptr);
         }
       }
 
   #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
       if (ProfileJava()) {
-        mozilla::widget::android::GeckoJavaSampler::PauseJavaProfiling();
+        mozilla::widget::GeckoJavaSampler::PauseJavaProfiling();
 
         BuildJavaThreadJSObject(b);
 
-        mozilla::widget::android::GeckoJavaSampler::UnpauseJavaProfiling();
+        mozilla::widget::GeckoJavaSampler::UnpauseJavaProfiling();
       }
   #endif
 
       SetPaused(false);
     b.EndArray();
 
   b.EndObject();
 }
--- a/tools/profiler/platform.cpp
+++ b/tools/profiler/platform.cpp
@@ -22,17 +22,16 @@
 #include "nsProfilerStartParams.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "ProfilerMarkers.h"
 #include "nsXULAppAPI.h"
 
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   #include "AndroidBridge.h"
-  using namespace mozilla::widget::android;
 #endif
 
 mozilla::ThreadLocal<PseudoStack *> tlsPseudoStack;
 mozilla::ThreadLocal<TableTicker *> tlsTicker;
 mozilla::ThreadLocal<void *> tlsStackTop;
 // We need to track whether we've been initialized otherwise
 // we end up using tlsStack without initializing it.
 // Because tlsStack is totally opaque to us we can't reuse
@@ -784,17 +783,17 @@ void mozilla_sampler_start(int aProfileE
 
 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   if (t->ProfileJava()) {
     int javaInterval = aInterval;
     // Java sampling doesn't accuratly keep up with 1ms sampling
     if (javaInterval < 10) {
       aInterval = 10;
     }
-    mozilla::widget::android::GeckoJavaSampler::StartJavaProfiling(javaInterval, 1000);
+    mozilla::widget::GeckoJavaSampler::StartJavaProfiling(javaInterval, 1000);
   }
 #endif
 
   if (t->AddMainThreadIO()) {
     if (!sInterposeObserver) {
       // Lazily create IO interposer observer
       sInterposeObserver = new mozilla::ProfilerIOInterposeObserver();
     }
--- a/uriloader/exthandler/android/nsAndroidHandlerApp.cpp
+++ b/uriloader/exthandler/android/nsAndroidHandlerApp.cpp
@@ -1,17 +1,17 @@
 /* -*- Mode: c++; c-basic-offset: 2; tab-width: 20; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsAndroidHandlerApp.h"
 #include "AndroidBridge.h"
 
-using namespace mozilla::widget::android;
+using namespace mozilla;
 
 
 NS_IMPL_ISUPPORTS(nsAndroidHandlerApp, nsIHandlerApp, nsISharingHandlerApp)
 
 nsAndroidHandlerApp::nsAndroidHandlerApp(const nsAString& aName,
                                          const nsAString& aDescription,
                                          const nsAString& aPackageName,
                                          const nsAString& aClassName,
@@ -71,20 +71,21 @@ nsAndroidHandlerApp::Equals(nsIHandlerAp
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsAndroidHandlerApp::LaunchWithURI(nsIURI *aURI, nsIInterfaceRequestor *aWindowContext)
 {
   nsCString uriSpec;
   aURI->GetSpec(uriSpec);
-  return mozilla::widget::android::GeckoAppShell::OpenUriExternal
-    (NS_ConvertUTF8toUTF16(uriSpec), NS_ConvertUTF8toUTF16(mMimeType), mPackageName, mClassName, mAction) ?
-    NS_OK : NS_ERROR_FAILURE;
+  return widget::GeckoAppShell::OpenUriExternal(
+          uriSpec, mMimeType, mPackageName, mClassName,
+          mAction, EmptyString()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsAndroidHandlerApp::Share(const nsAString & data, const nsAString & title)
 {
-  return mozilla::widget::android::GeckoAppShell::OpenUriExternal(data, NS_ConvertUTF8toUTF16(mMimeType),
-                    mPackageName, mClassName, mAction) ? NS_OK : NS_ERROR_FAILURE;
+  return widget::GeckoAppShell::OpenUriExternal(
+          data, mMimeType, mPackageName, mClassName,
+          mAction, EmptyString()) ? NS_OK : NS_ERROR_FAILURE;
 }
 
--- a/uriloader/exthandler/android/nsExternalSharingAppService.cpp
+++ b/uriloader/exthandler/android/nsExternalSharingAppService.cpp
@@ -26,18 +26,18 @@ nsExternalSharingAppService::~nsExternal
 
 NS_IMETHODIMP
 nsExternalSharingAppService::ShareWithDefault(const nsAString & data,
                                               const nsAString & mime,
                                               const nsAString & title)
 {
   NS_NAMED_LITERAL_STRING(sendAction, "android.intent.action.SEND");
   const nsString emptyString = EmptyString();
-  return mozilla::widget::android::GeckoAppShell::OpenUriExternal(data,
-           mime, emptyString,emptyString, sendAction, title) ? NS_OK : NS_ERROR_FAILURE;
+  return widget::GeckoAppShell::OpenUriExternal(data,
+      mime, emptyString, emptyString, sendAction, title) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsExternalSharingAppService::GetSharingApps(const nsAString & aMIMEType,
                                             uint32_t *aLen,
                                             nsISharingHandlerApp ***aHandlers)
 {
   nsresult rv;
--- a/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
+++ b/uriloader/exthandler/android/nsMIMEInfoAndroid.cpp
@@ -5,17 +5,17 @@
 #include "nsMIMEInfoAndroid.h"
 #include "AndroidBridge.h"
 #include "nsAndroidHandlerApp.h"
 #include "nsArrayUtils.h"
 #include "nsISupportsUtils.h"
 #include "nsStringEnumerator.h"
 #include "nsNetUtil.h"
 
-using namespace mozilla::widget::android;
+using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsMIMEInfoAndroid, nsIMIMEInfo, nsIHandlerInfo)
 
 NS_IMETHODIMP
 nsMIMEInfoAndroid::LaunchDefaultWithFile(nsIFile* aFile)
 {
   return LaunchWithFile(aFile);
 }
@@ -31,17 +31,19 @@ nsMIMEInfoAndroid::LoadUriInternal(nsIUR
 
   nsAutoString mimeType;
   if (mType.Equals(uriScheme) || mType.Equals(uriSpec)) {
     mimeType = EmptyString();
   } else {
     mimeType = NS_ConvertUTF8toUTF16(mType);
   }
 
-  if (GeckoAppShell::OpenUriExternal(NS_ConvertUTF8toUTF16(uriSpec), mimeType)) {
+  if (widget::GeckoAppShell::OpenUriExternal(
+      NS_ConvertUTF8toUTF16(uriSpec), mimeType, EmptyString(),
+      EmptyString(), EmptyString(), EmptyString())) {
     return NS_OK;
   }
   return NS_ERROR_FAILURE;
 }
 
 bool
 nsMIMEInfoAndroid::GetMimeInfoForMimeType(const nsACString& aMimeType,
                                           nsMIMEInfoAndroid** aMimeInfo)
--- a/widget/android/APZCCallbackHandler.cpp
+++ b/widget/android/APZCCallbackHandler.cpp
@@ -22,21 +22,21 @@ using mozilla::layers::FrameMetrics;
 using mozilla::layers::ScrollableLayerGuid;
 
 namespace mozilla {
 namespace widget {
 namespace android {
 
 StaticRefPtr<APZCCallbackHandler> APZCCallbackHandler::sInstance;
 
-NativePanZoomController*
-APZCCallbackHandler::SetNativePanZoomController(jobject obj)
+NativePanZoomController::LocalRef
+APZCCallbackHandler::SetNativePanZoomController(NativePanZoomController::Param obj)
 {
-    NativePanZoomController* old = mNativePanZoomController;
-    mNativePanZoomController = NativePanZoomController::Wrap(obj);
+    NativePanZoomController::LocalRef old = mNativePanZoomController;
+    mNativePanZoomController = obj;
     return old;
 }
 
 void
 APZCCallbackHandler::NotifyDefaultPrevented(uint64_t aInputBlockId,
                                             bool aDefaultPrevented)
 {
     if (!AndroidBridge::IsJavaUiThread()) {
--- a/widget/android/APZCCallbackHandler.h
+++ b/widget/android/APZCCallbackHandler.h
@@ -2,47 +2,48 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef APZCCallbackHandler_h__
 #define APZCCallbackHandler_h__
 
 #include "mozilla/layers/GeckoContentController.h"
+#include "mozilla/StaticPtr.h"
 #include "mozilla/TimeStamp.h"
 #include "GeneratedJNIWrappers.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 namespace widget {
 namespace android {
 
 class APZCCallbackHandler MOZ_FINAL : public mozilla::layers::GeckoContentController
 {
 private:
     static StaticRefPtr<APZCCallbackHandler> sInstance;
-    NativePanZoomController* mNativePanZoomController;
+    NativePanZoomController::GlobalRef mNativePanZoomController;
 
 private:
     APZCCallbackHandler()
       : mNativePanZoomController(nullptr)
     {}
 
     nsIDOMWindowUtils* GetDOMWindowUtils();
 
 public:
     static APZCCallbackHandler* GetInstance() {
         if (sInstance.get() == nullptr) {
             sInstance = new APZCCallbackHandler();
         }
         return sInstance.get();
     }
 
-    NativePanZoomController* SetNativePanZoomController(jobject obj);
+    NativePanZoomController::LocalRef SetNativePanZoomController(NativePanZoomController::Param obj);
     void NotifyDefaultPrevented(uint64_t aInputBlockId, bool aDefaultPrevented);
 
 public: // GeckoContentController methods
     void RequestContentRepaint(const mozilla::layers::FrameMetrics& aFrameMetrics) MOZ_OVERRIDE;
     void AcknowledgeScrollUpdate(const mozilla::layers::FrameMetrics::ViewID& aScrollId,
                                  const uint32_t& aScrollGeneration) MOZ_OVERRIDE;
     void HandleDoubleTap(const mozilla::CSSPoint& aPoint, int32_t aModifiers,
                          const mozilla::layers::ScrollableLayerGuid& aGuid) MOZ_OVERRIDE;
--- a/widget/android/AndroidBridge.cpp
+++ b/widget/android/AndroidBridge.cpp
@@ -41,18 +41,19 @@
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
 #include "nsIHttpChannel.h"
 
 #include "MediaCodec.h"
 #include "SurfaceTexture.h"
 
 using namespace mozilla;
-using namespace mozilla::widget::android;
 using namespace mozilla::gfx;
+using namespace mozilla::jni;
+using namespace mozilla::widget;
 
 AndroidBridge* AndroidBridge::sBridge;
 pthread_t AndroidBridge::sJavaUiThread = -1;
 static unsigned sJavaEnvThreadIndex = 0;
 static jobject sGlobalContext = nullptr;
 static void JavaThreadDetachFunc(void *arg);
 
 // This is a dummy class that can be used in the template for android::sp
@@ -61,32 +62,39 @@ class AndroidRefable {
     void decStrong(void* thing) { }
 };
 
 // This isn't in AndroidBridge.h because including StrongPointer.h there is gross
 static android::sp<AndroidRefable> (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nullptr;
 
 jclass AndroidBridge::GetClassGlobalRef(JNIEnv* env, const char* className)
 {
-    jobject classLocalRef = env->FindClass(className);
-    if (!classLocalRef) {
-        ALOG(">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. Did ProGuard optimize away something it shouldn't have?",
+    // First try the default class loader.
+    auto classRef = ClassObject::LocalRef::Adopt(
+            env, env->FindClass(className));
+
+    if (!classRef && sBridge && sBridge->mClassLoader) {
+        // If the default class loader failed but we have an app class loader, try that.
+        // Clear the pending exception from failed FindClass call above.
+        env->ExceptionClear();
+        classRef = ClassObject::LocalRef::Adopt(env,
+                env->CallObjectMethod(sBridge->mClassLoader.Get(),
+                                      sBridge->mClassLoaderLoadClass,
+                                      Param<String>::Type(className, env).Get()));
+    }
+
+    if (!classRef) {
+        ALOG(">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. "
+             "Did ProGuard optimize away something it shouldn't have?",
              className);
         env->ExceptionDescribe();
         MOZ_CRASH();
     }
-    jobject classGlobalRef = env->NewGlobalRef(classLocalRef);
-    if (!classGlobalRef) {
-        env->ExceptionDescribe();
-        MOZ_CRASH();
-    }
-    // Local ref no longer necessary because we have a global ref.
-    env->DeleteLocalRef(classLocalRef);
-    classLocalRef = nullptr;
-    return static_cast<jclass>(classGlobalRef);
+
+    return ClassObject::GlobalRef(env, classRef).Forget();
 }
 
 jmethodID AndroidBridge::GetMethodID(JNIEnv* env, jclass jClass,
                               const char* methodName, const char* methodType)
 {
    jmethodID methodID = env->GetMethodID(jClass, methodName, methodType);
    if (!methodID) {
        ALOG(">>> FATAL JNI ERROR! GetMethodID(methodName=\"%s\", "
@@ -136,46 +144,51 @@ jfieldID AndroidBridge::GetStaticFieldID
              fieldName, fieldType);
         env->ExceptionDescribe();
         MOZ_CRASH();
     }
     return fieldID;
 }
 
 void
-AndroidBridge::ConstructBridge(JNIEnv *jEnv)
+AndroidBridge::ConstructBridge(JNIEnv *jEnv, Object::Param clsLoader)
 {
     /* NSS hack -- bionic doesn't handle recursive unloads correctly,
      * because library finalizer functions are called with the dynamic
      * linker lock still held.  This results in a deadlock when trying
      * to call dlclose() while we're already inside dlclose().
      * Conveniently, NSS has an env var that can prevent it from unloading.
      */
     putenv("NSS_DISABLE_UNLOAD=1");
 
     PR_NewThreadPrivateIndex(&sJavaEnvThreadIndex, JavaThreadDetachFunc);
 
     AndroidBridge *bridge = new AndroidBridge();
-    if (!bridge->Init(jEnv)) {
+    if (!bridge->Init(jEnv, clsLoader)) {
         delete bridge;
     }
     sBridge = bridge;
 }
 
 bool
-AndroidBridge::Init(JNIEnv *jEnv)
+AndroidBridge::Init(JNIEnv *jEnv, Object::Param clsLoader)
 {
     ALOG_BRIDGE("AndroidBridge::Init");
     jEnv->GetJavaVM(&mJavaVM);
     if (!mJavaVM) {
         MOZ_CRASH(); // Nothing we can do here
     }
 
     AutoLocalJNIFrame jniFrame(jEnv);
 
+    mClassLoader = Object::GlobalRef(jEnv, clsLoader);
+    mClassLoaderLoadClass = GetMethodID(
+            jEnv, jEnv->GetObjectClass(clsLoader.Get()),
+            "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
     mJNIEnv = nullptr;
     mThread = -1;
     mGLControllerObj = nullptr;
     mOpenedGraphicsLibraries = false;
     mHasNativeBitmapAccess = false;
     mHasNativeWindowAccess = false;
     mHasNativeWindowFallback = false;
 
@@ -223,24 +236,16 @@ AndroidBridge::Init(JNIEnv *jEnv)
 
     AutoJNIClass inputStream(jEnv, "java/io/InputStream");
     jInputStream = inputStream.getGlobalRef();
     jClose = inputStream.getMethod("close", "()V");
     jAvailable = inputStream.getMethod("available", "()I");
 
     InitAndroidJavaWrappers(jEnv);
 
-    if (mAPIVersion >= 16 /* Jelly Bean */) {
-        sdk::InitMediaCodecStubs(jEnv);
-    }
-
-    if (mAPIVersion >= 14 /* ICS */) {
-        sdk::InitSurfaceTextureStubs(jEnv);
-    }
-
     // jEnv should NOT be cached here by anything -- the jEnv here
     // is not valid for the real gecko main thread, which is set
     // at SetMainThread time.
 
     return true;
 }
 
 bool
@@ -429,138 +434,119 @@ getHandlersFromStringArray(JNIEnv *aJNIE
 bool
 AndroidBridge::GetHandlersForMimeType(const nsAString& aMimeType,
                                       nsIMutableArray *aHandlersArray,
                                       nsIHandlerApp **aDefaultApp,
                                       const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForMimeType");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobjectArray arr =
-      mozilla::widget::android::GeckoAppShell::GetHandlersForMimeTypeWrapper(aMimeType, aAction);
+    auto arr = GeckoAppShell::GetHandlersForMimeTypeWrapper(aMimeType, aAction);
     if (!arr)
         return false;
 
-    jsize len = env->GetArrayLength(arr);
+    JNIEnv* const env = arr.Env();
+    jsize len = env->GetArrayLength(arr.Get());
 
     if (!aHandlersArray)
         return len > 0;
 
-    getHandlersFromStringArray(env, arr, len, aHandlersArray,
+    getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
                                aDefaultApp, aAction,
                                NS_ConvertUTF16toUTF8(aMimeType));
     return true;
 }
 
 bool
 AndroidBridge::GetHandlersForURL(const nsAString& aURL,
                                  nsIMutableArray* aHandlersArray,
                                  nsIHandlerApp **aDefaultApp,
                                  const nsAString& aAction)
 {
     ALOG_BRIDGE("AndroidBridge::GetHandlersForURL");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobjectArray arr = mozilla::widget::android::GeckoAppShell::GetHandlersForURLWrapper(aURL, aAction);
+    auto arr = GeckoAppShell::GetHandlersForURLWrapper(aURL, aAction);
     if (!arr)
         return false;
 
-    jsize len = env->GetArrayLength(arr);
+    JNIEnv* const env = arr.Env();
+    jsize len = env->GetArrayLength(arr.Get());
 
     if (!aHandlersArray)
         return len > 0;
 
-    getHandlersFromStringArray(env, arr, len, aHandlersArray,
+    getHandlersFromStringArray(env, arr.Get(), len, aHandlersArray,
                                aDefaultApp, aAction);
     return true;
 }
 
 void
 AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& aMimeType)
 {
     ALOG_BRIDGE("AndroidBridge::GetMimeTypeFromExtensions");
 
-    JNIEnv *env = GetJNIEnv();
+    auto jstrType = GeckoAppShell::GetMimeTypeFromExtensionsWrapper(aFileExt);
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring jstrType = mozilla::widget::android::GeckoAppShell::GetMimeTypeFromExtensionsWrapper
-                                                                (NS_ConvertUTF8toUTF16(aFileExt));
-    if (!jstrType) {
-        return;
+    if (jstrType) {
+        aMimeType = jstrType;
     }
-    nsJNIString jniStr(jstrType, env);
-    CopyUTF16toUTF8(jniStr.get(), aMimeType);
 }
 
 void
 AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& aFileExt)
 {
     ALOG_BRIDGE("AndroidBridge::GetExtensionFromMimeType");
 
-    JNIEnv *env = GetJNIEnv();
+    auto jstrExt = GeckoAppShell::GetExtensionFromMimeTypeWrapper(aMimeType);
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring jstrExt = mozilla::widget::android::GeckoAppShell::GetExtensionFromMimeTypeWrapper
-                                                             (NS_ConvertUTF8toUTF16(aMimeType));
-    if (!jstrExt) {
-        return;
+    if (jstrExt) {
+        aFileExt = nsCString(jstrExt);
     }
-    nsJNIString jniStr(jstrExt, env);
-    CopyUTF16toUTF8(jniStr.get(), aFileExt);
 }
 
 bool
 AndroidBridge::GetClipboardText(nsAString& aText)
 {
     ALOG_BRIDGE("AndroidBridge::GetClipboardText");
 
-    JNIEnv *env = GetJNIEnv();
+    auto text = Clipboard::GetClipboardTextWrapper();
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring result = Clipboard::GetClipboardTextWrapper();
-    if (!result)
-        return false;
-
-    nsJNIString jniStr(result, env);
-    aText.Assign(jniStr);
-    return true;
+    if (text) {
+        aText = nsString(text);
+    }
+    return !!text;
 }
 
 void
 AndroidBridge::ShowAlertNotification(const nsAString& aImageUrl,
                                      const nsAString& aAlertTitle,
                                      const nsAString& aAlertText,
                                      const nsAString& aAlertCookie,
                                      nsIObserver *aAlertListener,
                                      const nsAString& aAlertName)
 {
     if (nsAppShell::gAppShell && aAlertListener) {
         // This will remove any observers already registered for this id
         nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeAddObserver(aAlertName, aAlertListener));
     }
 
-    mozilla::widget::android::GeckoAppShell::ShowAlertNotificationWrapper
+    GeckoAppShell::ShowAlertNotificationWrapper
            (aImageUrl, aAlertTitle, aAlertText, aAlertCookie, aAlertName);
 }
 
 int
 AndroidBridge::GetDPI()
 {
     static int sDPI = 0;
     if (sDPI)
         return sDPI;
 
     const int DEFAULT_DPI = 160;
 
-    sDPI = mozilla::widget::android::GeckoAppShell::GetDpiWrapper();
+    sDPI = GeckoAppShell::GetDpiWrapper();
     if (!sDPI) {
         return DEFAULT_DPI;
     }
 
     return sDPI;
 }
 
 int
@@ -570,17 +556,17 @@ AndroidBridge::GetScreenDepth()
 
     static int sDepth = 0;
     if (sDepth)
         return sDepth;
 
     const int DEFAULT_DEPTH = 16;
 
     if (HasEnv()) {
-        sDepth = mozilla::widget::android::GeckoAppShell::GetScreenDepthWrapper();
+        sDepth = GeckoAppShell::GetScreenDepthWrapper();
     }
     if (!sDepth)
         return DEFAULT_DEPTH;
 
     return sDepth;
 }
 void
 AndroidBridge::Vibrate(const nsTArray<uint32_t>& aPattern)
@@ -588,35 +574,34 @@ AndroidBridge::Vibrate(const nsTArray<ui
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
 
     uint32_t len = aPattern.Length();
     if (!len) {
         ALOG_BRIDGE("  invalid 0-length array");
         return;
     }
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
     // It's clear if this worth special-casing, but it creates less
     // java junk, so dodges the GC.
     if (len == 1) {
         jlong d = aPattern[0];
         if (d < 0) {
             ALOG_BRIDGE("  invalid vibration duration < 0");
             return;
         }
-        mozilla::widget::android::GeckoAppShell::Vibrate1(d);
+        GeckoAppShell::Vibrate1(d);
         return;
     }
 
     // First element of the array vibrate() expects is how long to wait
     // *before* vibrating.  For us, this is always 0.
 
+    JNIEnv *env = GetJNIEnv();
+    AutoLocalJNIFrame jniFrame(env, 1);
+
     jlongArray array = env->NewLongArray(len + 1);
     if (!array) {
         ALOG_BRIDGE("  failed to allocate array");
         return;
     }
 
     jlong* elts = env->GetLongArrayElements(array, nullptr);
     elts[0] = 0;
@@ -626,143 +611,126 @@ AndroidBridge::Vibrate(const nsTArray<ui
             ALOG_BRIDGE("  invalid vibration duration < 0");
             env->ReleaseLongArrayElements(array, elts, JNI_ABORT);
             return;
         }
         elts[i + 1] = d;
     }
     env->ReleaseLongArrayElements(array, elts, 0);
 
-    mozilla::widget::android::GeckoAppShell::VibrateA(array, -1/*don't repeat*/);
+    GeckoAppShell::VibrateA(LongArray::Ref::From(array), -1 /* don't repeat */);
 }
 
 void
 AndroidBridge::GetSystemColors(AndroidSystemColors *aColors)
 {
 
     NS_ASSERTION(aColors != nullptr, "AndroidBridge::GetSystemColors: aColors is null!");
     if (!aColors)
         return;
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jintArray arr = mozilla::widget::android::GeckoAppShell::GetSystemColoursWrapper();
+    auto arr = GeckoAppShell::GetSystemColoursWrapper();
     if (!arr)
         return;
 
-    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
-    jint *elements = env->GetIntArrayElements(arr, 0);
+    JNIEnv* const env = arr.Env();
+    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
+    jint *elements = env->GetIntArrayElements(arr.Get(), 0);
 
     uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
     if (len < colorsCount)
         colorsCount = len;
 
     // Convert Android colors to nscolor by switching R and B in the ARGB 32 bit value
     nscolor *colors = (nscolor*)aColors;
 
     for (uint32_t i = 0; i < colorsCount; i++) {
         uint32_t androidColor = static_cast<uint32_t>(elements[i]);
         uint8_t r = (androidColor & 0x00ff0000) >> 16;
         uint8_t b = (androidColor & 0x000000ff);
         colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
     }
 
-    env->ReleaseIntArrayElements(arr, elements, 0);
+    env->ReleaseIntArrayElements(arr.Get(), elements, 0);
 }
 
 void
 AndroidBridge::GetIconForExtension(const nsACString& aFileExt, uint32_t aIconSize, uint8_t * const aBuf)
 {
     ALOG_BRIDGE("AndroidBridge::GetIconForExtension");
     NS_ASSERTION(aBuf != nullptr, "AndroidBridge::GetIconForExtension: aBuf is null!");
     if (!aBuf)
         return;
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jbyteArray arr = mozilla::widget::android::GeckoAppShell::GetIconForExtensionWrapper
+    auto arr = GeckoAppShell::GetIconForExtensionWrapper
                                              (NS_ConvertUTF8toUTF16(aFileExt), aIconSize);
 
     NS_ASSERTION(arr != nullptr, "AndroidBridge::GetIconForExtension: Returned pixels array is null!");
     if (!arr)
         return;
 
-    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr));
-    jbyte *elements = env->GetByteArrayElements(arr, 0);
+    JNIEnv* const env = arr.Env();
+    uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
+    jbyte *elements = env->GetByteArrayElements(arr.Get(), 0);
 
     uint32_t bufSize = aIconSize * aIconSize * 4;
     NS_ASSERTION(len == bufSize, "AndroidBridge::GetIconForExtension: Pixels array is incomplete!");
     if (len == bufSize)
         memcpy(aBuf, elements, bufSize);
 
-    env->ReleaseByteArrayElements(arr, elements, 0);
+    env->ReleaseByteArrayElements(arr.Get(), elements, 0);
 }
 
 void
-AndroidBridge::SetLayerClient(JNIEnv* env, jobject jobj)
+AndroidBridge::SetLayerClient(GeckoLayerClient::Param jobj)
 {
     // if resetting is true, that means Android destroyed our GeckoApp activity
     // and we had to recreate it, but all the Gecko-side things were not destroyed.
     // We therefore need to link up the new java objects to Gecko, and that's what
     // we do here.
     bool resetting = (mLayerClient != nullptr);
 
-    if (resetting) {
-        // clear out the old layer client
-        delete mLayerClient;
-        mLayerClient = nullptr;
-    }
-
-    mLayerClient = mozilla::widget::android::GeckoLayerClient::Wrap(jobj);
+    mLayerClient = jobj;
 
     if (resetting) {
         // since we are re-linking the new java objects to Gecko, we need to get
         // the viewport from the compositor (since the Java copy was thrown away)
         // and we do that by setting the first-paint flag.
         nsWindow::ForceIsFirstPaint();
     }
 }
 
 void
 AndroidBridge::RegisterCompositor(JNIEnv *env)
 {
-    if (mGLControllerObj != nullptr && !mGLControllerObj->isNull()) {
+    if (mGLControllerObj != nullptr) {
         // we already have this set up, no need to do it again
         return;
     }
 
-    jobject glController = LayerView::RegisterCompositorWrapper();
-    if (!glController) {
-        return;
-    }
-
-    mGLControllerObj = GLController::Wrap(glController);
+    mGLControllerObj = GLController::LocalRef(
+            LayerView::RegisterCompositorWrapper());
 }
 
 EGLSurface
 AndroidBridge::CreateEGLSurfaceForCompositor()
 {
     if (!jEGLSurfacePointerField) {
         return nullptr;
     }
     MOZ_ASSERT(mGLControllerObj, "AndroidBridge::CreateEGLSurfaceForCompositor called with a null GL controller ref");
 
-    JNIEnv* env = GetJNIForThread(); // called on the compositor thread
+    auto eglSurface = mGLControllerObj->CreateEGLSurfaceForCompositorWrapper();
+    if (!eglSurface) {
+        return nullptr;
+    }
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobject eglSurface = mGLControllerObj->CreateEGLSurfaceForCompositorWrapper();
-    if (!eglSurface)
-        return nullptr;
-
-    EGLSurface ret = reinterpret_cast<EGLSurface>(env->GetIntField(eglSurface, jEGLSurfacePointerField));
-    return ret;
+    JNIEnv* const env = GetJNIForThread(); // called on the compositor thread
+    return reinterpret_cast<EGLSurface>(
+            env->GetIntField(eglSurface.Get(), jEGLSurfacePointerField));
 }
 
 bool
 AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, int32_t* aInt, JNIEnv* jEnv /* = nullptr */)
 {
     ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName);
 
     if (!jEnv) {
@@ -1002,72 +970,67 @@ AndroidBridge::ValidateBitmap(jobject bi
         return false;
 
     return true;
 }
 
 bool
 AndroidBridge::InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps)
 {
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jintArray arr = mozilla::widget::android::GeckoAppShell::InitCameraWrapper
+    auto arr = GeckoAppShell::InitCameraWrapper
       (NS_ConvertUTF8toUTF16(contentType), (int32_t) camera, (int32_t) *width, (int32_t) *height);
 
     if (!arr)
         return false;
 
-    jint *elements = env->GetIntArrayElements(arr, 0);
+    JNIEnv* const env = arr.Env();
+    jint *elements = env->GetIntArrayElements(arr.Get(), 0);
 
     *width = elements[1];
     *height = elements[2];
     *fps = elements[3];
 
     bool res = elements[0] == 1;
 
-    env->ReleaseIntArrayElements(arr, elements, 0);
+    env->ReleaseIntArrayElements(arr.Get(), elements, 0);
 
     return res;
 }
 
 void
 AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
 {
     ALOG_BRIDGE("AndroidBridge::GetCurrentBatteryInformation");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
     // To prevent calling too many methods through JNI, the Java method returns
     // an array of double even if we actually want a double and a boolean.
-    jdoubleArray arr = mozilla::widget::android::GeckoAppShell::GetCurrentBatteryInformationWrapper();
-    if (!arr || env->GetArrayLength(arr) != 3) {
+    auto arr = GeckoAppShell::GetCurrentBatteryInformationWrapper();
+
+    JNIEnv* const env = arr.Env();
+    if (!arr || env->GetArrayLength(arr.Get()) != 3) {
         return;
     }
 
-    jdouble* info = env->GetDoubleArrayElements(arr, 0);
+    jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
 
     aBatteryInfo->level() = info[0];
     aBatteryInfo->charging() = info[1] == 1.0f;
     aBatteryInfo->remainingTime() = info[2];
 
-    env->ReleaseDoubleArrayElements(arr, info, 0);
+    env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
 }
 
 void
 AndroidBridge::HandleGeckoMessage(JSContext* cx, JS::HandleObject object)
 {
     ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
 
     JNIEnv* const env = GetJNIEnv();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    const jobject message =
-        mozilla::widget::CreateNativeJSContainer(env, cx, object);
+    auto message = Object::LocalRef::Adopt(env,
+        mozilla::widget::CreateNativeJSContainer(env, cx, object));
     GeckoAppShell::HandleGeckoMessageWrapper(message);
 }
 
 nsresult
 AndroidBridge::GetSegmentInfoForText(const nsAString& aText,
                                      nsIMobileMessageCallback* aRequest)
 {
 #ifndef MOZ_WEBSMS_BACKEND
@@ -1113,41 +1076,41 @@ AndroidBridge::SendMessage(const nsAStri
                            nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::SendMessage");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::SendMessageWrapper(aNumber, aMessage, requestId);
+    GeckoAppShell::SendMessageWrapper(aNumber, aMessage, requestId);
 }
 
 void
 AndroidBridge::GetMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::GetMessage");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::GetMessageWrapper(aMessageId, requestId);
+    GeckoAppShell::GetMessageWrapper(aMessageId, requestId);
 }
 
 void
 AndroidBridge::DeleteMessage(int32_t aMessageId, nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::DeleteMessage");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::DeleteMessageWrapper(aMessageId, requestId);
+    GeckoAppShell::DeleteMessageWrapper(aMessageId, requestId);
 }
 
 void
 AndroidBridge::CreateMessageList(const dom::mobilemessage::SmsFilterData& aFilter, bool aReverse,
                                  nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::CreateMessageList");
 
@@ -1168,33 +1131,34 @@ AndroidBridge::CreateMessageList(const d
         jstring elem = NewJavaString(&jniFrame, aFilter.numbers()[i]);
         env->SetObjectArrayElement(numbers, i, elem);
         env->DeleteLocalRef(elem);
     }
 
     int64_t startDate = aFilter.hasStartDate() ? aFilter.startDate() : -1;
     int64_t endDate = aFilter.hasEndDate() ? aFilter.endDate() : -1;
     GeckoAppShell::CreateMessageListWrapper(startDate, endDate,
-                                            numbers, aFilter.numbers().Length(),
+                                            ObjectArray::Ref::From(numbers),
+                                            aFilter.numbers().Length(),
                                             aFilter.delivery(),
                                             aFilter.hasRead(), aFilter.read(),
                                             aFilter.threadId(),
                                             aReverse, requestId);
 }
 
 void
 AndroidBridge::GetNextMessageInList(int32_t aListId, nsIMobileMessageCallback* aRequest)
 {
     ALOG_BRIDGE("AndroidBridge::GetNextMessageInList");
 
     uint32_t requestId;
     if (!QueueSmsRequest(aRequest, &requestId))
         return;
 
-    mozilla::widget::android::GeckoAppShell::GetNextMessageInListWrapper(aListId, requestId);
+    GeckoAppShell::GetNextMessageInListWrapper(aListId, requestId);
 }
 
 bool
 AndroidBridge::QueueSmsRequest(nsIMobileMessageCallback* aRequest, uint32_t* aRequestIdOut)
 {
     MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
     MOZ_ASSERT(aRequest && aRequestIdOut);
 
@@ -1227,62 +1191,56 @@ AndroidBridge::DequeueSmsRequest(uint32_
     return mSmsRequests[aRequestId].forget();
 }
 
 void
 AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
 {
     ALOG_BRIDGE("AndroidBridge::GetCurrentNetworkInformation");
 
-    JNIEnv *env = GetJNIEnv();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
     // To prevent calling too many methods through JNI, the Java method returns
     // an array of double even if we actually want an integer, a boolean, and an integer.
 
-    jdoubleArray arr = mozilla::widget::android::GeckoAppShell::GetCurrentNetworkInformationWrapper();
-    if (!arr || env->GetArrayLength(arr) != 3) {
+    auto arr = GeckoAppShell::GetCurrentNetworkInformationWrapper();
+
+    JNIEnv* const env = arr.Env();
+    if (!arr || env->GetArrayLength(arr.Get()) != 3) {
         return;
     }
 
-    jdouble* info = env->GetDoubleArrayElements(arr, 0);
+    jdouble* info = env->GetDoubleArrayElements(arr.Get(), 0);
 
     aNetworkInfo->type() = info[0];
     aNetworkInfo->isWifi() = info[1] == 1.0f;
     aNetworkInfo->dhcpGateway() = info[2];
 
-    env->ReleaseDoubleArrayElements(arr, info, 0);
+    env->ReleaseDoubleArrayElements(arr.Get(), info, 0);
 }
 
 void *
 AndroidBridge::LockBitmap(jobject bitmap)
 {
     JNIEnv *env = GetJNIEnv();
 
-    AutoLocalJNIFrame jniFrame(env, 0);
-
     int err;
     void *buf;
 
     if ((err = AndroidBitmap_lockPixels(env, bitmap, &buf)) != 0) {
         ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err);
         buf = nullptr;
     }
 
     return buf;
 }
 
 void
 AndroidBridge::UnlockBitmap(jobject bitmap)
 {
     JNIEnv *env = GetJNIEnv();
 
-    AutoLocalJNIFrame jniFrame(env, 0);
-
     int err;
 
     if ((err = AndroidBitmap_unlockPixels(env, bitmap)) != 0)
         ALOG_BRIDGE("AndroidBitmap_unlockPixels failed! (error %d)", err);
 }
 
 
 bool
@@ -1415,47 +1373,47 @@ AndroidBridge::LockWindow(void *window, 
         *stride = info.s;
     } else return false;
 
     return true;
 }
 
 jobject
 AndroidBridge::GetGlobalContextRef() {
-    if (sGlobalContext == nullptr) {
-        JNIEnv *env = GetJNIForThread();
-
-        AutoLocalJNIFrame jniFrame(env, 4);
-
-        jobject context = mozilla::widget::android::GeckoAppShell::GetContext();
-        if (!context) {
-            ALOG_BRIDGE("%s: Could not GetContext()", __FUNCTION__);
-            return 0;
-        }
-        jclass contextClass = env->FindClass("android/content/Context");
-        if (!contextClass) {
-            ALOG_BRIDGE("%s: Could not find Context class.", __FUNCTION__);
-            return 0;
-        }
-        jmethodID mid = env->GetMethodID(contextClass, "getApplicationContext",
-                                         "()Landroid/content/Context;");
-        if (!mid) {
-            ALOG_BRIDGE("%s: Could not find getApplicationContext.", __FUNCTION__);
-            return 0;
-        }
-        jobject appContext = env->CallObjectMethod(context, mid);
-        if (!appContext) {
-            ALOG_BRIDGE("%s: getApplicationContext failed.", __FUNCTION__);
-            return 0;
-        }
-
-        sGlobalContext = env->NewGlobalRef(appContext);
-        MOZ_ASSERT(sGlobalContext);
+    if (sGlobalContext) {
+        return sGlobalContext;
     }
 
+    JNIEnv* const env = GetJNIForThread();
+    AutoLocalJNIFrame jniFrame(env, 4);
+
+    auto context = GeckoAppShell::GetContext();
+    if (!context) {
+        ALOG_BRIDGE("%s: Could not GetContext()", __FUNCTION__);
+        return 0;
+    }
+    jclass contextClass = env->FindClass("android/content/Context");
+    if (!contextClass) {
+        ALOG_BRIDGE("%s: Could not find Context class.", __FUNCTION__);
+        return 0;
+    }
+    jmethodID mid = env->GetMethodID(contextClass, "getApplicationContext",
+                                     "()Landroid/content/Context;");
+    if (!mid) {
+        ALOG_BRIDGE("%s: Could not find getApplicationContext.", __FUNCTION__);
+        return 0;
+    }
+    jobject appContext = env->CallObjectMethod(context.Get(), mid);
+    if (!appContext) {
+        ALOG_BRIDGE("%s: getApplicationContext failed.", __FUNCTION__);
+        return 0;
+    }
+
+    sGlobalContext = env->NewGlobalRef(appContext);
+    MOZ_ASSERT(sGlobalContext);
     return sGlobalContext;
 }
 
 bool
 AndroidBridge::UnlockWindow(void* window)
 {
     int err;
 
@@ -1471,101 +1429,91 @@ AndroidBridge::UnlockWindow(void* window
     }
 
     return true;
 }
 
 void
 AndroidBridge::SetFirstPaintViewport(const LayerIntPoint& aOffset, const CSSToLayerScale& aZoom, const CSSRect& aCssPageRect)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client)
+    if (!mLayerClient) {
         return;
+    }
 
-    client->SetFirstPaintViewport((float)aOffset.x, (float)aOffset.y, aZoom.scale,
-                                  aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
+    mLayerClient->SetFirstPaintViewport(float(aOffset.x), float(aOffset.y), aZoom.scale,
+            aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
 AndroidBridge::SetPageRect(const CSSRect& aCssPageRect)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client)
+    if (!mLayerClient) {
         return;
+    }
 
-    client->SetPageRect(aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost());
+    mLayerClient->SetPageRect(aCssPageRect.x, aCssPageRect.y,
+                              aCssPageRect.XMost(), aCssPageRect.YMost());
 }
 
 void
 AndroidBridge::SyncViewportInfo(const LayerIntRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
                                 bool aLayersUpdated, ParentLayerPoint& aScrollOffset, CSSToParentLayerScale& aScale,
                                 LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client) {
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
 
-    jobject viewTransformJObj = client->SyncViewportInfo(aDisplayPort.x, aDisplayPort.y,
-                                aDisplayPort.width, aDisplayPort.height,
-                                aDisplayResolution.scale, aLayersUpdated);
-    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
+    ViewTransform::LocalRef viewTransform = mLayerClient->SyncViewportInfo(
+            aDisplayPort.x, aDisplayPort.y,
+            aDisplayPort.width, aDisplayPort.height,
+            aDisplayResolution.scale, aLayersUpdated);
 
-    if (!viewTransformJObj) {
-        return;
-    }
+    NS_ABORT_IF_FALSE(viewTransform, "No view transform object!");
 
-    ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
-    aScrollOffset = ParentLayerPoint(viewTransform->getx(), viewTransform->gety());
-    aScale.scale = viewTransform->getscale();
-    aFixedLayerMargins.top = viewTransform->getfixedLayerMarginTop();
-    aFixedLayerMargins.right = viewTransform->getfixedLayerMarginRight();
-    aFixedLayerMargins.bottom = viewTransform->getfixedLayerMarginBottom();
-    aFixedLayerMargins.left = viewTransform->getfixedLayerMarginLeft();
-    aOffset.x = viewTransform->getoffsetX();
-    aOffset.y = viewTransform->getoffsetY();
-    delete viewTransform;
+    aScrollOffset = ParentLayerPoint(viewTransform->X(), viewTransform->Y());
+    aScale.scale = viewTransform->Scale();
+    aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
+    aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
+    aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
+    aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
+    aOffset.x = viewTransform->OffsetX();
+    aOffset.y = viewTransform->OffsetY();
 }
 
 void AndroidBridge::SyncFrameMetrics(const ParentLayerPoint& aScrollOffset, float aZoom, const CSSRect& aCssPageRect,
                                      bool aLayersUpdated, const CSSRect& aDisplayPort, const CSSToLayerScale& aDisplayResolution,
                                      bool aIsFirstPaint, LayerMargin& aFixedLayerMargins, ScreenPoint& aOffset)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client) {
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
 
     // convert the displayport rect from scroll-relative CSS pixels to document-relative device pixels
     LayerRect dpUnrounded = aDisplayPort * aDisplayResolution;
     dpUnrounded += LayerPoint::FromUnknownPoint(aScrollOffset.ToUnknownPoint());
     LayerIntRect dp = gfx::RoundedToInt(dpUnrounded);
 
-    jobject viewTransformJObj = client->SyncFrameMetrics(aScrollOffset.x, aScrollOffset.y, aZoom,
-                                                         aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(),
-                                                         aLayersUpdated, dp.x, dp.y, dp.width, dp.height, aDisplayResolution.scale,
-                                                         aIsFirstPaint);
+    ViewTransform::LocalRef viewTransform = mLayerClient->SyncFrameMetrics(
+            aScrollOffset.x, aScrollOffset.y, aZoom,
+            aCssPageRect.x, aCssPageRect.y, aCssPageRect.XMost(), aCssPageRect.YMost(),
+            aLayersUpdated, dp.x, dp.y, dp.width, dp.height, aDisplayResolution.scale,
+            aIsFirstPaint);
+
+    NS_ABORT_IF_FALSE(viewTransform, "No view transform object!");
 
-    NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!");
-    if (!viewTransformJObj) {
-        return;
-    }
-    ViewTransform* viewTransform = ViewTransform::Wrap(viewTransformJObj);
+    aFixedLayerMargins.top = viewTransform->FixedLayerMarginTop();
+    aFixedLayerMargins.right = viewTransform->FixedLayerMarginRight();
+    aFixedLayerMargins.bottom = viewTransform->FixedLayerMarginBottom();
+    aFixedLayerMargins.left = viewTransform->FixedLayerMarginLeft();
 
-    aFixedLayerMargins.top = viewTransform->getfixedLayerMarginTop();
-    aFixedLayerMargins.right = viewTransform->getfixedLayerMarginRight();
-    aFixedLayerMargins.bottom = viewTransform->getfixedLayerMarginBottom();
-    aFixedLayerMargins.left = viewTransform->getfixedLayerMarginLeft();
-
-    aOffset.x = viewTransform->getoffsetX();
-    aOffset.y = viewTransform->getoffsetY();
-
-    delete viewTransform;
+    aOffset.x = viewTransform->OffsetX();
+    aOffset.y = viewTransform->OffsetY();
 }
 
 AndroidBridge::AndroidBridge()
   : mLayerClient(nullptr)
 {
 }
 
 AndroidBridge::~AndroidBridge()
@@ -1659,17 +1607,17 @@ JavaThreadDetachFunc(void *arg)
     vm->DetachCurrentThread();
 }
 
 uint32_t
 AndroidBridge::GetScreenOrientation()
 {
     ALOG_BRIDGE("AndroidBridge::GetScreenOrientation");
 
-    int16_t orientation = mozilla::widget::android::GeckoAppShell::GetScreenOrientationWrapper();
+    int16_t orientation = GeckoAppShell::GetScreenOrientationWrapper();
 
     if (!orientation)
         return dom::eScreenOrientation_None;
 
     return static_cast<dom::ScreenOrientation>(orientation);
 }
 
 void
@@ -1683,30 +1631,23 @@ AndroidBridge::GetProxyForURI(const nsAC
                               const nsACString & aScheme,
                               const nsACString & aHost,
                               const int32_t      aPort,
                               nsACString & aResult)
 {
     if (!HasEnv()) {
         return NS_ERROR_FAILURE;
     }
-    JNIEnv* env = GetJNIEnv();
 
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jstring jstrRet =
-      mozilla::widget::android::GeckoAppShell::GetProxyForURIWrapper(NS_ConvertUTF8toUTF16(aSpec),
-                                                                   NS_ConvertUTF8toUTF16(aScheme),
-                                                                     NS_ConvertUTF8toUTF16(aHost),
-                                                                                           aPort);
+    auto jstrRet = GeckoAppShell::GetProxyForURIWrapper(aSpec, aScheme, aHost, aPort);
 
     if (!jstrRet)
         return NS_ERROR_FAILURE;
 
-    nsJNIString jniStr(jstrRet, env);
-    CopyUTF16toUTF8(jniStr, aResult);
+    aResult = nsCString(jstrRet);
     return NS_OK;
 }
 
 
 /* attribute nsIAndroidBrowserApp browserApp; */
 NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp)
 {
     if (nsAppShell::gAppShell)
@@ -1723,63 +1664,52 @@ NS_IMETHODIMP nsAndroidBridge::SetBrowse
 
 void
 AndroidBridge::AddPluginView(jobject view, const LayoutDeviceRect& rect, bool isFullScreen) {
     nsWindow* win = nsWindow::TopWindow();
     if (!win)
         return;
 
     CSSRect cssRect = rect / win->GetDefaultScale();
-    mozilla::widget::android::GeckoAppShell::AddPluginViewWrapper(view, cssRect.x, cssRect.y,
-                                                cssRect.width, cssRect.height, isFullScreen);
+    GeckoAppShell::AddPluginViewWrapper(Object::Ref::From(view), cssRect.x, cssRect.y,
+                                        cssRect.width, cssRect.height, isFullScreen);
 }
 
 extern "C"
 __attribute__ ((visibility("default")))
 jobject JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size);
 
 bool
 AndroidBridge::GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult)
 {
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jstring jstrThreadName =
-      mozilla::widget::android::GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(aThreadId);
+    auto jstrThreadName = GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(aThreadId);
 
     if (!jstrThreadName)
         return false;
 
-    nsJNIString jniStr(jstrThreadName, env);
-    CopyUTF16toUTF8(jniStr.get(), aResult);
+    aResult = nsCString(jstrThreadName);
     return true;
 }
 
 bool
 AndroidBridge::GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId,
                                           uint32_t aFrameId, nsCString & aResult)
 {
-    JNIEnv* env = GetJNIForThread();
-
-    AutoLocalJNIFrame jniFrame(env, 1);
-
-    jstring jstrSampleName = mozilla::widget::android::GeckoJavaSampler::GetFrameNameJavaProfilingWrapper
-      									(aThreadId, aSampleId, aFrameId);
+    auto jstrSampleName = GeckoJavaSampler::GetFrameNameJavaProfilingWrapper
+            (aThreadId, aSampleId, aFrameId);
 
     if (!jstrSampleName)
         return false;
 
-    nsJNIString jniStr(jstrSampleName, env);
-    CopyUTF16toUTF8(jniStr.get(), aResult);
+    aResult = nsCString(jstrSampleName);
     return true;
 }
 
-nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer, bool &shouldStore)
+nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, Object::Param buffer, bool &shouldStore)
 {
     nsresult rv;
     float scale = 1.0;
 
     if (!buffer)
         return NS_ERROR_FAILURE;
 
     // take a screenshot, as wide as possible, proportional to the destination size
@@ -1843,17 +1773,17 @@ nsresult AndroidBridge::CaptureThumbnail
     nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale),
              nsPresContext::CSSPixelsToAppUnits(srcY / scale),
              nsPresContext::CSSPixelsToAppUnits(srcW / scale),
              nsPresContext::CSSPixelsToAppUnits(srcH / scale));
 
     bool is24bit = (GetScreenDepth() == 24);
     uint32_t stride = bufW * (is24bit ? 4 : 2);
 
-    uint8_t* data = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
+    uint8_t* data = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer.Get()));
     if (!data)
         return NS_ERROR_FAILURE;
 
     MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO),
                "Need BackendType::CAIRO support");
     RefPtr<DrawTarget> dt =
         Factory::CreateDrawTargetForData(BackendType::CAIRO,
                                          data,
@@ -1877,23 +1807,23 @@ nsresult AndroidBridge::CaptureThumbnail
     return NS_OK;
 }
 
 void
 AndroidBridge::GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort)
 {
 
     ALOG_BRIDGE("Enter: %s", __PRETTY_FUNCTION__);
-    JNIEnv* env = GetJNIEnv();
-    if (!mLayerClient || mLayerClient->isNull()) {
-
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
-    AutoLocalJNIFrame jniFrame(env, 0);
+
+    JNIEnv* const env = GetJNIEnv();
+    AutoLocalJNIFrame jniFrame(env, 1);
 
     float x, y, width, height,
         pageLeft, pageTop, pageRight, pageBottom,
         cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
         zoom;
     metrics->GetX(&x);
     metrics->GetY(&y);
     metrics->GetWidth(&width);
@@ -1903,44 +1833,36 @@ AndroidBridge::GetDisplayPort(bool aPage
     metrics->GetPageRight(&pageRight);
     metrics->GetPageBottom(&pageBottom);
     metrics->GetCssPageLeft(&cssPageLeft);
     metrics->GetCssPageTop(&cssPageTop);
     metrics->GetCssPageRight(&cssPageRight);
     metrics->GetCssPageBottom(&cssPageBottom);
     metrics->GetZoom(&zoom);
 
-    ImmutableViewportMetrics jmetrics = ImmutableViewportMetrics(pageLeft, pageTop, pageRight, pageBottom,
-                                                                 cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
-                                                                 x, y, x + width, y + height,
-                                                                 zoom);
+    auto jmetrics = ImmutableViewportMetrics::New(
+            pageLeft, pageTop, pageRight, pageBottom,
+            cssPageLeft, cssPageTop, cssPageRight, cssPageBottom,
+            x, y, x + width, y + height,
+            zoom);
 
-    jobject jobj = mLayerClient->GetDisplayPort(aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, jmetrics.wrappedObject());
-    if (!jobj) {
-        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
-        return;
-    }
-    DisplayPortMetrics* displayPortMetrics = DisplayPortMetrics::Wrap(jobj);
+    DisplayPortMetrics::LocalRef displayPortMetrics = mLayerClient->GetDisplayPort(
+            aPageSizeUpdate, aIsBrowserContentDisplayed, tabId, jmetrics);
 
-    AndroidRectF rect(env, displayPortMetrics->getMPosition());
-    if (jniFrame.CheckForException()) {
+    if (!displayPortMetrics) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return;
     }
 
-    float resolution = displayPortMetrics->getResolution();
-    if (jniFrame.CheckForException()) {
-        ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
-        return;
-    }
+    AndroidRectF rect(env, displayPortMetrics->MPosition().Get());
+    float resolution = displayPortMetrics->Resolution();
 
     *displayPort = new nsAndroidDisplayport(rect, resolution);
     (*displayPort)->AddRef();
 
-    delete displayPortMetrics;
     ALOG_BRIDGE("Exit: %s", __PRETTY_FUNCTION__);
 }
 
 void
 AndroidBridge::ContentDocumentChanged()
 {
     if (!mLayerClient) {
         return;
@@ -1953,45 +1875,40 @@ AndroidBridge::IsContentDocumentDisplaye
 {
     if (!mLayerClient)
         return false;
 
     return mLayerClient->IsContentDocumentDisplayed();
 }
 
 bool
-AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution,
-                                         bool aDrawingCritical, ParentLayerPoint& aScrollOffset, CSSToParentLayerScale& aZoom)
+AndroidBridge::ProgressiveUpdateCallback(bool aHasPendingNewThebesContent,
+                                         const LayerRect& aDisplayPort, float aDisplayResolution,
+                                         bool aDrawingCritical, ParentLayerPoint& aScrollOffset,
+                                         CSSToParentLayerScale& aZoom)
 {
-    mozilla::widget::android::GeckoLayerClient *client = mLayerClient;
-    if (!client) {
+    if (!mLayerClient) {
         ALOG_BRIDGE("Exceptional Exit: %s", __PRETTY_FUNCTION__);
         return false;
     }
 
-    jobject progressiveUpdateDataJObj = client->ProgressiveUpdateCallback(aHasPendingNewThebesContent,
-                                                                   (float)aDisplayPort.x,
-                                                                   (float)aDisplayPort.y,
-                                                                   (float)aDisplayPort.width,
-                                                                   (float)aDisplayPort.height,
-                                                                          aDisplayResolution,
-                                                                         !aDrawingCritical);
-
-    NS_ABORT_IF_FALSE(progressiveUpdateDataJObj, "No progressive update data!");
+    ProgressiveUpdateData::LocalRef progressiveUpdateData =
+            mLayerClient->ProgressiveUpdateCallback(aHasPendingNewThebesContent,
+                                                    (float)aDisplayPort.x,
+                                                    (float)aDisplayPort.y,
+                                                    (float)aDisplayPort.width,
+                                                    (float)aDisplayPort.height,
+                                                           aDisplayResolution,
+                                                          !aDrawingCritical);
 
-    ProgressiveUpdateData* progressiveUpdateData = ProgressiveUpdateData::Wrap(progressiveUpdateDataJObj);
+    aScrollOffset.x = progressiveUpdateData->X();
+    aScrollOffset.y = progressiveUpdateData->Y();
+    aZoom.scale = progressiveUpdateData->Scale();
 
-    aScrollOffset.x = progressiveUpdateData->getx();
-    aScrollOffset.y = progressiveUpdateData->gety();
-    aZoom.scale = progressiveUpdateData->getscale();
-
-    bool ret = progressiveUpdateData->getabort();
-    delete progressiveUpdateData;
-
-    return ret;
+    return progressiveUpdateData->Abort();
 }
 
 void
 AndroidBridge::PostTaskToUiThread(Task* aTask, int aDelayMs)
 {
     // add the new task into the mDelayedTaskQueue, sorted with
     // the earliest task first in the queue
     DelayedTask* newTask = new DelayedTask(aTask, aDelayMs);
@@ -2035,56 +1952,55 @@ AndroidBridge::RunDelayedUiThreadTasks()
         Task* task = nextTask->GetTask();
         delete nextTask;
 
         task->Run();
     }
     return -1;
 }
 
-jobject AndroidBridge::ChannelCreate(jobject stream) {
-    JNIEnv *env = GetJNIForThread();
-    env->PushLocalFrame(1);
-    jobject channel = env->CallStaticObjectMethod(sBridge->jReadableByteChannel, sBridge->jChannelCreate, stream);
-    return env->PopLocalFrame(channel);
+Object::LocalRef AndroidBridge::ChannelCreate(Object::Param stream) {
+    JNIEnv* const env = GetJNIForThread();
+    auto rv = Object::LocalRef::Adopt(env, env->CallStaticObjectMethod(
+            sBridge->jReadableByteChannel, sBridge->jChannelCreate, stream.Get()));
+    HandleUncaughtException(env);
+    return rv;
 }
 
-void AndroidBridge::InputStreamClose(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    env->CallVoidMethod(obj, sBridge->jClose);
+void AndroidBridge::InputStreamClose(Object::Param obj) {
+    JNIEnv* const env = GetJNIForThread();
+    env->CallVoidMethod(obj.Get(), sBridge->jClose);
+    HandleUncaughtException(env);
 }
 
-uint32_t AndroidBridge::InputStreamAvailable(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    return env->CallIntMethod(obj, sBridge->jAvailable);
+uint32_t AndroidBridge::InputStreamAvailable(Object::Param obj) {
+    JNIEnv* const env = GetJNIForThread();
+    auto rv = env->CallIntMethod(obj.Get(), sBridge->jAvailable);
+    HandleUncaughtException(env);
+    return rv;
 }
 
-nsresult AndroidBridge::InputStreamRead(jobject obj, char *aBuf, uint32_t aCount, uint32_t *aRead) {
-    JNIEnv *env = GetJNIForThread();
-    AutoLocalJNIFrame jniFrame(env, 1);
-    jobject arr =  env->NewDirectByteBuffer(aBuf, aCount);
-    jint read = env->CallIntMethod(obj, sBridge->jByteBufferRead, arr);
+nsresult AndroidBridge::InputStreamRead(Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead) {
+    JNIEnv* const env = GetJNIForThread();
+    auto arr = Object::LocalRef::Adopt(env, env->NewDirectByteBuffer(aBuf, aCount));
+    jint read = env->CallIntMethod(obj.Get(), sBridge->jByteBufferRead, arr.Get());
 
     if (env->ExceptionCheck()) {
         env->ExceptionClear();
         return NS_ERROR_FAILURE;
     }
 
     if (read <= 0) {
         *aRead = 0;
         return NS_OK;
     }
     *aRead = read;
     return NS_OK;
 }
 
 nsresult AndroidBridge::GetExternalPublicDirectory(const nsAString& aType, nsAString& aPath) {
-    AutoLocalJNIFrame frame(1);
-    const jstring path = GeckoAppShell::GetExternalPublicDirectory(aType);
+    auto path = GeckoAppShell::GetExternalPublicDirectory(aType);
     if (!path) {
         return NS_ERROR_NOT_AVAILABLE;
     }
-    nsJNIString pathStr(path, frame.GetEnv());
-    aPath.Assign(pathStr);
+    aPath = nsString(path);
     return NS_OK;
 }
--- a/widget/android/AndroidBridge.h
+++ b/widget/android/AndroidBridge.h
@@ -10,16 +10,17 @@
 #include <android/log.h>
 #include <cstdlib>
 #include <pthread.h>
 
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 
 #include "GeneratedJNIWrappers.h"
+#include "AndroidJavaWrappers.h"
 
 #include "nsIMutableArray.h"
 #include "nsIMIMEInfo.h"
 #include "nsColor.h"
 #include "gfxRect.h"
 
 #include "nsIAndroidBridge.h"
 #include "nsIMobileMessageCallback.h"
@@ -132,17 +133,17 @@ public:
     static void RegisterJavaUiThread() {
         sJavaUiThread = pthread_self();
     }
 
     static bool IsJavaUiThread() {
         return pthread_equal(pthread_self(), sJavaUiThread);
     }
 
-    static void ConstructBridge(JNIEnv *jEnv);
+    static void ConstructBridge(JNIEnv *jEnv, jni::Object::Param clsLoader);
 
     static AndroidBridge *Bridge() {
         return sBridge;
     }
 
     static JavaVM *GetVM() {
         MOZ_ASSERT(sBridge);
         return sBridge->mJavaVM;
@@ -182,26 +183,26 @@ public:
     // us to use.  toolkit/xre/nsAndroidStartup.cpp calls
     // SetMainThread.
     bool SetMainThread(pthread_t thr);
 
     /* These are all implemented in Java */
     bool GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult);
     bool GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId, uint32_t aFrameId, nsCString & aResult);
 
-    nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jobject buffer, bool &shouldStore);
+    nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jni::Object::Param buffer, bool &shouldStore);
     void GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
     void ContentDocumentChanged();
     bool IsContentDocumentDisplayed();
 
     bool ProgressiveUpdateCallback(bool aHasPendingNewThebesContent, const LayerRect& aDisplayPort, float aDisplayResolution, bool aDrawingCritical,
                                    mozilla::ParentLayerPoint& aScrollOffset, mozilla::CSSToParentLayerScale& aZoom);
 
-    void SetLayerClient(JNIEnv* env, jobject jobj);
-    mozilla::widget::android::GeckoLayerClient* GetLayerClient() { return mLayerClient; }
+    void SetLayerClient(widget::GeckoLayerClient::Param jobj);
+    const widget::GeckoLayerClient::Ref& GetLayerClient() { return mLayerClient; }
 
     bool GetHandlersForURL(const nsAString& aURL,
                            nsIMutableArray* handlersArray = nullptr,
                            nsIHandlerApp **aDefaultApp = nullptr,
                            const nsAString& aAction = EmptyString());
 
     bool GetHandlersForMimeType(const nsAString& aMimeType,
                                 nsIMutableArray* handlersArray = nullptr,
@@ -328,46 +329,46 @@ public:
     static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string);
 
     static jclass GetClassGlobalRef(JNIEnv* env, const char* className);
     static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
     static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
     static jmethodID GetMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType);
     static jmethodID GetStaticMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType);
 
-    static jobject ChannelCreate(jobject);
+    static jni::Object::LocalRef ChannelCreate(jni::Object::Param);
 
-    static void InputStreamClose(jobject obj);
-    static uint32_t InputStreamAvailable(jobject obj);
-    static nsresult InputStreamRead(jobject obj, char *aBuf, uint32_t aCount, uint32_t *aRead);
+    static void InputStreamClose(jni::Object::Param obj);
+    static uint32_t InputStreamAvailable(jni::Object::Param obj);
+    static nsresult InputStreamRead(jni::Object::Param obj, char *aBuf, uint32_t aCount, uint32_t *aRead);
 
     static nsresult GetExternalPublicDirectory(const nsAString& aType, nsAString& aPath);
 
 protected:
     static pthread_t sJavaUiThread;
     static AndroidBridge* sBridge;
     nsTArray<nsCOMPtr<nsIMobileMessageCallback> > mSmsRequests;
 
     // the global JavaVM
     JavaVM *mJavaVM;
 
     // the JNIEnv for the main thread
     JNIEnv *mJNIEnv;
     pthread_t mThread;
 
-    mozilla::widget::android::GeckoLayerClient *mLayerClient;
+    widget::GeckoLayerClient::GlobalRef mLayerClient;
 
     // the android.telephony.SmsMessage class
     jclass mAndroidSmsMessageClass;
 
     AndroidBridge();
     ~AndroidBridge();
 
     void InitStubs(JNIEnv *jEnv);
-    bool Init(JNIEnv *jEnv);
+    bool Init(JNIEnv *jEnv, jni::Object::Param clsLoader);
 
     bool mOpenedGraphicsLibraries;
     void OpenGraphicsLibraries();
     void* GetNativeSurface(JNIEnv* env, jobject surface);
 
     bool mHasNativeBitmapAccess;
     bool mHasNativeWindowAccess;
     bool mHasNativeWindowFallback;
@@ -399,21 +400,24 @@ protected:
 
     // For native surface stuff
     jclass jSurfaceClass;
     jfieldID jSurfacePointerField;
 
     jclass jLayerView;
 
     jfieldID jEGLSurfacePointerField;
-    mozilla::widget::android::GLController *mGLControllerObj;
+    widget::GLController::GlobalRef mGLControllerObj;
 
     // some convinient types to have around
     jclass jStringClass;
 
+    jni::Object::GlobalRef mClassLoader;
+    jmethodID mClassLoaderLoadClass;
+
     // calls we've dlopened from libjnigraphics.so
     int (* AndroidBitmap_getInfo)(JNIEnv *env, jobject bitmap, void *info);
     int (* AndroidBitmap_lockPixels)(JNIEnv *env, jobject bitmap, void **buffer);
     int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap);
 
     void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface);
     void* (*ANativeWindow_fromSurfaceTexture)(JNIEnv *env, jobject surfaceTexture);
     void (*ANativeWindow_release)(void *window);
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -43,35 +43,36 @@
 #include "AndroidSurfaceTexture.h"
 #include "GeckoProfiler.h"
 #include "nsMemoryPressure.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::mobilemessage;
 using namespace mozilla::layers;
+using namespace mozilla::widget;
 using namespace mozilla::widget::android;
 
 /* Forward declare all the JNI methods as extern "C" */
 
 extern "C" {
 /*
  * Incoming JNI methods
  */
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_registerJavaUiThread(JNIEnv *jenv, jclass jc)
 {
     AndroidBridge::RegisterJavaUiThread();
 }
 
 NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass jc)
+Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *jenv, jclass, jobject clsLoader)
 {
-    AndroidBridge::ConstructBridge(jenv);
+    AndroidBridge::ConstructBridge(jenv, jni::Object::Ref::From(clsLoader));
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *jenv, jclass jc, jobject event)
 {
     // poke the appshell
     if (nsAppShell::gAppShell)
         nsAppShell::gAppShell->PostEvent(AndroidGeckoEvent::MakeFromJavaObject(jenv, event));
@@ -895,21 +896,21 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv* env, jobject instance)
 {
     if (!AndroidBridge::Bridge()) {
         return;
     }
 
-    NativePanZoomController* oldRef = APZCCallbackHandler::GetInstance()->SetNativePanZoomController(instance);
-    if (oldRef && !oldRef->isNull()) {
-        MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
-        delete oldRef;
-    }
+    const auto& newRef = NativePanZoomController::Ref::From(instance);
+    NativePanZoomController::LocalRef oldRef =
+            APZCCallbackHandler::GetInstance()->SetNativePanZoomController(newRef);
+
+    MOZ_ASSERT(!oldRef, "Registering a new NPZC when we already have one");
 }
 
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
 {
     APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (!controller) {
         return false;
@@ -940,22 +941,20 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_destroy(JNIEnv* env, jobject instance)
 {
     if (!AndroidBridge::Bridge()) {
         return;
     }
 
-    NativePanZoomController* oldRef = APZCCallbackHandler::GetInstance()->SetNativePanZoomController(nullptr);
-    if (!oldRef || oldRef->isNull()) {
-        MOZ_ASSERT(false, "Clearing a non-existent NPZC");
-    } else {
-        delete oldRef;
-    }
+    NativePanZoomController::LocalRef oldRef =
+            APZCCallbackHandler::GetInstance()->SetNativePanZoomController(nullptr);
+
+    MOZ_ASSERT(oldRef, "Clearing a non-existent NPZC");
 }
 
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance)
 {
     // FIXME implement this
     return true;
 }
--- a/widget/android/AndroidJavaWrappers.cpp
+++ b/widget/android/AndroidJavaWrappers.cpp
@@ -9,17 +9,16 @@
 #include "nsIDOMKeyEvent.h"
 #include "nsIWidget.h"
 #include "mozilla/BasicEvents.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TouchEvents.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
-using namespace mozilla::widget::android;
 
 jclass AndroidGeckoEvent::jGeckoEventClass = 0;
 jfieldID AndroidGeckoEvent::jActionField = 0;
 jfieldID AndroidGeckoEvent::jTypeField = 0;
 jfieldID AndroidGeckoEvent::jAckNeededField = 0;
 jfieldID AndroidGeckoEvent::jTimeField = 0;
 jfieldID AndroidGeckoEvent::jPoints = 0;
 jfieldID AndroidGeckoEvent::jPointIndicies = 0;
@@ -117,17 +116,16 @@ void
 mozilla::InitAndroidJavaWrappers(JNIEnv *jEnv)
 {
     AndroidGeckoEvent::InitGeckoEventClass(jEnv);
     AndroidPoint::InitPointClass(jEnv);
     AndroidLocation::InitLocationClass(jEnv);
     AndroidRect::InitRectClass(jEnv);
     AndroidRectF::InitRectFClass(jEnv);
     AndroidLayerRendererFrame::InitLayerRendererFrameClass(jEnv);
-    InitStubs(jEnv);
 }
 
 void
 AndroidGeckoEvent::InitGeckoEventClass(JNIEnv *jEnv)
 {
     AutoJNIClass geckoEvent(jEnv, "org/mozilla/gecko/GeckoEvent");
     jGeckoEventClass = geckoEvent.getGlobalRef();
 
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -1,2479 +1,1304 @@
 // GENERATED CODE
-// Generated by the Java program at /build/annotationProcessors at compile time from
-// annotations on Java methods. To update, change the annotations on the corresponding Java
-// methods and rerun the build. Manually updating this file will cause your build to fail.
+// Generated by the Java program at /build/annotationProcessors at compile time
+// from annotations on Java methods. To update, change the annotations on the
+// corresponding Javamethods and rerun the build. Manually updating this file
+// will cause your build to fail.
 
 #include "GeneratedJNIWrappers.h"
-#include "AndroidBridgeUtilities.h"
-#include "nsXPCOMStrings.h"
-#include "AndroidBridge.h"
+#include "mozilla/jni/Accessors.h"
 
 namespace mozilla {
 namespace widget {
-namespace android {
-jclass DownloadsIntegration::mDownloadsIntegrationClass = 0;
-jmethodID DownloadsIntegration::jScanMedia = 0;
-void DownloadsIntegration::InitStubs(JNIEnv *env) {
-    mDownloadsIntegrationClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/DownloadsIntegration");
-    jScanMedia = AndroidBridge::GetStaticMethodID(env, mDownloadsIntegrationClass, "scanMedia", "(Ljava/lang/String;Ljava/lang/String;)V");
+
+constexpr char DownloadsIntegration::name[];
+
+constexpr char DownloadsIntegration::ScanMedia_t::name[];
+constexpr char DownloadsIntegration::ScanMedia_t::signature[];
+
+void DownloadsIntegration::ScanMedia(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<ScanMedia_t>::Call(nullptr, nullptr, a0, a1);
+}
+
+constexpr char GeckoAppShell::name[];
+
+constexpr char GeckoAppShell::AcknowledgeEvent_t::name[];
+constexpr char GeckoAppShell::AcknowledgeEvent_t::signature[];
+
+void GeckoAppShell::AcknowledgeEvent()
+{
+    return mozilla::jni::Method<AcknowledgeEvent_t>::Call(nullptr, nullptr);
+}
+
+constexpr char GeckoAppShell::AddPluginViewWrapper_t::name[];
+constexpr char GeckoAppShell::AddPluginViewWrapper_t::signature[];
+
+void GeckoAppShell::AddPluginViewWrapper(mozilla::jni::Object::Param a0, float a1, float a2, float a3, float a4, bool a5)
+{
+    return mozilla::jni::Method<AddPluginViewWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5);
+}
+
+constexpr char GeckoAppShell::AlertsProgressListener_OnProgress_t::name[];
+constexpr char GeckoAppShell::AlertsProgressListener_OnProgress_t::signature[];
+
+void GeckoAppShell::AlertsProgressListener_OnProgress(mozilla::jni::String::Param a0, int64_t a1, int64_t a2, mozilla::jni::String::Param a3)
+{
+    return mozilla::jni::Method<AlertsProgressListener_OnProgress_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-DownloadsIntegration* DownloadsIntegration::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    DownloadsIntegration* ret = new DownloadsIntegration(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char GeckoAppShell::CancelVibrate_t::name[];
+constexpr char GeckoAppShell::CancelVibrate_t::signature[];
+
+void GeckoAppShell::CancelVibrate()
+{
+    return mozilla::jni::Method<CancelVibrate_t>::Call(nullptr, nullptr);
+}
+
+constexpr char GeckoAppShell::CheckURIVisited_t::name[];
+constexpr char GeckoAppShell::CheckURIVisited_t::signature[];
+
+void GeckoAppShell::CheckURIVisited(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<CheckURIVisited_t>::Call(nullptr, nullptr, a0);
+}
+
+constexpr char GeckoAppShell::ClearMessageList_t::name[];
+constexpr char GeckoAppShell::ClearMessageList_t::signature[];
+
+void GeckoAppShell::ClearMessageList(int32_t a0)
+{
+    return mozilla::jni::Method<ClearMessageList_t>::Call(nullptr, nullptr, a0);
+}
+
+constexpr char GeckoAppShell::CloseCamera_t::name[];
+constexpr char GeckoAppShell::CloseCamera_t::signature[];
+
+void GeckoAppShell::CloseCamera()
+{
+    return mozilla::jni::Method<CloseCamera_t>::Call(nullptr, nullptr);
+}
+
+constexpr char GeckoAppShell::CloseNotification_t::name[];
+constexpr char GeckoAppShell::CloseNotification_t::signature[];
+
+void GeckoAppShell::CloseNotification(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<CloseNotification_t>::Call(nullptr, nullptr, a0);
 }
 
-void DownloadsIntegration::ScanMedia(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::ConnectionGetMimeType_t::name[];
+constexpr char GeckoAppShell::ConnectionGetMimeType_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
+mozilla::jni::String::LocalRef GeckoAppShell::ConnectionGetMimeType(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<ConnectionGetMimeType_t>::Call(nullptr, nullptr, a0);
+}
 
-    env->CallStaticVoidMethod(mDownloadsIntegrationClass, jScanMedia, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+constexpr char GeckoAppShell::CreateInputStream_t::name[];
+constexpr char GeckoAppShell::CreateInputStream_t::signature[];
+
+mozilla::jni::Object::LocalRef GeckoAppShell::CreateInputStream(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<CreateInputStream_t>::Call(nullptr, nullptr, a0);
 }
-jclass GeckoAppShell::mGeckoAppShellClass = 0;
-jmethodID GeckoAppShell::jAcknowledgeEvent = 0;
-jmethodID GeckoAppShell::jAddPluginViewWrapper = 0;
-jmethodID GeckoAppShell::jAlertsProgressListener_OnProgress = 0;
-jmethodID GeckoAppShell::jCancelVibrate = 0;
-jmethodID GeckoAppShell::jCheckURIVisited = 0;
-jmethodID GeckoAppShell::jClearMessageList = 0;
-jmethodID GeckoAppShell::jCloseCamera = 0;
-jmethodID GeckoAppShell::jCloseNotification = 0;
-jmethodID GeckoAppShell::jConnectionGetMimeType = 0;
-jmethodID GeckoAppShell::jCreateInputStream = 0;
-jmethodID GeckoAppShell::jCreateMessageListWrapper = 0;
-jmethodID GeckoAppShell::jCreateShortcut = 0;
-jmethodID GeckoAppShell::jDeleteMessageWrapper = 0;
-jmethodID GeckoAppShell::jDisableBatteryNotifications = 0;
-jmethodID GeckoAppShell::jDisableNetworkNotifications = 0;
-jmethodID GeckoAppShell::jDisableScreenOrientationNotifications = 0;
-jmethodID GeckoAppShell::jDisableSensor = 0;
-jmethodID GeckoAppShell::jEnableBatteryNotifications = 0;
-jmethodID GeckoAppShell::jEnableLocation = 0;
-jmethodID GeckoAppShell::jEnableLocationHighAccuracy = 0;
-jmethodID GeckoAppShell::jEnableNetworkNotifications = 0;
-jmethodID GeckoAppShell::jEnableScreenOrientationNotifications = 0;
-jmethodID GeckoAppShell::jEnableSensor = 0;
-jmethodID GeckoAppShell::jGamepadAdded = 0;
-jmethodID GeckoAppShell::jGetConnection = 0;
-jmethodID GeckoAppShell::jGetContext = 0;
-jmethodID GeckoAppShell::jGetCurrentBatteryInformationWrapper = 0;
-jmethodID GeckoAppShell::jGetCurrentNetworkInformationWrapper = 0;
-jmethodID GeckoAppShell::jGetDensity = 0;
-jmethodID GeckoAppShell::jGetDpiWrapper = 0;
-jmethodID GeckoAppShell::jGetExtensionFromMimeTypeWrapper = 0;
-jmethodID GeckoAppShell::jGetExternalPublicDirectory = 0;
-jmethodID GeckoAppShell::jGetHandlersForMimeTypeWrapper = 0;
-jmethodID GeckoAppShell::jGetHandlersForURLWrapper = 0;
-jmethodID GeckoAppShell::jGetIconForExtensionWrapper = 0;
-jmethodID GeckoAppShell::jGetMessageWrapper = 0;
-jmethodID GeckoAppShell::jGetMimeTypeFromExtensionsWrapper = 0;
-jmethodID GeckoAppShell::jGetNextMessageInListWrapper = 0;
-jmethodID GeckoAppShell::jGetProxyForURIWrapper = 0;
-jmethodID GeckoAppShell::jGetScreenDepthWrapper = 0;
-jmethodID GeckoAppShell::jGetScreenOrientationWrapper = 0;
-jmethodID GeckoAppShell::jGetShowPasswordSetting = 0;
-jmethodID GeckoAppShell::jGetSystemColoursWrapper = 0;
-jmethodID GeckoAppShell::jHandleGeckoMessageWrapper = 0;
-jmethodID GeckoAppShell::jHandleUncaughtException = 0;
-jmethodID GeckoAppShell::jHideProgressDialog = 0;
-jmethodID GeckoAppShell::jInitCameraWrapper = 0;
-jmethodID GeckoAppShell::jIsNetworkLinkKnown = 0;
-jmethodID GeckoAppShell::jIsNetworkLinkUp = 0;
-jmethodID GeckoAppShell::jIsTablet = 0;
-jmethodID GeckoAppShell::jKillAnyZombies = 0;
-jmethodID GeckoAppShell::jLoadPluginClass = 0;
-jmethodID GeckoAppShell::jLockScreenOrientation = 0;
-jmethodID GeckoAppShell::jMarkURIVisited = 0;
-jmethodID GeckoAppShell::jMoveTaskToBack = 0;
-jmethodID GeckoAppShell::jNetworkLinkType = 0;
-jmethodID GeckoAppShell::jNotifyDefaultPrevented = 0;
-jmethodID GeckoAppShell::jNotifyIME = 0;
-jmethodID GeckoAppShell::jNotifyIMEChange = 0;
-jmethodID GeckoAppShell::jNotifyIMEContext = 0;
-jmethodID GeckoAppShell::jNotifyWakeLockChanged = 0;
-jmethodID GeckoAppShell::jNotifyXreExit = 0;
-jmethodID GeckoAppShell::jOpenUriExternal = 0;
-jmethodID GeckoAppShell::jPerformHapticFeedback = 0;
-jmethodID GeckoAppShell::jPumpMessageLoop = 0;
-jmethodID GeckoAppShell::jRegisterSurfaceTextureFrameListener = 0;
-jmethodID GeckoAppShell::jRemovePluginView = 0;
-jmethodID GeckoAppShell::jRequestUiThreadCallback = 0;
-jmethodID GeckoAppShell::jScheduleRestart = 0;
-jmethodID GeckoAppShell::jSendMessageWrapper = 0;
-jmethodID GeckoAppShell::jSetFullScreen = 0;
-jmethodID GeckoAppShell::jSetKeepScreenOn = 0;
-jmethodID GeckoAppShell::jSetURITitle = 0;
-jmethodID GeckoAppShell::jShowAlertNotificationWrapper = 0;
-jmethodID GeckoAppShell::jShowInputMethodPicker = 0;
-jmethodID GeckoAppShell::jStartMonitoringGamepad = 0;
-jmethodID GeckoAppShell::jStopMonitoringGamepad = 0;
-jmethodID GeckoAppShell::jUnlockProfile = 0;
-jmethodID GeckoAppShell::jUnlockScreenOrientation = 0;
-jmethodID GeckoAppShell::jUnregisterSurfaceTextureFrameListener = 0;
-jmethodID GeckoAppShell::jVibrate1 = 0;
-jmethodID GeckoAppShell::jVibrateA = 0;
-void GeckoAppShell::InitStubs(JNIEnv *env) {
-    mGeckoAppShellClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoAppShell");
-    jAcknowledgeEvent = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "acknowledgeEvent", "()V");
-    jAddPluginViewWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "addPluginView", "(Landroid/view/View;FFFFZ)V");
-    jAlertsProgressListener_OnProgress = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "alertsProgressListener_OnProgress", "(Ljava/lang/String;JJLjava/lang/String;)V");
-    jCancelVibrate = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "cancelVibrate", "()V");
-    jCheckURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "checkUriVisited", "(Ljava/lang/String;)V");
-    jClearMessageList = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "clearMessageList", "(I)V");
-    jCloseCamera = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeCamera", "()V");
-    jCloseNotification = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "closeNotification", "(Ljava/lang/String;)V");
-    jConnectionGetMimeType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "connectionGetMimeType", "(Ljava/net/URLConnection;)Ljava/lang/String;");
-    jCreateInputStream = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createInputStream", "(Ljava/net/URLConnection;)Ljava/io/InputStream;");
-    jCreateMessageListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createMessageList", "(JJ[Ljava/lang/String;ILjava/lang/String;ZZJZI)V");
-    jCreateShortcut = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "createShortcut", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-    jDeleteMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "deleteMessage", "(II)V");
-    jDisableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableBatteryNotifications", "()V");
-    jDisableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableNetworkNotifications", "()V");
-    jDisableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableScreenOrientationNotifications", "()V");
-    jDisableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "disableSensor", "(I)V");
-    jEnableBatteryNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableBatteryNotifications", "()V");
-    jEnableLocation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocation", "(Z)V");
-    jEnableLocationHighAccuracy = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableLocationHighAccuracy", "(Z)V");
-    jEnableNetworkNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableNetworkNotifications", "()V");
-    jEnableScreenOrientationNotifications = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableScreenOrientationNotifications", "()V");
-    jEnableSensor = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "enableSensor", "(I)V");
-    jGamepadAdded = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "gamepadAdded", "(II)V");
-    jGetConnection = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getConnection", "(Ljava/lang/String;)Ljava/net/URLConnection;");
-    jGetContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getContext", "()Landroid/content/Context;");
-    jGetCurrentBatteryInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentBatteryInformation", "()[D");
-    jGetCurrentNetworkInformationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getCurrentNetworkInformation", "()[D");
-    jGetDensity = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDensity", "()F");
-    jGetDpiWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getDpi", "()I");
-    jGetExtensionFromMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExtensionFromMimeType", "(Ljava/lang/String;)Ljava/lang/String;");
-    jGetExternalPublicDirectory = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getExternalPublicDirectory", "(Ljava/lang/String;)Ljava/lang/String;");
-    jGetHandlersForMimeTypeWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForMimeType", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
-    jGetHandlersForURLWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getHandlersForURL", "(Ljava/lang/String;Ljava/lang/String;)[Ljava/lang/String;");
-    jGetIconForExtensionWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getIconForExtension", "(Ljava/lang/String;I)[B");
-    jGetMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMessage", "(II)V");
-    jGetMimeTypeFromExtensionsWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getMimeTypeFromExtensions", "(Ljava/lang/String;)Ljava/lang/String;");
-    jGetNextMessageInListWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getNextMessageInList", "(II)V");
-    jGetProxyForURIWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getProxyForURI", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;");
-    jGetScreenDepthWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenDepth", "()I");
-    jGetScreenOrientationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getScreenOrientation", "()S");
-    jGetShowPasswordSetting = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getShowPasswordSetting", "()Z");
-    jGetSystemColoursWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "getSystemColors", "()[I");
-    jHandleGeckoMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleGeckoMessage", "(Lorg/mozilla/gecko/util/NativeJSContainer;)V");
-    jHandleUncaughtException = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "handleUncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V");
-    jHideProgressDialog = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "hideProgressDialog", "()V");
-    jInitCameraWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "initCamera", "(Ljava/lang/String;III)[I");
-    jIsNetworkLinkKnown = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkKnown", "()Z");
-    jIsNetworkLinkUp = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isNetworkLinkUp", "()Z");
-    jIsTablet = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "isTablet", "()Z");
-    jKillAnyZombies = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "killAnyZombies", "()V");
-    jLoadPluginClass = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "loadPluginClass", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/Class;");
-    jLockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "lockScreenOrientation", "(I)V");
-    jMarkURIVisited = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "markUriVisited", "(Ljava/lang/String;)V");
-    jMoveTaskToBack = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "moveTaskToBack", "()V");
-    jNetworkLinkType = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "networkLinkType", "()I");
-    jNotifyDefaultPrevented = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyDefaultPrevented", "(Z)V");
-    jNotifyIME = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIME", "(I)V");
-    jNotifyIMEChange = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEChange", "(Ljava/lang/String;III)V");
-    jNotifyIMEContext = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyIMEContext", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-    jNotifyWakeLockChanged = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "notifyWakeLockChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
-    jNotifyXreExit = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "onXreExit", "()V");
-    jOpenUriExternal = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "openUriExternal", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
-    jPerformHapticFeedback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "performHapticFeedback", "(Z)V");
-    jPumpMessageLoop = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "pumpMessageLoop", "()Z");
-    jRegisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "registerSurfaceTextureFrameListener", "(Ljava/lang/Object;I)V");
-    jRemovePluginView = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "removePluginView", "(Landroid/view/View;Z)V");
-    jRequestUiThreadCallback = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "requestUiThreadCallback", "(J)V");
-    jScheduleRestart = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "scheduleRestart", "()V");
-    jSendMessageWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "sendMessage", "(Ljava/lang/String;Ljava/lang/String;I)V");
-    jSetFullScreen = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setFullScreen", "(Z)V");
-    jSetKeepScreenOn = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setKeepScreenOn", "(Z)V");
-    jSetURITitle = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "setUriTitle", "(Ljava/lang/String;Ljava/lang/String;)V");
-    jShowAlertNotificationWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showAlertNotification", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
-    jShowInputMethodPicker = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "showInputMethodPicker", "()V");
-    jStartMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "startMonitoringGamepad", "()V");
-    jStopMonitoringGamepad = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "stopMonitoringGamepad", "()V");
-    jUnlockProfile = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockProfile", "()Z");
-    jUnlockScreenOrientation = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unlockScreenOrientation", "()V");
-    jUnregisterSurfaceTextureFrameListener = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "unregisterSurfaceTextureFrameListener", "(Ljava/lang/Object;)V");
-    jVibrate1 = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "(J)V");
-    jVibrateA = AndroidBridge::GetStaticMethodID(env, mGeckoAppShellClass, "vibrate", "([JI)V");
+
+constexpr char GeckoAppShell::CreateMessageListWrapper_t::name[];
+constexpr char GeckoAppShell::CreateMessageListWrapper_t::signature[];
+
+void GeckoAppShell::CreateMessageListWrapper(int64_t a0, int64_t a1, mozilla::jni::ObjectArray::Param a2, int32_t a3, mozilla::jni::String::Param a4, bool a5, bool a6, int64_t a7, bool a8, int32_t a9)
+{
+    return mozilla::jni::Method<CreateMessageListWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
+}
+
+constexpr char GeckoAppShell::CreateShortcut_t::name[];
+constexpr char GeckoAppShell::CreateShortcut_t::signature[];
+
+void GeckoAppShell::CreateShortcut(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2)
+{
+    return mozilla::jni::Method<CreateShortcut_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-GeckoAppShell* GeckoAppShell::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GeckoAppShell* ret = new GeckoAppShell(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char GeckoAppShell::DeleteMessageWrapper_t::name[];
+constexpr char GeckoAppShell::DeleteMessageWrapper_t::signature[];
 
-void GeckoAppShell::AcknowledgeEvent() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEvent);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DeleteMessageWrapper(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<DeleteMessageWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::AddPluginViewWrapper(jobject a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, bool a5) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableBatteryNotifications_t::name[];
+constexpr char GeckoAppShell::DisableBatteryNotifications_t::signature[];
 
-    jvalue args[6];
-    args[0].l = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].z = a5;
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jAddPluginViewWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableBatteryNotifications()
+{
+    return mozilla::jni::Method<DisableBatteryNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::AlertsProgressListener_OnProgress(const nsAString& a0, int64_t a1, int64_t a2, const nsAString& a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableNetworkNotifications_t::name[];
+constexpr char GeckoAppShell::DisableNetworkNotifications_t::signature[];
 
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].j = a1;
-    args[2].j = a2;
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jAlertsProgressListener_OnProgress, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableNetworkNotifications()
+{
+    return mozilla::jni::Method<DisableNetworkNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CancelVibrate() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableScreenOrientationNotifications_t::name[];
+constexpr char GeckoAppShell::DisableScreenOrientationNotifications_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCancelVibrate);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableScreenOrientationNotifications()
+{
+    return mozilla::jni::Method<DisableScreenOrientationNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CheckURIVisited(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::DisableSensor_t::name[];
+constexpr char GeckoAppShell::DisableSensor_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCheckURIVisited, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::DisableSensor(int32_t a0)
+{
+    return mozilla::jni::Method<DisableSensor_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::ClearMessageList(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableBatteryNotifications_t::name[];
+constexpr char GeckoAppShell::EnableBatteryNotifications_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jClearMessageList, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableBatteryNotifications()
+{
+    return mozilla::jni::Method<EnableBatteryNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CloseCamera() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseCamera);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char GeckoAppShell::EnableLocation_t::name[];
+constexpr char GeckoAppShell::EnableLocation_t::signature[];
 
-void GeckoAppShell::CloseNotification(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseNotification, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableLocation(bool a0)
+{
+    return mozilla::jni::Method<EnableLocation_t>::Call(nullptr, nullptr, a0);
 }
 
-jstring GeckoAppShell::ConnectionGetMimeType(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableLocationHighAccuracy_t::name[];
+constexpr char GeckoAppShell::EnableLocationHighAccuracy_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jConnectionGetMimeType, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::EnableLocationHighAccuracy(bool a0)
+{
+    return mozilla::jni::Method<EnableLocationHighAccuracy_t>::Call(nullptr, nullptr, a0);
 }
 
-jobject GeckoAppShell::CreateInputStream(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableNetworkNotifications_t::name[];
+constexpr char GeckoAppShell::EnableNetworkNotifications_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jCreateInputStream, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::EnableNetworkNotifications()
+{
+    return mozilla::jni::Method<EnableNetworkNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CreateMessageListWrapper(int64_t a0, int64_t a1, jobjectArray a2, int32_t a3, const nsAString& a4, bool a5, bool a6, int64_t a7, bool a8, int32_t a9) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableScreenOrientationNotifications_t::name[];
+constexpr char GeckoAppShell::EnableScreenOrientationNotifications_t::signature[];
 
-    jvalue args[10];
-    args[0].j = a0;
-    args[1].j = a1;
-    args[2].l = a2;
-    args[3].i = a3;
-    args[4].l = AndroidBridge::NewJavaString(env, a4);
-    args[5].z = a5;
-    args[6].z = a6;
-    args[7].j = a7;
-    args[8].z = a8;
-    args[9].i = a9;
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jCreateMessageListWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableScreenOrientationNotifications()
+{
+    return mozilla::jni::Method<EnableScreenOrientationNotifications_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::CreateShortcut(const nsAString& a0, const nsAString& a1, const nsAString& a2) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::EnableSensor_t::name[];
+constexpr char GeckoAppShell::EnableSensor_t::signature[];
 
-    jvalue args[3];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jCreateShortcut, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::EnableSensor(int32_t a0)
+{
+    return mozilla::jni::Method<EnableSensor_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::DeleteMessageWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GamepadAdded_t::name[];
+constexpr char GeckoAppShell::GamepadAdded_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDeleteMessageWrapper, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::GamepadAdded(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GamepadAdded_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::DisableBatteryNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetConnection_t::name[];
+constexpr char GeckoAppShell::GetConnection_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableBatteryNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GeckoAppShell::GetConnection(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetConnection_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::DisableNetworkNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetContext_t::name[];
+constexpr char GeckoAppShell::GetContext_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableNetworkNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GeckoAppShell::GetContext()
+{
+    return mozilla::jni::Method<GetContext_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::DisableScreenOrientationNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetCurrentBatteryInformationWrapper_t::name[];
+constexpr char GeckoAppShell::GetCurrentBatteryInformationWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableScreenOrientationNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::DisableSensor(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableSensor, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::DoubleArray::LocalRef GeckoAppShell::GetCurrentBatteryInformationWrapper()
+{
+    return mozilla::jni::Method<GetCurrentBatteryInformationWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableBatteryNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetCurrentNetworkInformationWrapper_t::name[];
+constexpr char GeckoAppShell::GetCurrentNetworkInformationWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableBatteryNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::DoubleArray::LocalRef GeckoAppShell::GetCurrentNetworkInformationWrapper()
+{
+    return mozilla::jni::Method<GetCurrentNetworkInformationWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableLocation(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetDensity_t::name[];
+constexpr char GeckoAppShell::GetDensity_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+float GeckoAppShell::GetDensity()
+{
+    return mozilla::jni::Method<GetDensity_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableLocationHighAccuracy(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetDpiWrapper_t::name[];
+constexpr char GeckoAppShell::GetDpiWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocationHighAccuracy, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+int32_t GeckoAppShell::GetDpiWrapper()
+{
+    return mozilla::jni::Method<GetDpiWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::EnableNetworkNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetExtensionFromMimeTypeWrapper_t::name[];
+constexpr char GeckoAppShell::GetExtensionFromMimeTypeWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableNetworkNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoAppShell::GetExtensionFromMimeTypeWrapper(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetExtensionFromMimeTypeWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::EnableScreenOrientationNotifications() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetExternalPublicDirectory_t::name[];
+constexpr char GeckoAppShell::GetExternalPublicDirectory_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableScreenOrientationNotifications);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::EnableSensor(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableSensor, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoAppShell::GetExternalPublicDirectory(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetExternalPublicDirectory_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::GamepadAdded(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetHandlersForMimeTypeWrapper_t::name[];
+constexpr char GeckoAppShell::GetHandlersForMimeTypeWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jGamepadAdded, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::ObjectArray::LocalRef GeckoAppShell::GetHandlersForMimeTypeWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<GetHandlersForMimeTypeWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jobject GeckoAppShell::GetConnection(const nsACString& a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+constexpr char GeckoAppShell::GetHandlersForURLWrapper_t::name[];
+constexpr char GeckoAppShell::GetHandlersForURLWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetConnection, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-
-jobject GeckoAppShell::GetContext() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetContext);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::ObjectArray::LocalRef GeckoAppShell::GetHandlersForURLWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<GetHandlersForURLWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jdoubleArray GeckoAppShell::GetCurrentBatteryInformationWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetIconForExtensionWrapper_t::name[];
+constexpr char GeckoAppShell::GetIconForExtensionWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentBatteryInformationWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jdoubleArray ret = static_cast<jdoubleArray>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::ByteArray::LocalRef GeckoAppShell::GetIconForExtensionWrapper(mozilla::jni::String::Param a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetIconForExtensionWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jdoubleArray GeckoAppShell::GetCurrentNetworkInformationWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetMessageWrapper_t::name[];
+constexpr char GeckoAppShell::GetMessageWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentNetworkInformationWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jdoubleArray ret = static_cast<jdoubleArray>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::GetMessageWrapper(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetMessageWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jfloat GeckoAppShell::GetDensity() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetMimeTypeFromExtensionsWrapper_t::name[];
+constexpr char GeckoAppShell::GetMimeTypeFromExtensionsWrapper_t::signature[];
 
-    jfloat temp = env->CallStaticFloatMethod(mGeckoAppShellClass, jGetDensity);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+mozilla::jni::String::LocalRef GeckoAppShell::GetMimeTypeFromExtensionsWrapper(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<GetMimeTypeFromExtensionsWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-int32_t GeckoAppShell::GetDpiWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetNextMessageInListWrapper_t::name[];
+constexpr char GeckoAppShell::GetNextMessageInListWrapper_t::signature[];
 
-    int32_t temp = env->CallStaticIntMethod(mGeckoAppShellClass, jGetDpiWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::GetNextMessageInListWrapper(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetNextMessageInListWrapper_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jstring GeckoAppShell::GetExtensionFromMimeTypeWrapper(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+constexpr char GeckoAppShell::GetProxyForURIWrapper_t::name[];
+constexpr char GeckoAppShell::GetProxyForURIWrapper_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetExtensionFromMimeTypeWrapper, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
-}
-
-jstring GeckoAppShell::GetExternalPublicDirectory(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetExternalPublicDirectory, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::String::LocalRef GeckoAppShell::GetProxyForURIWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, int32_t a3)
+{
+    return mozilla::jni::Method<GetProxyForURIWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-jobjectArray GeckoAppShell::GetHandlersForMimeTypeWrapper(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetScreenDepthWrapper_t::name[];
+constexpr char GeckoAppShell::GetScreenDepthWrapper_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForMimeTypeWrapper, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
-    return ret;
+int32_t GeckoAppShell::GetScreenDepthWrapper()
+{
+    return mozilla::jni::Method<GetScreenDepthWrapper_t>::Call(nullptr, nullptr);
 }
 
-jobjectArray GeckoAppShell::GetHandlersForURLWrapper(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetScreenOrientationWrapper_t::name[];
+constexpr char GeckoAppShell::GetScreenOrientationWrapper_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
+int16_t GeckoAppShell::GetScreenOrientationWrapper()
+{
+    return mozilla::jni::Method<GetScreenOrientationWrapper_t>::Call(nullptr, nullptr);
+}
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForURLWrapper, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    jobjectArray ret = static_cast<jobjectArray>(env->PopLocalFrame(temp));
-    return ret;
+constexpr char GeckoAppShell::GetShowPasswordSetting_t::name[];
+constexpr char GeckoAppShell::GetShowPasswordSetting_t::signature[];
+
+bool GeckoAppShell::GetShowPasswordSetting()
+{
+    return mozilla::jni::Method<GetShowPasswordSetting_t>::Call(nullptr, nullptr);
 }
 
-jbyteArray GeckoAppShell::GetIconForExtensionWrapper(const nsAString& a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::GetSystemColoursWrapper_t::name[];
+constexpr char GeckoAppShell::GetSystemColoursWrapper_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetIconForExtensionWrapper, j0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    jbyteArray ret = static_cast<jbyteArray>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::IntArray::LocalRef GeckoAppShell::GetSystemColoursWrapper()
+{
+    return mozilla::jni::Method<GetSystemColoursWrapper_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::GetMessageWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::HandleGeckoMessageWrapper_t::name[];
+constexpr char GeckoAppShell::HandleGeckoMessageWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jGetMessageWrapper, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::HandleGeckoMessageWrapper(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<HandleGeckoMessageWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-jstring GeckoAppShell::GetMimeTypeFromExtensionsWrapper(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::HandleUncaughtException_t::name[];
+constexpr char GeckoAppShell::HandleUncaughtException_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetMimeTypeFromExtensionsWrapper, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::HandleUncaughtException(mozilla::jni::Object::Param a0, mozilla::jni::Throwable::Param a1)
+{
+    return mozilla::jni::Method<HandleUncaughtException_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::GetNextMessageInListWrapper(int32_t a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::HideProgressDialog_t::name[];
+constexpr char GeckoAppShell::HideProgressDialog_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jGetNextMessageInListWrapper, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::HideProgressDialog()
+{
+    return mozilla::jni::Method<HideProgressDialog_t>::Call(nullptr, nullptr);
 }
 
-jstring GeckoAppShell::GetProxyForURIWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, int32_t a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(4) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::InitCameraWrapper_t::name[];
+constexpr char GeckoAppShell::InitCameraWrapper_t::signature[];
 
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].i = a3;
-
-    jobject temp = env->CallStaticObjectMethodA(mGeckoAppShellClass, jGetProxyForURIWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::IntArray::LocalRef GeckoAppShell::InitCameraWrapper(mozilla::jni::String::Param a0, int32_t a1, int32_t a2, int32_t a3)
+{
+    return mozilla::jni::Method<InitCameraWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-int32_t GeckoAppShell::GetScreenDepthWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::IsNetworkLinkKnown_t::name[];
+constexpr char GeckoAppShell::IsNetworkLinkKnown_t::signature[];
 
-    int32_t temp = env->CallStaticIntMethod(mGeckoAppShellClass, jGetScreenDepthWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+bool GeckoAppShell::IsNetworkLinkKnown()
+{
+    return mozilla::jni::Method<IsNetworkLinkKnown_t>::Call(nullptr, nullptr);
 }
 
-int16_t GeckoAppShell::GetScreenOrientationWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::IsNetworkLinkUp_t::name[];
+constexpr char GeckoAppShell::IsNetworkLinkUp_t::signature[];
 
-    int16_t temp = env->CallStaticShortMethod(mGeckoAppShellClass, jGetScreenOrientationWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+bool GeckoAppShell::IsNetworkLinkUp()
+{
+    return mozilla::jni::Method<IsNetworkLinkUp_t>::Call(nullptr, nullptr);
 }
 
-bool GeckoAppShell::GetShowPasswordSetting() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::IsTablet_t::name[];
+constexpr char GeckoAppShell::IsTablet_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jGetShowPasswordSetting);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+bool GeckoAppShell::IsTablet()
+{
+    return mozilla::jni::Method<IsTablet_t>::Call(nullptr, nullptr);
 }
 
-jintArray GeckoAppShell::GetSystemColoursWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::KillAnyZombies_t::name[];
+constexpr char GeckoAppShell::KillAnyZombies_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetSystemColoursWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jintArray ret = static_cast<jintArray>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::KillAnyZombies()
+{
+    return mozilla::jni::Method<KillAnyZombies_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::HandleGeckoMessageWrapper(jobject a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::LoadPluginClass_t::name[];
+constexpr char GeckoAppShell::LoadPluginClass_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jHandleGeckoMessageWrapper, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::HandleUncaughtException(jobject a0, jthrowable a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(2) != 0) {
-        return;
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jHandleUncaughtException, a0, a1);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::ClassObject::LocalRef GeckoAppShell::LoadPluginClass(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<LoadPluginClass_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::HideProgressDialog() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::LockScreenOrientation_t::name[];
+constexpr char GeckoAppShell::LockScreenOrientation_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::LockScreenOrientation(int32_t a0)
+{
+    return mozilla::jni::Method<LockScreenOrientation_t>::Call(nullptr, nullptr, a0);
 }
 
-jintArray GeckoAppShell::InitCameraWrapper(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::MarkURIVisited_t::name[];
+constexpr char GeckoAppShell::MarkURIVisited_t::signature[];
 
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-
-    jobject temp = env->CallStaticObjectMethodA(mGeckoAppShellClass, jInitCameraWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jintArray ret = static_cast<jintArray>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoAppShell::MarkURIVisited(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<MarkURIVisited_t>::Call(nullptr, nullptr, a0);
 }
 
-bool GeckoAppShell::IsNetworkLinkKnown() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::MoveTaskToBack_t::name[];
+constexpr char GeckoAppShell::MoveTaskToBack_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkKnown);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::MoveTaskToBack()
+{
+    return mozilla::jni::Method<MoveTaskToBack_t>::Call(nullptr, nullptr);
 }
 
-bool GeckoAppShell::IsNetworkLinkUp() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NetworkLinkType_t::name[];
+constexpr char GeckoAppShell::NetworkLinkType_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkUp);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+int32_t GeckoAppShell::NetworkLinkType()
+{
+    return mozilla::jni::Method<NetworkLinkType_t>::Call(nullptr, nullptr);
 }
 
-bool GeckoAppShell::IsTablet() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyDefaultPrevented_t::name[];
+constexpr char GeckoAppShell::NotifyDefaultPrevented_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::NotifyDefaultPrevented(bool a0)
+{
+    return mozilla::jni::Method<NotifyDefaultPrevented_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::KillAnyZombies() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyIME_t::name[];
+constexpr char GeckoAppShell::NotifyIME_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jKillAnyZombies);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyIME(int32_t a0)
+{
+    return mozilla::jni::Method<NotifyIME_t>::Call(nullptr, nullptr, a0);
 }
 
-jclass GeckoAppShell::LoadPluginClass(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
+constexpr char GeckoAppShell::NotifyIMEChange_t::name[];
+constexpr char GeckoAppShell::NotifyIMEChange_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mGeckoAppShellClass, jLoadPluginClass, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    jclass ret = static_cast<jclass>(env->PopLocalFrame(temp));
-    return ret;
-}
-
-void GeckoAppShell::LockScreenOrientation(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jLockScreenOrientation, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyIMEChange(mozilla::jni::String::Param a0, int32_t a1, int32_t a2, int32_t a3)
+{
+    return mozilla::jni::Method<NotifyIMEChange_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-void GeckoAppShell::MarkURIVisited(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyIMEContext_t::name[];
+constexpr char GeckoAppShell::NotifyIMEContext_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jMarkURIVisited, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyIMEContext(int32_t a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3)
+{
+    return mozilla::jni::Method<NotifyIMEContext_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-void GeckoAppShell::MoveTaskToBack() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyWakeLockChanged_t::name[];
+constexpr char GeckoAppShell::NotifyWakeLockChanged_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jMoveTaskToBack);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::NotifyWakeLockChanged(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<NotifyWakeLockChanged_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-int32_t GeckoAppShell::NetworkLinkType() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::NotifyXreExit_t::name[];
+constexpr char GeckoAppShell::NotifyXreExit_t::signature[];
 
-    int32_t temp = env->CallStaticIntMethod(mGeckoAppShellClass, jNetworkLinkType);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::NotifyXreExit()
+{
+    return mozilla::jni::Method<NotifyXreExit_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::NotifyDefaultPrevented(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::OpenUriExternal_t::name[];
+constexpr char GeckoAppShell::OpenUriExternal_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyDefaultPrevented, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool GeckoAppShell::OpenUriExternal(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3, mozilla::jni::String::Param a4, mozilla::jni::String::Param a5)
+{
+    return mozilla::jni::Method<OpenUriExternal_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5);
 }
 
-void GeckoAppShell::NotifyIME(int32_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyIME, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char GeckoAppShell::PerformHapticFeedback_t::name[];
+constexpr char GeckoAppShell::PerformHapticFeedback_t::signature[];
 
-void GeckoAppShell::NotifyIMEChange(const nsAString& a0, int32_t a1, int32_t a2, int32_t a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[4];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jNotifyIMEChange, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::PerformHapticFeedback(bool a0)
+{
+    return mozilla::jni::Method<PerformHapticFeedback_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::NotifyIMEContext(int32_t a0, const nsAString& a1, const nsAString& a2, const nsAString& a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(3) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::PumpMessageLoop_t::name[];
+constexpr char GeckoAppShell::PumpMessageLoop_t::signature[];
 
-    jvalue args[4];
-    args[0].i = a0;
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jNotifyIMEContext, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool GeckoAppShell::PumpMessageLoop()
+{
+    return mozilla::jni::Method<PumpMessageLoop_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::NotifyWakeLockChanged(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::RegisterSurfaceTextureFrameListener_t::name[];
+constexpr char GeckoAppShell::RegisterSurfaceTextureFrameListener_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyWakeLockChanged, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::RegisterSurfaceTextureFrameListener(mozilla::jni::Object::Param a0, int32_t a1)
+{
+    return mozilla::jni::Method<RegisterSurfaceTextureFrameListener_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::NotifyXreExit() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::RemovePluginView_t::name[];
+constexpr char GeckoAppShell::RemovePluginView_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::RemovePluginView(mozilla::jni::Object::Param a0, bool a1)
+{
+    return mozilla::jni::Method<RemovePluginView_t>::Call(nullptr, nullptr, a0, a1);
+}
+
+constexpr char GeckoAppShell::RequestUiThreadCallback_t::name[];
+constexpr char GeckoAppShell::RequestUiThreadCallback_t::signature[];
+
+void GeckoAppShell::RequestUiThreadCallback(int64_t a0)
+{
+    return mozilla::jni::Method<RequestUiThreadCallback_t>::Call(nullptr, nullptr, a0);
 }
 
-bool GeckoAppShell::OpenUriExternal(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4, const nsAString& a5) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(6) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::ScheduleRestart_t::name[];
+constexpr char GeckoAppShell::ScheduleRestart_t::signature[];
 
-    jvalue args[6];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-    args[4].l = AndroidBridge::NewJavaString(env, a4);
-    args[5].l = AndroidBridge::NewJavaString(env, a5);
-
-    bool temp = env->CallStaticBooleanMethodA(mGeckoAppShellClass, jOpenUriExternal, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::ScheduleRestart()
+{
+    return mozilla::jni::Method<ScheduleRestart_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::PerformHapticFeedback(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SendMessageWrapper_t::name[];
+constexpr char GeckoAppShell::SendMessageWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jPerformHapticFeedback, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::SendMessageWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, int32_t a2)
+{
+    return mozilla::jni::Method<SendMessageWrapper_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-bool GeckoAppShell::PumpMessageLoop() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SetFullScreen_t::name[];
+constexpr char GeckoAppShell::SetFullScreen_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jPumpMessageLoop);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+void GeckoAppShell::SetFullScreen(bool a0)
+{
+    return mozilla::jni::Method<SetFullScreen_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::RegisterSurfaceTextureFrameListener(jobject a0, int32_t a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SetKeepScreenOn_t::name[];
+constexpr char GeckoAppShell::SetKeepScreenOn_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jRegisterSurfaceTextureFrameListener, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::SetKeepScreenOn(bool a0)
+{
+    return mozilla::jni::Method<SetKeepScreenOn_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::RemovePluginView(jobject a0, bool a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::SetURITitle_t::name[];
+constexpr char GeckoAppShell::SetURITitle_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jRemovePluginView, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::RequestUiThreadCallback(int64_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jRequestUiThreadCallback, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::SetURITitle(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<SetURITitle_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::ScheduleRestart() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::ShowAlertNotificationWrapper_t::name[];
+constexpr char GeckoAppShell::ShowAlertNotificationWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jScheduleRestart);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::ShowAlertNotificationWrapper(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1, mozilla::jni::String::Param a2, mozilla::jni::String::Param a3, mozilla::jni::String::Param a4)
+{
+    return mozilla::jni::Method<ShowAlertNotificationWrapper_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4);
 }
 
-void GeckoAppShell::SendMessageWrapper(const nsAString& a0, const nsAString& a1, int32_t a2) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[3];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].i = a2;
+constexpr char GeckoAppShell::ShowInputMethodPicker_t::name[];
+constexpr char GeckoAppShell::ShowInputMethodPicker_t::signature[];
 
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jSendMessageWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-
-void GeckoAppShell::SetFullScreen(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetFullScreen, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::ShowInputMethodPicker()
+{
+    return mozilla::jni::Method<ShowInputMethodPicker_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::SetKeepScreenOn(bool a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::StartMonitoringGamepad_t::name[];
+constexpr char GeckoAppShell::StartMonitoringGamepad_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetKeepScreenOn, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::StartMonitoringGamepad()
+{
+    return mozilla::jni::Method<StartMonitoringGamepad_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::SetURITitle(const nsAString& a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::StopMonitoringGamepad_t::name[];
+constexpr char GeckoAppShell::StopMonitoringGamepad_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jSetURITitle, j0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::StopMonitoringGamepad()
+{
+    return mozilla::jni::Method<StopMonitoringGamepad_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::ShowAlertNotificationWrapper(const nsAString& a0, const nsAString& a1, const nsAString& a2, const nsAString& a3, const nsAString& a4) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(5) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::UnlockProfile_t::name[];
+constexpr char GeckoAppShell::UnlockProfile_t::signature[];
 
-    jvalue args[5];
-    args[0].l = AndroidBridge::NewJavaString(env, a0);
-    args[1].l = AndroidBridge::NewJavaString(env, a1);
-    args[2].l = AndroidBridge::NewJavaString(env, a2);
-    args[3].l = AndroidBridge::NewJavaString(env, a3);
-    args[4].l = AndroidBridge::NewJavaString(env, a4);
+bool GeckoAppShell::UnlockProfile()
+{
+    return mozilla::jni::Method<UnlockProfile_t>::Call(nullptr, nullptr);
+}
 
-    env->CallStaticVoidMethodA(mGeckoAppShellClass, jShowAlertNotificationWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+constexpr char GeckoAppShell::UnlockScreenOrientation_t::name[];
+constexpr char GeckoAppShell::UnlockScreenOrientation_t::signature[];
+
+void GeckoAppShell::UnlockScreenOrientation()
+{
+    return mozilla::jni::Method<UnlockScreenOrientation_t>::Call(nullptr, nullptr);
 }
 
-void GeckoAppShell::ShowInputMethodPicker() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::UnregisterSurfaceTextureFrameListener_t::name[];
+constexpr char GeckoAppShell::UnregisterSurfaceTextureFrameListener_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jShowInputMethodPicker);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::UnregisterSurfaceTextureFrameListener(mozilla::jni::Object::Param a0)
+{
+    return mozilla::jni::Method<UnregisterSurfaceTextureFrameListener_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::StartMonitoringGamepad() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::Vibrate1_t::name[];
+constexpr char GeckoAppShell::Vibrate1_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jStartMonitoringGamepad);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::Vibrate1(int64_t a0)
+{
+    return mozilla::jni::Method<Vibrate1_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::StopMonitoringGamepad() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoAppShell::VibrateA_t::name[];
+constexpr char GeckoAppShell::VibrateA_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jStopMonitoringGamepad);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoAppShell::VibrateA(mozilla::jni::LongArray::Param a0, int32_t a1)
+{
+    return mozilla::jni::Method<VibrateA_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-bool GeckoAppShell::UnlockProfile() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::name[];
 
-    bool temp = env->CallStaticBooleanMethod(mGeckoAppShellClass, jUnlockProfile);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
-}
+constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::name[];
+constexpr char GeckoJavaSampler::GetFrameNameJavaProfilingWrapper_t::signature[];
 
-void GeckoAppShell::UnlockScreenOrientation() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jUnlockScreenOrientation);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoJavaSampler::GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2)
+{
+    return mozilla::jni::Method<GetFrameNameJavaProfilingWrapper_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-void GeckoAppShell::UnregisterSurfaceTextureFrameListener(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::GetSampleTimeJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::GetSampleTimeJavaProfiling_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jUnregisterSurfaceTextureFrameListener, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+double GeckoJavaSampler::GetSampleTimeJavaProfiling(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<GetSampleTimeJavaProfiling_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoAppShell::Vibrate1(int64_t a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::GetThreadNameJavaProfilingWrapper_t::name[];
+constexpr char GeckoJavaSampler::GetThreadNameJavaProfilingWrapper_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrate1, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::String::LocalRef GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(int32_t a0)
+{
+    return mozilla::jni::Method<GetThreadNameJavaProfilingWrapper_t>::Call(nullptr, nullptr, a0);
 }
 
-void GeckoAppShell::VibrateA(jlongArray a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::PauseJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::PauseJavaProfiling_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoAppShellClass, jVibrateA, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass GeckoJavaSampler::mGeckoJavaSamplerClass = 0;
-jmethodID GeckoJavaSampler::jGetFrameNameJavaProfilingWrapper = 0;
-jmethodID GeckoJavaSampler::jGetSampleTimeJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jGetThreadNameJavaProfilingWrapper = 0;
-jmethodID GeckoJavaSampler::jPauseJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jStartJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jStopJavaProfiling = 0;
-jmethodID GeckoJavaSampler::jUnpauseJavaProfiling = 0;
-void GeckoJavaSampler::InitStubs(JNIEnv *env) {
-    mGeckoJavaSamplerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/GeckoJavaSampler");
-    jGetFrameNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getFrameName", "(III)Ljava/lang/String;");
-    jGetSampleTimeJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getSampleTime", "(II)D");
-    jGetThreadNameJavaProfilingWrapper = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "getThreadName", "(I)Ljava/lang/String;");
-    jPauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "pause", "()V");
-    jStartJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "start", "(II)V");
-    jStopJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "stop", "()V");
-    jUnpauseJavaProfiling = AndroidBridge::GetStaticMethodID(env, mGeckoJavaSamplerClass, "unpause", "()V");
+void GeckoJavaSampler::PauseJavaProfiling()
+{
+    return mozilla::jni::Method<PauseJavaProfiling_t>::Call(nullptr, nullptr);
 }
 
-GeckoJavaSampler* GeckoJavaSampler::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GeckoJavaSampler* ret = new GeckoJavaSampler(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char GeckoJavaSampler::StartJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::StartJavaProfiling_t::signature[];
+
+void GeckoJavaSampler::StartJavaProfiling(int32_t a0, int32_t a1)
+{
+    return mozilla::jni::Method<StartJavaProfiling_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-jstring GeckoJavaSampler::GetFrameNameJavaProfilingWrapper(int32_t a0, int32_t a1, int32_t a2) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::StopJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::StopJavaProfiling_t::signature[];
 
-    jvalue args[3];
-    args[0].i = a0;
-    args[1].i = a1;
-    args[2].i = a2;
-
-    jobject temp = env->CallStaticObjectMethodA(mGeckoJavaSamplerClass, jGetFrameNameJavaProfilingWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoJavaSampler::StopJavaProfiling()
+{
+    return mozilla::jni::Method<StopJavaProfiling_t>::Call(nullptr, nullptr);
 }
 
-jdouble GeckoJavaSampler::GetSampleTimeJavaProfiling(int32_t a0, int32_t a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoJavaSampler::UnpauseJavaProfiling_t::name[];
+constexpr char GeckoJavaSampler::UnpauseJavaProfiling_t::signature[];
 
-    jdouble temp = env->CallStaticDoubleMethod(mGeckoJavaSamplerClass, jGetSampleTimeJavaProfiling, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
-}
-
-jstring GeckoJavaSampler::GetThreadNameJavaProfilingWrapper(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jobject temp = env->CallStaticObjectMethod(mGeckoJavaSamplerClass, jGetThreadNameJavaProfilingWrapper, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoJavaSampler::UnpauseJavaProfiling()
+{
+    return mozilla::jni::Method<UnpauseJavaProfiling_t>::Call(nullptr, nullptr);
 }
 
-void GeckoJavaSampler::PauseJavaProfiling() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char RestrictedProfiles::name[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jPauseJavaProfiling);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+constexpr char RestrictedProfiles::GetUserRestrictions_t::name[];
+constexpr char RestrictedProfiles::GetUserRestrictions_t::signature[];
+
+mozilla::jni::String::LocalRef RestrictedProfiles::GetUserRestrictions()
+{
+    return mozilla::jni::Method<GetUserRestrictions_t>::Call(nullptr, nullptr);
 }
 
-void GeckoJavaSampler::StartJavaProfiling(int32_t a0, int32_t a1) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char RestrictedProfiles::IsAllowed_t::name[];
+constexpr char RestrictedProfiles::IsAllowed_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jStartJavaProfiling, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool RestrictedProfiles::IsAllowed(int32_t a0, mozilla::jni::String::Param a1)
+{
+    return mozilla::jni::Method<IsAllowed_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void GeckoJavaSampler::StopJavaProfiling() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char RestrictedProfiles::IsUserRestricted_t::name[];
+constexpr char RestrictedProfiles::IsUserRestricted_t::signature[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jStopJavaProfiling);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool RestrictedProfiles::IsUserRestricted()
+{
+    return mozilla::jni::Method<IsUserRestricted_t>::Call(nullptr, nullptr);
 }
 
-void GeckoJavaSampler::UnpauseJavaProfiling() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char SurfaceBits::name[];
 
-    env->CallStaticVoidMethod(mGeckoJavaSamplerClass, jUnpauseJavaProfiling);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass RestrictedProfiles::mRestrictedProfilesClass = 0;
-jmethodID RestrictedProfiles::jGetUserRestrictions = 0;
-jmethodID RestrictedProfiles::jIsAllowed = 0;
-jmethodID RestrictedProfiles::jIsUserRestricted = 0;
-void RestrictedProfiles::InitStubs(JNIEnv *env) {
-    mRestrictedProfilesClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/RestrictedProfiles");
-    jGetUserRestrictions = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "getUserRestrictions", "()Ljava/lang/String;");
-    jIsAllowed = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isAllowed", "(ILjava/lang/String;)Z");
-    jIsUserRestricted = AndroidBridge::GetStaticMethodID(env, mRestrictedProfilesClass, "isUserRestricted", "()Z");
+constexpr char SurfaceBits::New_t::name[];
+constexpr char SurfaceBits::New_t::signature[];
+
+SurfaceBits::LocalRef SurfaceBits::New()
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr);
 }
 
-RestrictedProfiles* RestrictedProfiles::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    RestrictedProfiles* ret = new RestrictedProfiles(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char SurfaceBits::Buffer_t::name[];
+constexpr char SurfaceBits::Buffer_t::signature[];
+
+mozilla::jni::Object::LocalRef SurfaceBits::Buffer() const
+{
+    return mozilla::jni::Field<Buffer_t>::Get(this, nullptr);
 }
 
-jstring RestrictedProfiles::GetUserRestrictions() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jobject temp = env->CallStaticObjectMethod(mRestrictedProfilesClass, jGetUserRestrictions);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void SurfaceBits::Buffer(mozilla::jni::Object::Param a0) const
+{
+    return mozilla::jni::Field<Buffer_t>::Set(this, nullptr, a0);
 }
 
-bool RestrictedProfiles::IsAllowed(int32_t a0, const nsAString& a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char SurfaceBits::Format_t::name[];
+constexpr char SurfaceBits::Format_t::signature[];
 
-    jstring j1 = AndroidBridge::NewJavaString(env, a1);
-
-    bool temp = env->CallStaticBooleanMethod(mRestrictedProfilesClass, jIsAllowed, a0, j1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+int32_t SurfaceBits::Format() const
+{
+    return mozilla::jni::Field<Format_t>::Get(this, nullptr);
 }
 
-bool RestrictedProfiles::IsUserRestricted() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    bool temp = env->CallStaticBooleanMethod(mRestrictedProfilesClass, jIsUserRestricted);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
-}
-jclass SurfaceBits::mSurfaceBitsClass = 0;
-jmethodID SurfaceBits::jSurfaceBits = 0;
-jfieldID SurfaceBits::jbuffer = 0;
-jfieldID SurfaceBits::jformat = 0;
-jfieldID SurfaceBits::jheight = 0;
-jfieldID SurfaceBits::jwidth = 0;
-void SurfaceBits::InitStubs(JNIEnv *env) {
-    mSurfaceBitsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/SurfaceBits");
-    jSurfaceBits = AndroidBridge::GetMethodID(env, mSurfaceBitsClass, "<init>", "()V");
-    jbuffer = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "buffer", "Ljava/nio/ByteBuffer;");
-    jformat = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "format", "I");
-    jheight = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "height", "I");
-    jwidth = AndroidBridge::GetFieldID(env, mSurfaceBitsClass, "width", "I");
+void SurfaceBits::Format(int32_t a0) const
+{
+    return mozilla::jni::Field<Format_t>::Set(this, nullptr, a0);
 }
 
-SurfaceBits* SurfaceBits::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    SurfaceBits* ret = new SurfaceBits(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char SurfaceBits::Height_t::name[];
+constexpr char SurfaceBits::Height_t::signature[];
+
+int32_t SurfaceBits::Height() const
+{
+    return mozilla::jni::Field<Height_t>::Get(this, nullptr);
 }
 
-SurfaceBits::SurfaceBits() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    Init(env->NewObject(mSurfaceBitsClass, jSurfaceBits), env);
-    env->PopLocalFrame(nullptr);
+void SurfaceBits::Height(int32_t a0) const
+{
+    return mozilla::jni::Field<Height_t>::Set(this, nullptr, a0);
 }
 
-jobject SurfaceBits::getbuffer() {
-    JNIEnv *env = GetJNIForThread();
-    return static_cast<jobject>(env->GetObjectField(wrapped_obj, jbuffer));
-}
+constexpr char SurfaceBits::Width_t::name[];
+constexpr char SurfaceBits::Width_t::signature[];
 
-void SurfaceBits::setbuffer(jobject a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetObjectField(wrapped_obj, jbuffer, a0);
+int32_t SurfaceBits::Width() const
+{
+    return mozilla::jni::Field<Width_t>::Get(this, nullptr);
 }
 
-int32_t SurfaceBits::getformat() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetIntField(wrapped_obj, jformat);
-}
-
-void SurfaceBits::setformat(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetIntField(wrapped_obj, jformat, a0);
-}
-
-int32_t SurfaceBits::getheight() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetIntField(wrapped_obj, jheight);
+void SurfaceBits::Width(int32_t a0) const
+{
+    return mozilla::jni::Field<Width_t>::Set(this, nullptr, a0);
 }
 
-void SurfaceBits::setheight(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetIntField(wrapped_obj, jheight, a0);
-}
+constexpr char ThumbnailHelper::name[];
 
-int32_t SurfaceBits::getwidth() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetIntField(wrapped_obj, jwidth);
+constexpr char ThumbnailHelper::SendThumbnail_t::name[];
+constexpr char ThumbnailHelper::SendThumbnail_t::signature[];
+
+void ThumbnailHelper::SendThumbnail(mozilla::jni::Object::Param a0, int32_t a1, bool a2, bool a3)
+{
+    return mozilla::jni::Method<SendThumbnail_t>::Call(nullptr, nullptr, a0, a1, a2, a3);
 }
 
-void SurfaceBits::setwidth(int32_t a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetIntField(wrapped_obj, jwidth, a0);
-}
-jclass ThumbnailHelper::mThumbnailHelperClass = 0;
-jmethodID ThumbnailHelper::jSendThumbnail = 0;
-void ThumbnailHelper::InitStubs(JNIEnv *env) {
-    mThumbnailHelperClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/ThumbnailHelper");
-    jSendThumbnail = AndroidBridge::GetStaticMethodID(env, mThumbnailHelperClass, "notifyThumbnail", "(Ljava/nio/ByteBuffer;IZZ)V");
-}
+constexpr char DisplayPortMetrics::name[];
 
-ThumbnailHelper* ThumbnailHelper::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ThumbnailHelper* ret = new ThumbnailHelper(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char DisplayPortMetrics::New_t::name[];
+constexpr char DisplayPortMetrics::New_t::signature[];
+
+DisplayPortMetrics::LocalRef DisplayPortMetrics::New(float a0, float a1, float a2, float a3, float a4)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4);
 }
 
-void ThumbnailHelper::SendThumbnail(jobject a0, int32_t a1, bool a2, bool a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[4];
-    args[0].l = a0;
-    args[1].i = a1;
-    args[2].z = a2;
-    args[3].z = a3;
+constexpr char DisplayPortMetrics::MPosition_t::name[];
+constexpr char DisplayPortMetrics::MPosition_t::signature[];
 
-    env->CallStaticVoidMethodA(mThumbnailHelperClass, jSendThumbnail, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass DisplayPortMetrics::mDisplayPortMetricsClass = 0;
-jmethodID DisplayPortMetrics::jDisplayPortMetrics = 0;
-jfieldID DisplayPortMetrics::jMPosition = 0;
-jfieldID DisplayPortMetrics::jResolution = 0;
-void DisplayPortMetrics::InitStubs(JNIEnv *env) {
-    mDisplayPortMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/DisplayPortMetrics");
-    jDisplayPortMetrics = AndroidBridge::GetMethodID(env, mDisplayPortMetricsClass, "<init>", "(FFFFF)V");
-    jMPosition = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "mPosition", "Landroid/graphics/RectF;");
-    jResolution = AndroidBridge::GetFieldID(env, mDisplayPortMetricsClass, "resolution", "F");
+mozilla::jni::Object::LocalRef DisplayPortMetrics::MPosition() const
+{
+    return mozilla::jni::Field<MPosition_t>::Get(this, nullptr);
 }
 
-DisplayPortMetrics* DisplayPortMetrics::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    DisplayPortMetrics* ret = new DisplayPortMetrics(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char DisplayPortMetrics::Resolution_t::name[];
+constexpr char DisplayPortMetrics::Resolution_t::signature[];
+
+float DisplayPortMetrics::Resolution() const
+{
+    return mozilla::jni::Field<Resolution_t>::Get(this, nullptr);
 }
 
-DisplayPortMetrics::DisplayPortMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GLController::name[];
 
-    jvalue args[5];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
+constexpr char GLController::CreateEGLSurfaceForCompositorWrapper_t::name[];
+constexpr char GLController::CreateEGLSurfaceForCompositorWrapper_t::signature[];
 
-    Init(env->NewObjectA(mDisplayPortMetricsClass, jDisplayPortMetrics, args), env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GLController::CreateEGLSurfaceForCompositorWrapper() const
+{
+    return mozilla::jni::Method<CreateEGLSurfaceForCompositorWrapper_t>::Call(this, nullptr);
 }
 
-jobject DisplayPortMetrics::getMPosition() {
-    JNIEnv *env = GetJNIForThread();
-    return static_cast<jobject>(env->GetObjectField(wrapped_obj, jMPosition));
+constexpr char GeckoLayerClient::name[];
+
+constexpr char GeckoLayerClient::ActivateProgram_t::name[];
+constexpr char GeckoLayerClient::ActivateProgram_t::signature[];
+
+void GeckoLayerClient::ActivateProgram() const
+{
+    return mozilla::jni::Method<ActivateProgram_t>::Call(this, nullptr);
 }
 
-jfloat DisplayPortMetrics::getResolution() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jResolution);
-}
-jclass GLController::mGLControllerClass = 0;
-jmethodID GLController::jCreateEGLSurfaceForCompositorWrapper = 0;
-void GLController::InitStubs(JNIEnv *env) {
-    mGLControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GLController");
-    jCreateEGLSurfaceForCompositorWrapper = AndroidBridge::GetMethodID(env, mGLControllerClass, "createEGLSurfaceForCompositor", "()Ljavax/microedition/khronos/egl/EGLSurface;");
-}
+constexpr char GeckoLayerClient::ContentDocumentChanged_t::name[];
+constexpr char GeckoLayerClient::ContentDocumentChanged_t::signature[];
 
-GLController* GLController::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GLController* ret = new GLController(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void GeckoLayerClient::ContentDocumentChanged() const
+{
+    return mozilla::jni::Method<ContentDocumentChanged_t>::Call(this, nullptr);
 }
 
-jobject GLController::CreateEGLSurfaceForCompositorWrapper() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::CreateFrame_t::name[];
+constexpr char GeckoLayerClient::CreateFrame_t::signature[];
 
-    jobject temp = env->CallObjectMethod(wrapped_obj, jCreateEGLSurfaceForCompositorWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::Object::LocalRef GeckoLayerClient::CreateFrame() const
+{
+    return mozilla::jni::Method<CreateFrame_t>::Call(this, nullptr);
 }
-jclass GeckoLayerClient::mGeckoLayerClientClass = 0;
-jmethodID GeckoLayerClient::jActivateProgram = 0;
-jmethodID GeckoLayerClient::jContentDocumentChanged = 0;
-jmethodID GeckoLayerClient::jCreateFrame = 0;
-jmethodID GeckoLayerClient::jDeactivateProgramAndRestoreState = 0;
-jmethodID GeckoLayerClient::jGetDisplayPort = 0;
-jmethodID GeckoLayerClient::jIsContentDocumentDisplayed = 0;
-jmethodID GeckoLayerClient::jProgressiveUpdateCallback = 0;
-jmethodID GeckoLayerClient::jSetFirstPaintViewport = 0;
-jmethodID GeckoLayerClient::jSetPageRect = 0;
-jmethodID GeckoLayerClient::jSyncFrameMetrics = 0;
-jmethodID GeckoLayerClient::jSyncViewportInfo = 0;
-void GeckoLayerClient::InitStubs(JNIEnv *env) {
-    mGeckoLayerClientClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/GeckoLayerClient");
-    jActivateProgram = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "activateProgram", "()V");
-    jContentDocumentChanged = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "contentDocumentChanged", "()V");
-    jCreateFrame = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "createFrame", "()Lorg/mozilla/gecko/gfx/LayerRenderer$Frame;");
-    jDeactivateProgramAndRestoreState = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "deactivateProgramAndRestoreState", "(ZIIII)V");
-    jGetDisplayPort = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "getDisplayPort", "(ZZILorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)Lorg/mozilla/gecko/gfx/DisplayPortMetrics;");
-    jIsContentDocumentDisplayed = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "isContentDocumentDisplayed", "()Z");
-    jProgressiveUpdateCallback = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "progressiveUpdateCallback", "(ZFFFFFZ)Lorg/mozilla/gecko/gfx/ProgressiveUpdateData;");
-    jSetFirstPaintViewport = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setFirstPaintViewport", "(FFFFFFF)V");
-    jSetPageRect = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "setPageRect", "(FFFF)V");
-    jSyncFrameMetrics = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncFrameMetrics", "(FFFFFFFZIIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
-    jSyncViewportInfo = AndroidBridge::GetMethodID(env, mGeckoLayerClientClass, "syncViewportInfo", "(IIIIFZ)Lorg/mozilla/gecko/gfx/ViewTransform;");
+
+constexpr char GeckoLayerClient::DeactivateProgramAndRestoreState_t::name[];
+constexpr char GeckoLayerClient::DeactivateProgramAndRestoreState_t::signature[];
+
+void GeckoLayerClient::DeactivateProgramAndRestoreState(bool a0, int32_t a1, int32_t a2, int32_t a3, int32_t a4) const
+{
+    return mozilla::jni::Method<DeactivateProgramAndRestoreState_t>::Call(this, nullptr, a0, a1, a2, a3, a4);
 }
 
-GeckoLayerClient* GeckoLayerClient::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    GeckoLayerClient* ret = new GeckoLayerClient(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char GeckoLayerClient::GetDisplayPort_t::name[];
+constexpr char GeckoLayerClient::GetDisplayPort_t::signature[];
 
-void GeckoLayerClient::ActivateProgram() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallVoidMethod(wrapped_obj, jActivateProgram);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef GeckoLayerClient::GetDisplayPort(bool a0, bool a1, int32_t a2, mozilla::jni::Object::Param a3) const
+{
+    return mozilla::jni::Method<GetDisplayPort_t>::Call(this, nullptr, a0, a1, a2, a3);
 }
 
-void GeckoLayerClient::ContentDocumentChanged() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::IsContentDocumentDisplayed_t::name[];
+constexpr char GeckoLayerClient::IsContentDocumentDisplayed_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jContentDocumentChanged);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool GeckoLayerClient::IsContentDocumentDisplayed() const
+{
+    return mozilla::jni::Method<IsContentDocumentDisplayed_t>::Call(this, nullptr);
 }
 
-jobject GeckoLayerClient::CreateFrame() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::ProgressiveUpdateCallback_t::name[];
+constexpr char GeckoLayerClient::ProgressiveUpdateCallback_t::signature[];
 
-    jobject temp = env->CallObjectMethod(wrapped_obj, jCreateFrame);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::Object::LocalRef GeckoLayerClient::ProgressiveUpdateCallback(bool a0, float a1, float a2, float a3, float a4, float a5, bool a6) const
+{
+    return mozilla::jni::Method<ProgressiveUpdateCallback_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5, a6);
 }
 
-void GeckoLayerClient::DeactivateProgramAndRestoreState(bool a0, int32_t a1, int32_t a2, int32_t a3, int32_t a4) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SetFirstPaintViewport_t::name[];
+constexpr char GeckoLayerClient::SetFirstPaintViewport_t::signature[];
 
-    jvalue args[5];
-    args[0].z = a0;
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-    args[4].i = a4;
-
-    env->CallVoidMethodA(wrapped_obj, jDeactivateProgramAndRestoreState, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void GeckoLayerClient::SetFirstPaintViewport(float a0, float a1, float a2, float a3, float a4, float a5, float a6) const
+{
+    return mozilla::jni::Method<SetFirstPaintViewport_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5, a6);
 }
 
-jobject GeckoLayerClient::GetDisplayPort(bool a0, bool a1, int32_t a2, jobject a3) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SetPageRect_t::name[];
+constexpr char GeckoLayerClient::SetPageRect_t::signature[];
 
-    jvalue args[4];
-    args[0].z = a0;
-    args[1].z = a1;
-    args[2].i = a2;
-    args[3].l = a3;
-
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jGetDisplayPort, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+void GeckoLayerClient::SetPageRect(float a0, float a1, float a2, float a3) const
+{
+    return mozilla::jni::Method<SetPageRect_t>::Call(this, nullptr, a0, a1, a2, a3);
 }
 
-bool GeckoLayerClient::IsContentDocumentDisplayed() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SyncFrameMetrics_t::name[];
+constexpr char GeckoLayerClient::SyncFrameMetrics_t::signature[];
 
-    bool temp = env->CallBooleanMethod(wrapped_obj, jIsContentDocumentDisplayed);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+mozilla::jni::Object::LocalRef GeckoLayerClient::SyncFrameMetrics(float a0, float a1, float a2, float a3, float a4, float a5, float a6, bool a7, int32_t a8, int32_t a9, int32_t a10, int32_t a11, float a12, bool a13) const
+{
+    return mozilla::jni::Method<SyncFrameMetrics_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13);
 }
 
-jobject GeckoLayerClient::ProgressiveUpdateCallback(bool a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, bool a6) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char GeckoLayerClient::SyncViewportInfo_t::name[];
+constexpr char GeckoLayerClient::SyncViewportInfo_t::signature[];
 
-    jvalue args[7];
-    args[0].z = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].z = a6;
-
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jProgressiveUpdateCallback, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+mozilla::jni::Object::LocalRef GeckoLayerClient::SyncViewportInfo(int32_t a0, int32_t a1, int32_t a2, int32_t a3, float a4, bool a5) const
+{
+    return mozilla::jni::Method<SyncViewportInfo_t>::Call(this, nullptr, a0, a1, a2, a3, a4, a5);
 }
 
-void GeckoLayerClient::SetFirstPaintViewport(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ImmutableViewportMetrics::name[];
 
-    jvalue args[7];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].f = a6;
+constexpr char ImmutableViewportMetrics::New_t::name[];
+constexpr char ImmutableViewportMetrics::New_t::signature[];
 
-    env->CallVoidMethodA(wrapped_obj, jSetFirstPaintViewport, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+ImmutableViewportMetrics::LocalRef ImmutableViewportMetrics::New(float a0, float a1, float a2, float a3, float a4, float a5, float a6, float a7, float a8, float a9, float a10, float a11, float a12)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12);
 }
 
-void GeckoLayerClient::SetPageRect(jfloat a0, jfloat a1, jfloat a2, jfloat a3) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char LayerView::name[];
 
-    jvalue args[4];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
+constexpr char LayerView::RegisterCompositorWrapper_t::name[];
+constexpr char LayerView::RegisterCompositorWrapper_t::signature[];
 
-    env->CallVoidMethodA(wrapped_obj, jSetPageRect, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+mozilla::jni::Object::LocalRef LayerView::RegisterCompositorWrapper()
+{
+    return mozilla::jni::Method<RegisterCompositorWrapper_t>::Call(nullptr, nullptr);
 }
 
-jobject GeckoLayerClient::SyncFrameMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, bool a7, int32_t a8, int32_t a9, int32_t a10, int32_t a11, jfloat a12, bool a13) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char NativePanZoomController::name[];
+
+constexpr char NativePanZoomController::RequestContentRepaintWrapper_t::name[];
+constexpr char NativePanZoomController::RequestContentRepaintWrapper_t::signature[];
+
+void NativePanZoomController::RequestContentRepaintWrapper(float a0, float a1, float a2, float a3, float a4) const
+{
+    return mozilla::jni::Method<RequestContentRepaintWrapper_t>::Call(this, nullptr, a0, a1, a2, a3, a4);
+}
+
+constexpr char ProgressiveUpdateData::name[];
 
-    jvalue args[14];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].f = a6;
-    args[7].z = a7;
-    args[8].i = a8;
-    args[9].i = a9;
-    args[10].i = a10;
-    args[11].i = a11;
-    args[12].f = a12;
-    args[13].z = a13;
+constexpr char ProgressiveUpdateData::New_t::name[];
+constexpr char ProgressiveUpdateData::New_t::signature[];
 
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jSyncFrameMetrics, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
+ProgressiveUpdateData::LocalRef ProgressiveUpdateData::New()
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr);
+}
+
+constexpr char ProgressiveUpdateData::SetViewport_t::name[];
+constexpr char ProgressiveUpdateData::SetViewport_t::signature[];
+
+void ProgressiveUpdateData::SetViewport(mozilla::jni::Object::Param a0) const
+{
+    return mozilla::jni::Method<SetViewport_t>::Call(this, nullptr, a0);
 }
 
-jobject GeckoLayerClient::SyncViewportInfo(int32_t a0, int32_t a1, int32_t a2, int32_t a3, jfloat a4, bool a5) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ProgressiveUpdateData::Abort_t::name[];
+constexpr char ProgressiveUpdateData::Abort_t::signature[];
 
-    jvalue args[6];
-    args[0].i = a0;
-    args[1].i = a1;
-    args[2].i = a2;
-    args[3].i = a3;
-    args[4].f = a4;
-    args[5].z = a5;
-
-    jobject temp = env->CallObjectMethodA(wrapped_obj, jSyncViewportInfo, args);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-jclass ImmutableViewportMetrics::mImmutableViewportMetricsClass = 0;
-jmethodID ImmutableViewportMetrics::jImmutableViewportMetrics = 0;
-void ImmutableViewportMetrics::InitStubs(JNIEnv *env) {
-    mImmutableViewportMetricsClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ImmutableViewportMetrics");
-    jImmutableViewportMetrics = AndroidBridge::GetMethodID(env, mImmutableViewportMetricsClass, "<init>", "(FFFFFFFFFFFFF)V");
+bool ProgressiveUpdateData::Abort() const
+{
+    return mozilla::jni::Field<Abort_t>::Get(this, nullptr);
 }
 
-ImmutableViewportMetrics* ImmutableViewportMetrics::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ImmutableViewportMetrics* ret = new ImmutableViewportMetrics(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ProgressiveUpdateData::Abort(bool a0) const
+{
+    return mozilla::jni::Field<Abort_t>::Set(this, nullptr, a0);
 }
 
-ImmutableViewportMetrics::ImmutableViewportMetrics(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4, jfloat a5, jfloat a6, jfloat a7, jfloat a8, jfloat a9, jfloat a10, jfloat a11, jfloat a12) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ProgressiveUpdateData::Scale_t::name[];
+constexpr char ProgressiveUpdateData::Scale_t::signature[];
 
-    jvalue args[13];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
-    args[5].f = a5;
-    args[6].f = a6;
-    args[7].f = a7;
-    args[8].f = a8;
-    args[9].f = a9;
-    args[10].f = a10;
-    args[11].f = a11;
-    args[12].f = a12;
-
-    Init(env->NewObjectA(mImmutableViewportMetricsClass, jImmutableViewportMetrics, args), env);
-    env->PopLocalFrame(nullptr);
-}
-jclass LayerView::mLayerViewClass = 0;
-jmethodID LayerView::jRegisterCompositorWrapper = 0;
-void LayerView::InitStubs(JNIEnv *env) {
-    mLayerViewClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/LayerView");
-    jRegisterCompositorWrapper = AndroidBridge::GetStaticMethodID(env, mLayerViewClass, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;");
+float ProgressiveUpdateData::Scale() const
+{
+    return mozilla::jni::Field<Scale_t>::Get(this, nullptr);
 }
 
-LayerView* LayerView::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    LayerView* ret = new LayerView(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ProgressiveUpdateData::Scale(float a0) const
+{
+    return mozilla::jni::Field<Scale_t>::Set(this, nullptr, a0);
 }
 
-jobject LayerView::RegisterCompositorWrapper() {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ProgressiveUpdateData::X_t::name[];
+constexpr char ProgressiveUpdateData::X_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mLayerViewClass, jRegisterCompositorWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-jclass NativePanZoomController::mNativePanZoomControllerClass = 0;
-jmethodID NativePanZoomController::jRequestContentRepaintWrapper = 0;
-void NativePanZoomController::InitStubs(JNIEnv *env) {
-    mNativePanZoomControllerClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/NativePanZoomController");
-    jRequestContentRepaintWrapper = AndroidBridge::GetMethodID(env, mNativePanZoomControllerClass, "requestContentRepaint", "(FFFFF)V");
+float ProgressiveUpdateData::X() const
+{
+    return mozilla::jni::Field<X_t>::Get(this, nullptr);
 }
 
-NativePanZoomController* NativePanZoomController::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    NativePanZoomController* ret = new NativePanZoomController(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ProgressiveUpdateData::X(float a0) const
+{
+    return mozilla::jni::Field<X_t>::Set(this, nullptr, a0);
 }
 
-void NativePanZoomController::RequestContentRepaintWrapper(jfloat a0, jfloat a1, jfloat a2, jfloat a3, jfloat a4) {
-    JNIEnv *env = GetJNIForThread();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    jvalue args[5];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-    args[3].f = a3;
-    args[4].f = a4;
+constexpr char ProgressiveUpdateData::Y_t::name[];
+constexpr char ProgressiveUpdateData::Y_t::signature[];
 
-    env->CallVoidMethodA(wrapped_obj, jRequestContentRepaintWrapper, args);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+float ProgressiveUpdateData::Y() const
+{
+    return mozilla::jni::Field<Y_t>::Get(this, nullptr);
 }
-jclass ProgressiveUpdateData::mProgressiveUpdateDataClass = 0;
-jmethodID ProgressiveUpdateData::jProgressiveUpdateData = 0;
-jmethodID ProgressiveUpdateData::jsetViewport = 0;
-jfieldID ProgressiveUpdateData::jabort = 0;
-jfieldID ProgressiveUpdateData::jscale = 0;
-jfieldID ProgressiveUpdateData::jx = 0;
-jfieldID ProgressiveUpdateData::jy = 0;
-void ProgressiveUpdateData::InitStubs(JNIEnv *env) {
-    mProgressiveUpdateDataClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ProgressiveUpdateData");
-    jProgressiveUpdateData = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "<init>", "()V");
-    jsetViewport = AndroidBridge::GetMethodID(env, mProgressiveUpdateDataClass, "setViewport", "(Lorg/mozilla/gecko/gfx/ImmutableViewportMetrics;)V");
-    jabort = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "abort", "Z");
-    jscale = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "scale", "F");
-    jx = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "x", "F");
-    jy = AndroidBridge::GetFieldID(env, mProgressiveUpdateDataClass, "y", "F");
+
+void ProgressiveUpdateData::Y(float a0) const
+{
+    return mozilla::jni::Field<Y_t>::Set(this, nullptr, a0);
 }
 
-ProgressiveUpdateData* ProgressiveUpdateData::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ProgressiveUpdateData* ret = new ProgressiveUpdateData(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char ViewTransform::name[];
 
-ProgressiveUpdateData::ProgressiveUpdateData() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ViewTransform::New_t::name[];
+constexpr char ViewTransform::New_t::signature[];
 
-    Init(env->NewObject(mProgressiveUpdateDataClass, jProgressiveUpdateData), env);
-    env->PopLocalFrame(nullptr);
+ViewTransform::LocalRef ViewTransform::New(float a0, float a1, float a2)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0, a1, a2);
 }
 
-void ProgressiveUpdateData::setViewport(jobject a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ViewTransform::FixedLayerMarginBottom_t::name[];
+constexpr char ViewTransform::FixedLayerMarginBottom_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jsetViewport, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+float ViewTransform::FixedLayerMarginBottom() const
+{
+    return mozilla::jni::Field<FixedLayerMarginBottom_t>::Get(this, nullptr);
 }
 
-bool ProgressiveUpdateData::getabort() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetBooleanField(wrapped_obj, jabort);
-}
-
-void ProgressiveUpdateData::setabort(bool a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetBooleanField(wrapped_obj, jabort, a0);
-}
-
-jfloat ProgressiveUpdateData::getscale() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jscale);
+void ViewTransform::FixedLayerMarginBottom(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginBottom_t>::Set(this, nullptr, a0);
 }
 
-void ProgressiveUpdateData::setscale(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jscale, a0);
+constexpr char ViewTransform::FixedLayerMarginLeft_t::name[];
+constexpr char ViewTransform::FixedLayerMarginLeft_t::signature[];
+
+float ViewTransform::FixedLayerMarginLeft() const
+{
+    return mozilla::jni::Field<FixedLayerMarginLeft_t>::Get(this, nullptr);
 }
 
-jfloat ProgressiveUpdateData::getx() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jx);
+void ViewTransform::FixedLayerMarginLeft(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginLeft_t>::Set(this, nullptr, a0);
 }
 
-void ProgressiveUpdateData::setx(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jx, a0);
-}
+constexpr char ViewTransform::FixedLayerMarginRight_t::name[];
+constexpr char ViewTransform::FixedLayerMarginRight_t::signature[];
 
-jfloat ProgressiveUpdateData::gety() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jy);
+float ViewTransform::FixedLayerMarginRight() const
+{
+    return mozilla::jni::Field<FixedLayerMarginRight_t>::Get(this, nullptr);
 }
 
-void ProgressiveUpdateData::sety(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jy, a0);
+void ViewTransform::FixedLayerMarginRight(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginRight_t>::Set(this, nullptr, a0);
 }
-jclass ViewTransform::mViewTransformClass = 0;
-jmethodID ViewTransform::jViewTransform = 0;
-jfieldID ViewTransform::jfixedLayerMarginBottom = 0;
-jfieldID ViewTransform::jfixedLayerMarginLeft = 0;
-jfieldID ViewTransform::jfixedLayerMarginRight = 0;
-jfieldID ViewTransform::jfixedLayerMarginTop = 0;
-jfieldID ViewTransform::joffsetX = 0;
-jfieldID ViewTransform::joffsetY = 0;
-jfieldID ViewTransform::jscale = 0;
-jfieldID ViewTransform::jx = 0;
-jfieldID ViewTransform::jy = 0;
-void ViewTransform::InitStubs(JNIEnv *env) {
-    mViewTransformClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/gfx/ViewTransform");
-    jViewTransform = AndroidBridge::GetMethodID(env, mViewTransformClass, "<init>", "(FFF)V");
-    jfixedLayerMarginBottom = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginBottom", "F");
-    jfixedLayerMarginLeft = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginLeft", "F");
-    jfixedLayerMarginRight = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginRight", "F");
-    jfixedLayerMarginTop = AndroidBridge::GetFieldID(env, mViewTransformClass, "fixedLayerMarginTop", "F");
-    joffsetX = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetX", "F");
-    joffsetY = AndroidBridge::GetFieldID(env, mViewTransformClass, "offsetY", "F");
-    jscale = AndroidBridge::GetFieldID(env, mViewTransformClass, "scale", "F");
-    jx = AndroidBridge::GetFieldID(env, mViewTransformClass, "x", "F");
-    jy = AndroidBridge::GetFieldID(env, mViewTransformClass, "y", "F");
+
+constexpr char ViewTransform::FixedLayerMarginTop_t::name[];
+constexpr char ViewTransform::FixedLayerMarginTop_t::signature[];
+
+float ViewTransform::FixedLayerMarginTop() const
+{
+    return mozilla::jni::Field<FixedLayerMarginTop_t>::Get(this, nullptr);
 }
 
-ViewTransform* ViewTransform::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    ViewTransform* ret = new ViewTransform(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ViewTransform::FixedLayerMarginTop(float a0) const
+{
+    return mozilla::jni::Field<FixedLayerMarginTop_t>::Set(this, nullptr, a0);
 }
 
-ViewTransform::ViewTransform(jfloat a0, jfloat a1, jfloat a2) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char ViewTransform::OffsetX_t::name[];
+constexpr char ViewTransform::OffsetX_t::signature[];
 
-    jvalue args[3];
-    args[0].f = a0;
-    args[1].f = a1;
-    args[2].f = a2;
-
-    Init(env->NewObjectA(mViewTransformClass, jViewTransform, args), env);
-    env->PopLocalFrame(nullptr);
+float ViewTransform::OffsetX() const
+{
+    return mozilla::jni::Field<OffsetX_t>::Get(this, nullptr);
 }
 
-jfloat ViewTransform::getfixedLayerMarginBottom() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginBottom);
-}
-
-void ViewTransform::setfixedLayerMarginBottom(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginBottom, a0);
-}
-
-jfloat ViewTransform::getfixedLayerMarginLeft() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginLeft);
+void ViewTransform::OffsetX(float a0) const
+{
+    return mozilla::jni::Field<OffsetX_t>::Set(this, nullptr, a0);
 }
 
-void ViewTransform::setfixedLayerMarginLeft(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginLeft, a0);
-}
+constexpr char ViewTransform::OffsetY_t::name[];
+constexpr char ViewTransform::OffsetY_t::signature[];
 
-jfloat ViewTransform::getfixedLayerMarginRight() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginRight);
+float ViewTransform::OffsetY() const
+{
+    return mozilla::jni::Field<OffsetY_t>::Get(this, nullptr);
 }
 
-void ViewTransform::setfixedLayerMarginRight(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginRight, a0);
-}
-
-jfloat ViewTransform::getfixedLayerMarginTop() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jfixedLayerMarginTop);
-}
-
-void ViewTransform::setfixedLayerMarginTop(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jfixedLayerMarginTop, a0);
-}
-
-jfloat ViewTransform::getoffsetX() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, joffsetX);
+void ViewTransform::OffsetY(float a0) const
+{
+    return mozilla::jni::Field<OffsetY_t>::Set(this, nullptr, a0);
 }
 
-void ViewTransform::setoffsetX(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, joffsetX, a0);
-}
+constexpr char ViewTransform::Scale_t::name[];
+constexpr char ViewTransform::Scale_t::signature[];
 
-jfloat ViewTransform::getoffsetY() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, joffsetY);
-}
-
-void ViewTransform::setoffsetY(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, joffsetY, a0);
+float ViewTransform::Scale() const
+{
+    return mozilla::jni::Field<Scale_t>::Get(this, nullptr);
 }
 
-jfloat ViewTransform::getscale() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jscale);
-}
-
-void ViewTransform::setscale(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jscale, a0);
+void ViewTransform::Scale(float a0) const
+{
+    return mozilla::jni::Field<Scale_t>::Set(this, nullptr, a0);
 }
 
-jfloat ViewTransform::getx() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jx);
+constexpr char ViewTransform::X_t::name[];
+constexpr char ViewTransform::X_t::signature[];
+
+float ViewTransform::X() const
+{
+    return mozilla::jni::Field<X_t>::Get(this, nullptr);
 }
 
-void ViewTransform::setx(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jx, a0);
-}
-
-jfloat ViewTransform::gety() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetFloatField(wrapped_obj, jy);
+void ViewTransform::X(float a0) const
+{
+    return mozilla::jni::Field<X_t>::Set(this, nullptr, a0);
 }
 
-void ViewTransform::sety(jfloat a0) {
-    JNIEnv *env = GetJNIForThread();
-    env->SetFloatField(wrapped_obj, jy, a0);
-}
-jclass NativeZip::mNativeZipClass = 0;
-jmethodID NativeZip::jCreateInputStream = 0;
-void NativeZip::InitStubs(JNIEnv *env) {
-    mNativeZipClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/mozglue/NativeZip");
-    jCreateInputStream = AndroidBridge::GetMethodID(env, mNativeZipClass, "createInputStream", "(Ljava/nio/ByteBuffer;I)Ljava/io/InputStream;");
+constexpr char ViewTransform::Y_t::name[];
+constexpr char ViewTransform::Y_t::signature[];
+
+float ViewTransform::Y() const
+{
+    return mozilla::jni::Field<Y_t>::Get(this, nullptr);
 }
 
-NativeZip* NativeZip::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    NativeZip* ret = new NativeZip(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+void ViewTransform::Y(float a0) const
+{
+    return mozilla::jni::Field<Y_t>::Set(this, nullptr, a0);
 }
 
-jobject NativeZip::CreateInputStream(jobject a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(2) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char NativeZip::name[];
 
-    jobject temp = env->CallObjectMethod(wrapped_obj, jCreateInputStream, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    jobject ret = static_cast<jobject>(env->PopLocalFrame(temp));
-    return ret;
-}
-jclass MatrixBlobCursor::mMatrixBlobCursorClass = 0;
-jmethodID MatrixBlobCursor::jMatrixBlobCursor = 0;
-jmethodID MatrixBlobCursor::jMatrixBlobCursor0 = 0;
-jmethodID MatrixBlobCursor::jAddRow = 0;
-jmethodID MatrixBlobCursor::jAddRow1 = 0;
-jmethodID MatrixBlobCursor::jAddRow2 = 0;
-void MatrixBlobCursor::InitStubs(JNIEnv *env) {
-    mMatrixBlobCursorClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/MatrixBlobCursor");
-    jMatrixBlobCursor = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "<init>", "([Ljava/lang/String;)V");
-    jMatrixBlobCursor0 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "<init>", "([Ljava/lang/String;I)V");
-    jAddRow = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/lang/Iterable;)V");
-    jAddRow1 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "(Ljava/util/ArrayList;I)V");
-    jAddRow2 = AndroidBridge::GetMethodID(env, mMatrixBlobCursorClass, "addRow", "([Ljava/lang/Object;)V");
+constexpr char NativeZip::CreateInputStream_t::name[];
+constexpr char NativeZip::CreateInputStream_t::signature[];
+
+mozilla::jni::Object::LocalRef NativeZip::CreateInputStream(mozilla::jni::Object::Param a0, int32_t a1) const
+{
+    return mozilla::jni::Method<CreateInputStream_t>::Call(this, nullptr, a0, a1);
 }
 
-MatrixBlobCursor* MatrixBlobCursor::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    MatrixBlobCursor* ret = new MatrixBlobCursor(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char MatrixBlobCursor::name[];
 
-MatrixBlobCursor::MatrixBlobCursor(jobjectArray a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char MatrixBlobCursor::New_t::name[];
+constexpr char MatrixBlobCursor::New_t::signature[];
 
-    Init(env->NewObject(mMatrixBlobCursorClass, jMatrixBlobCursor, a0), env);
-    env->PopLocalFrame(nullptr);
+MatrixBlobCursor::LocalRef MatrixBlobCursor::New(mozilla::jni::ObjectArray::Param a0)
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr, a0);
 }
 
-MatrixBlobCursor::MatrixBlobCursor(jobjectArray a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    Init(env->NewObject(mMatrixBlobCursorClass, jMatrixBlobCursor0, a0, a1), env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char MatrixBlobCursor::New2_t::name[];
+constexpr char MatrixBlobCursor::New2_t::signature[];
 
-void MatrixBlobCursor::AddRow(jobject a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallVoidMethod(wrapped_obj, jAddRow, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+MatrixBlobCursor::LocalRef MatrixBlobCursor::New(mozilla::jni::ObjectArray::Param a0, int32_t a1)
+{
+    return mozilla::jni::Constructor<New2_t>::Call(nullptr, nullptr, a0, a1);
 }
 
-void MatrixBlobCursor::AddRow(jobject a0, int32_t a1) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char MatrixBlobCursor::AddRow_t::name[];
+constexpr char MatrixBlobCursor::AddRow_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jAddRow1, a0, a1);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+void MatrixBlobCursor::AddRow(mozilla::jni::Object::Param a0) const
+{
+    return mozilla::jni::Method<AddRow_t>::Call(this, nullptr, a0);
 }
 
-void MatrixBlobCursor::AddRow(jobjectArray a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char MatrixBlobCursor::AddRow2_t::name[];
+constexpr char MatrixBlobCursor::AddRow2_t::signature[];
 
-    env->CallVoidMethod(wrapped_obj, jAddRow2, a0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
-jclass SQLiteBridgeException::mSQLiteBridgeExceptionClass = 0;
-jmethodID SQLiteBridgeException::jSQLiteBridgeException = 0;
-jmethodID SQLiteBridgeException::jSQLiteBridgeException0 = 0;
-jfieldID SQLiteBridgeException::jserialVersionUID = 0;
-void SQLiteBridgeException::InitStubs(JNIEnv *env) {
-    mSQLiteBridgeExceptionClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/sqlite/SQLiteBridgeException");
-    jSQLiteBridgeException = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "<init>", "()V");
-    jSQLiteBridgeException0 = AndroidBridge::GetMethodID(env, mSQLiteBridgeExceptionClass, "<init>", "(Ljava/lang/String;)V");
-    jserialVersionUID = AndroidBridge::GetStaticFieldID(env, mSQLiteBridgeExceptionClass, "serialVersionUID", "J");
+void MatrixBlobCursor::AddRow(mozilla::jni::Object::Param a0, int32_t a1) const
+{
+    return mozilla::jni::Method<AddRow2_t>::Call(this, nullptr, a0, a1);
 }
 
-SQLiteBridgeException* SQLiteBridgeException::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    SQLiteBridgeException* ret = new SQLiteBridgeException(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
-}
+constexpr char MatrixBlobCursor::AddRow3_t::name[];
+constexpr char MatrixBlobCursor::AddRow3_t::signature[];
 
-SQLiteBridgeException::SQLiteBridgeException() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    Init(env->NewObject(mSQLiteBridgeExceptionClass, jSQLiteBridgeException), env);
-    env->PopLocalFrame(nullptr);
+void MatrixBlobCursor::AddRow(mozilla::jni::ObjectArray::Param a0) const
+{
+    return mozilla::jni::Method<AddRow3_t>::Call(this, nullptr, a0);
 }
 
-SQLiteBridgeException::SQLiteBridgeException(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char SQLiteBridgeException::name[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
+constexpr char SQLiteBridgeException::New_t::name[];
+constexpr char SQLiteBridgeException::New_t::signature[];
 
-    Init(env->NewObject(mSQLiteBridgeExceptionClass, jSQLiteBridgeException0, j0), env);
-    env->PopLocalFrame(nullptr);
+SQLiteBridgeException::LocalRef SQLiteBridgeException::New()
+{
+    return mozilla::jni::Constructor<New_t>::Call(nullptr, nullptr);
 }
 
-int64_t SQLiteBridgeException::getserialVersionUID() {
-    JNIEnv *env = GetJNIForThread();
-    return env->GetStaticLongField(mSQLiteBridgeExceptionClass, jserialVersionUID);
-}
-jclass Clipboard::mClipboardClass = 0;
-jmethodID Clipboard::jClearText = 0;
-jmethodID Clipboard::jGetClipboardTextWrapper = 0;
-jmethodID Clipboard::jHasText = 0;
-jmethodID Clipboard::jSetClipboardText = 0;
-void Clipboard::InitStubs(JNIEnv *env) {
-    mClipboardClass = AndroidBridge::GetClassGlobalRef(env, "org/mozilla/gecko/util/Clipboard");
-    jClearText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "clearText", "()V");
-    jGetClipboardTextWrapper = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "getText", "()Ljava/lang/String;");
-    jHasText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "hasText", "()Z");
-    jSetClipboardText = AndroidBridge::GetStaticMethodID(env, mClipboardClass, "setText", "(Ljava/lang/CharSequence;)V");
+constexpr char SQLiteBridgeException::New2_t::name[];
+constexpr char SQLiteBridgeException::New2_t::signature[];
+
+SQLiteBridgeException::LocalRef SQLiteBridgeException::New(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Constructor<New2_t>::Call(nullptr, nullptr, a0);
 }
 
-Clipboard* Clipboard::Wrap(jobject obj) {
-    JNIEnv *env = GetJNIForThread();
-    Clipboard* ret = new Clipboard(obj, env);
-    env->DeleteLocalRef(obj);
-    return ret;
+constexpr char SQLiteBridgeException::SerialVersionUID_t::name[];
+constexpr char SQLiteBridgeException::SerialVersionUID_t::signature[];
+
+int64_t SQLiteBridgeException::SerialVersionUID()
+{
+    return mozilla::jni::Field<SerialVersionUID_t>::Get(nullptr, nullptr);
 }
 
-void Clipboard::ClearText() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
-
-    env->CallStaticVoidMethod(mClipboardClass, jClearText);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-}
+constexpr char Clipboard::name[];
 
-jstring Clipboard::GetClipboardTextWrapper() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char Clipboard::ClearText_t::name[];
+constexpr char Clipboard::ClearText_t::signature[];
 
-    jobject temp = env->CallStaticObjectMethod(mClipboardClass, jGetClipboardTextWrapper);
-    AndroidBridge::HandleUncaughtException(env);
-    jstring ret = static_cast<jstring>(env->PopLocalFrame(temp));
-    return ret;
+void Clipboard::ClearText()
+{
+    return mozilla::jni::Method<ClearText_t>::Call(nullptr, nullptr);
 }
 
-bool Clipboard::HasText() {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(0) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char Clipboard::GetClipboardTextWrapper_t::name[];
+constexpr char Clipboard::GetClipboardTextWrapper_t::signature[];
 
-    bool temp = env->CallStaticBooleanMethod(mClipboardClass, jHasText);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
-    return temp;
+mozilla::jni::String::LocalRef Clipboard::GetClipboardTextWrapper()
+{
+    return mozilla::jni::Method<GetClipboardTextWrapper_t>::Call(nullptr, nullptr);
 }
 
-void Clipboard::SetClipboardText(const nsAString& a0) {
-    JNIEnv *env = AndroidBridge::GetJNIEnv();
-    if (env->PushLocalFrame(1) != 0) {
-        AndroidBridge::HandleUncaughtException(env);
-        MOZ_CRASH("Exception should have caused crash.");
-    }
+constexpr char Clipboard::HasText_t::name[];
+constexpr char Clipboard::HasText_t::signature[];
 
-    jstring j0 = AndroidBridge::NewJavaString(env, a0);
-
-    env->CallStaticVoidMethod(mClipboardClass, jSetClipboardText, j0);
-    AndroidBridge::HandleUncaughtException(env);
-    env->PopLocalFrame(nullptr);
+bool Clipboard::HasText()
+{
+    return mozilla::jni::Method<HasText_t>::Call(nullptr, nullptr);
 }
 
-void InitStubs(JNIEnv *env) {
-    DownloadsIntegration::InitStubs(env);
-    GeckoAppShell::InitStubs(env);
-    GeckoJavaSampler::InitStubs(env);
-    RestrictedProfiles::InitStubs(env);
-    SurfaceBits::InitStubs(env);
-    ThumbnailHelper::InitStubs(env);
-    DisplayPortMetrics::InitStubs(env);
-    GLController::InitStubs(env);
-    GeckoLayerClient::InitStubs(env);
-    ImmutableViewportMetrics::InitStubs(env);
-    LayerView::InitStubs(env);
-    NativePanZoomController::InitStubs(env);
-    ProgressiveUpdateData::InitStubs(env);
-    ViewTransform::InitStubs(env);
-    NativeZip::InitStubs(env);
-    MatrixBlobCursor::InitStubs(env);
-    SQLiteBridgeException::InitStubs(env);
-    Clipboard::InitStubs(env);
+constexpr char Clipboard::SetClipboardText_t::name[];
+constexpr char Clipboard::SetClipboardText_t::signature[];
+
+void Clipboard::SetClipboardText(mozilla::jni::String::Param a0)
+{
+    return mozilla::jni::Method<SetClipboardText_t>::Call(nullptr, nullptr, a0);
 }
-} /* android */
+
+
 } /* widget */
 } /* mozilla */
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -1,507 +1,2530 @@
 // GENERATED CODE
-// Generated by the Java program at /build/annotationProcessors at compile time from
-// annotations on Java methods. To update, change the annotations on the corresponding Java
-// methods and rerun the build. Manually updating this file will cause your build to fail.
+// Generated by the Java program at /build/annotationProcessors at compile time
+// from annotations on Java methods. To update, change the annotations on the
+// corresponding Javamethods and rerun the build. Manually updating this file
+// will cause your build to fail.
 
 #ifndef GeneratedJNIWrappers_h__
 #define GeneratedJNIWrappers_h__
 
-#include "nsXPCOMStrings.h"
-#include "AndroidJavaWrappers.h"
+#include "mozilla/jni/Refs.h"
 
 namespace mozilla {