Using JNI in chromium

725 views
Skip to first unread message

Sarah

unread,
Apr 28, 2016, 10:46:46 PM4/28/16
to Chromium-dev
I want to add a new Java class in src/content/public/android/java/src/org/chromium/content/browser/ (say with name'MyClass.java'). The class will include some native methods. Currently I am not able to get the .h file to be created. This is what I do:
  1. In content_jni.gypi: add 'public/android/java/src/org/chromium/content/browser/MyClass.java' to sources
  2. In content_browser.gypi
    1. add 'public/browser/android/my_class.h' to variables
    2. add 'browser/android/my_class.h' and 'browser/android/my_class.cc', to android_browser_sources
  3. Then run ninja -C out/Release system_webview_apk
What am I missing here? What else do I need to be doing?

Thanks very much!

Nico Weber

unread,
Apr 28, 2016, 11:03:56 PM4/28/16
to mobius...@gmail.com, Chromium-dev
Hi Sarah,

please be a bit more patient than 5 hours before resending your question.

How the JNI stuff works is documented at https://www.chromium.org/developers/design-documents/android-jni, give that a look if you haven't yet (though someone should update that page to explain how to do things in gn – https://code.google.com/p/chromium/codesearch#search/&q=jni%20file:%5C.gn&sq=package:chromium&type=cs could get you started there).

On Thu, Apr 28, 2016 at 10:46 PM, Sarah <mobius...@gmail.com> wrote:
I want to add a new Java class in src/content/public/android/java/src/org/chromium/content/browser/ (say with name'MyClass.java'). The class will include some native methods. Currently I am not able to get the .h file to be created. This is what I do:
  1. In content_jni.gypi: add 'public/android/java/src/org/chromium/content/browser/MyClass.java' to sources
This sounds right.

  1. In content_browser.gypi
    1. add 'public/browser/android/my_class.h' to variables
    2. add 'browser/android/my_class.h' and 'browser/android/my_class.cc', to android_browser_sources
This might not be necessary.
  1. Then run ninja -C out/Release system_webview_apk
What am I missing here? What else do I need to be doing?

Does building content_jni_headers instead help? How do you check if the header is getting generated? Something like `find out/Release -name MyClass_jni.h` should find it.

I think this should work, but I haven't tried it (no Android build at hand atm) and just looked at codesearch a bit, so maybe I misread something.

Nico
 

Thanks very much!

--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev

Sarah

unread,
Apr 29, 2016, 2:09:00 AM4/29/16
to Chromium-dev
Thanks Nico,

Yes you're right, it actually worked and a file named MyClass_jni.h was created. Is this the file I should be including in my c++ code? The contents of it seemed a little odd to me, I was expecting something along the lines of aw_contents.h: https://code.google.com/p/chromium/codesearch#chromium/src/android_webview/native/aw_contents.h&q=aw_conten&sq=package:chromium&l=1
Is this  aw_contents.h not an automatically created file? I thought for a java class named MyClass, I had to create my_class.cc and my_class.h would be autogenerated, and these would be linked together since they follow a naming convention, but it seems that  I'm wrong. A little explanation on how I should be using JNI here would be great. I read the information on chromium website and that didn't help much.

Thanks!

Anthony Berent

unread,
Apr 29, 2016, 4:31:08 AM4/29/16
to mobius...@gmail.com, Chromium-dev
Yes, you need to include MyClass_jni.h in your C++ code. Also, during Chrome startup, you need to call the RegisterNativesImpl() function defined in this header

For a complete example I worked on recently see:


--

Nico Weber

unread,
Apr 29, 2016, 10:26:21 AM4/29/16
to mobius...@gmail.com, Chromium-dev
On Fri, Apr 29, 2016 at 2:09 AM, Sarah <mobius...@gmail.com> wrote:
Thanks Nico,

Yes you're right, it actually worked and a file named MyClass_jni.h was created. Is this the file I should be including in my c++ code? The contents of it seemed a little odd to me, I was expecting something along the lines of aw_contents.h: https://code.google.com/p/chromium/codesearch#chromium/src/android_webview/native/aw_contents.h&q=aw_conten&sq=package:chromium&l=1
Is this  aw_contents.h not an automatically created file?

Correct, that file isn't autogenerated. All files that are generated during the build will appear somewhere below out/Release. If a file is not in out/Release, then with 99% certainty it's an hand-crafted artisanal file. (The 1% exception is that a couple files in gpu/ are generated by a script but then checked in for some reason -- but that has nothing to do with JNI anyways). Also, almost all of our generated files have a comment saying something like "// This is a file generated by script X, do not edit" at the top, so if a file doesn't have that comment then chances are it's not generated.
 
I thought for a java class named MyClass, I had to create my_class.cc and my_class.h would be autogenerated, and these would be linked together since they follow a naming convention, but it seems that  I'm wrong. A little explanation on how I should be using JNI here would be great. I read the information on chromium website and that didn't help much.

For aberent's example, clicking "View In" (in the top right) and then "Revision log" might be helpful. With it, you can find the CL that added their code in the first place: https://codereview.chromium.org/1452603002
 

Thanks!




On Thursday, April 28, 2016 at 9:46:46 PM UTC-5, Sarah wrote:
I want to add a new Java class in src/content/public/android/java/src/org/chromium/content/browser/ (say with name'MyClass.java'). The class will include some native methods. Currently I am not able to get the .h file to be created. This is what I do:
  1. In content_jni.gypi: add 'public/android/java/src/org/chromium/content/browser/MyClass.java' to sources
  2. In content_browser.gypi
    1. add 'public/browser/android/my_class.h' to variables
    2. add 'browser/android/my_class.h' and 'browser/android/my_class.cc', to android_browser_sources
  3. Then run ninja -C out/Release system_webview_apk
What am I missing here? What else do I need to be doing?

Thanks very much!

--

Sarah

unread,
Apr 29, 2016, 1:01:36 PM4/29/16
to Chromium-dev, mobius...@gmail.com
Thanks a lot Aberent! What do you mean with Chrome statrtup? I see that in the code you posted, there is a method like the following that calls RegisterNativesImpl(): 
bool SupervisedUserContentProvider::Register(JNIEnv* env) {
  return RegisterNativesImpl(env);
}

but who calls the Register() method? It does not seem to be invoked in the constructor.

Tommy Nyquist

unread,
Apr 29, 2016, 2:05:18 PM4/29/16
to mobius...@gmail.com, Chromium-dev
That would be the JNI registrar. There are several of them throughout the code base, so pick the one that fits where your code lives.

For the example aberent@ mentioned, that would for example be in //chrome/browser/android/chrome_jni_registrar.cc:
static base::android::RegistrationMethod kChromeRegisteredMethods[] = {
    <snip>
    {"SupervisedUserContentProvider", SupervisedUserContentProvider::Regi
    <snip>
};

bool RegisterBrowserJNI(JNIEnv* env) {
  return RegisterNativeMethods(env, kChromeRegisteredMethods,
                               arraysize(kChromeRegisteredMethods));
}

That last method is again called from within the JNI onload code, see for example //chrome/app/android/chrome_jni_onload.cc.

In general, using the chromium code search tool (cs.chromium.org) is usually very helpful in finding these answers to "who calls what".

Sarah

unread,
Apr 29, 2016, 4:00:42 PM4/29/16
to Chromium-dev, mobius...@gmail.com
Hi,

when I try to register I get "error: 'RegisteMyClass' is not a member of 'content'" error, even the this function exists in the namespace. I added  "{"MyClass", content::RegisterMyClass}," to browser_jni_registrar.cc . What am I doing wrong? 

and this is how my cpp class looks like (my_class.cc):

#include "jni/MyClass_jni.h"

#include <stddef.h>

namespace content {

    class MyClass {
    public:
        int x;
        // static bool RegisterMyClass(JNIEnv* env);

    };

    // Static free functions declared and called directly from java.
    static void Parse(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
                                    const JavaParamRef<jstring>& text) {
    }


    bool RegisterPolicyManager(JNIEnv* env) {
      return RegisterNativesImpl(env);
    }

}  // namespace content

Tommy Nyquist

unread,
Apr 29, 2016, 4:06:57 PM4/29/16
to mobius...@gmail.com, Chromium-dev
Did you also remember to include the header file for your class (my_class.h) in the JNI registrar?

Thiago Farina

unread,
Apr 29, 2016, 4:07:43 PM4/29/16
to mobius...@gmail.com, Chromium-dev
On Fri, Apr 29, 2016 at 5:00 PM, Sarah <mobius...@gmail.com> wrote:
Hi,

when I try to register I get "error: 'RegisteMyClass' is not a member of 'content'" error, even the this function exists in the namespace. I added  "{"MyClass", content::RegisterMyClass}," to browser_jni_registrar.cc . What am I doing wrong? 

and this is how my cpp class looks like (my_class.cc):

Where is your my_class.h? Which target is it at? Why is it on content rather than chrome?

Did you EXPORT it?

This is a basic C++ question though.

--
Thiago Farina

Sarah

unread,
Apr 29, 2016, 4:23:28 PM4/29/16
to Chromium-dev, mobius...@gmail.com
Oops. I had forgotten to do that. Thanks so much!!!

Vincent Scheib

unread,
Apr 29, 2016, 4:52:44 PM4/29/16
to mobius...@gmail.com, Chromium-dev
Sarah, you're in a great position to help, please see what documentation was missing in 
https://www.chromium.org/developers/design-documents/android-jni points to. It is intended to have instructions for these steps.

Mobius Kravets

unread,
Apr 30, 2016, 6:33:47 PM4/30/16
to Tommy Nyquist, Chromium-dev
One more question. When I look at the example SampleForTests.java I see two methods startExample() and finishExample() which call nativeInit and nativeDestroy respectively. If you look SampleForTests_jni.h, nativeInit calls a static Init function internally, whereas nativeDestroy creates an instance of CPPClass and calls this instance's Destroy method. What causes this difference? What should I be doing to auto-generate  the second implementation?
Following is this code in SampleForTest_jni.h:
static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jcaller,
    const JavaParamRef<jstring>& param);

static jlong
    Java_org_chromium_example_jni_1generator_SampleForTests_nativeInit(JNIEnv*
    env, jobject jcaller,
    jstring param) {
  return Init(env, JavaParamRef<jobject>(env, jcaller),
      JavaParamRef<jstring>(env, param));
}

static void
    Java_org_chromium_example_jni_1generator_SampleForTests_nativeDestroy(JNIEnv*
    env,
    jobject jcaller,
    jlong nativeCPPClass) {
  CPPClass* native = reinterpret_cast<CPPClass*>(nativeCPPClass);
  CHECK_NATIVE_PTR(env, jcaller, native, "Destroy");
  return native->Destroy(env, JavaParamRef<jobject>(env, jcaller));
}

Tommy Nyquist

unread,
May 2, 2016, 3:27:34 PM5/2/16
to Mobius Kravets, Chromium-dev
I believe the java version of nativeDestroy takes a long as the first argument and the name of that parameter starts with 'native' and the rest of the that parameter name is the name of the C++ class it will be reinterpret_cast to. The nativeInit method does not take a long param as the first argument and as such, the name of that non-existing param is not nativeCPPClass...
Reply all
Reply to author
Forward
0 new messages