• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.example.jni_generator;
6 
7 import android.graphics.Rect;
8 
9 import org.chromium.base.annotations.AccessedByNative;
10 import org.chromium.base.annotations.CalledByNative;
11 import org.chromium.base.annotations.CalledByNativeUnchecked;
12 import org.chromium.base.annotations.JNINamespace;
13 import org.chromium.base.annotations.NativeCall;
14 import org.chromium.base.annotations.NativeClassQualifiedName;
15 
16 import java.util.ArrayList;
17 import java.util.Iterator;
18 import java.util.LinkedList;
19 import java.util.List;
20 import java.util.Map;
21 
22 // This class serves as a reference test for the bindings generator, and as example documentation
23 // for how to use the jni generator.
24 // The C++ counter-part is sample_for_tests.cc.
25 // jni_generator/BUILD.gn has a jni_generator_tests target that will:
26 //   * Generate a header file for the JNI bindings based on this file.
27 //   * Generate a header file containing registration methods required to use C++ methods from this
28 //     file.
29 //   * Compile sample_for_tests.cc using the generated header file.
30 //   * link a native executable to prove the generated header + cc file are self-contained.
31 // All comments are informational only, and are ignored by the jni generator.
32 //
33 // This JNINamespace annotation indicates that all native methods should be
34 // generated inside this namespace, including the native class that this
35 // object binds to.
36 @JNINamespace("base::android")
37 class SampleForTests {
38     // Classes can store their C++ pointer counterpart as an int that is normally initialized by
39     // calling out a nativeInit() function. Replace "CPPClass" with your particular class name!
40     long mNativeCPPObject;
41 
42     // You can define methods and attributes on the java class just like any other.
43     // Methods without the @CalledByNative annotation won't be exposed to JNI.
SampleForTests()44     public SampleForTests() {
45     }
46 
startExample()47     public void startExample() {
48         // Calls C++ Init(...) method and holds a pointer to the C++ class.
49         mNativeCPPObject = nativeInit("myParam");
50     }
51 
doStuff()52     public void doStuff() {
53         // This will call CPPClass::Method() using nativePtr as a pointer to the object. This must
54         // be done to:
55         // * avoid leaks.
56         // * using finalizers are not allowed to destroy the cpp class.
57         nativeMethod(mNativeCPPObject);
58     }
59 
finishExample()60     public void finishExample() {
61         // We're done, so let's destroy nativePtr object.
62         nativeDestroy(mNativeCPPObject);
63     }
64 
65     // ---------------------------------------------------------------------------------------------
66     // The following methods demonstrate exporting Java methods for invocation from C++ code.
67     // Java functions are mapping into C global functions by prefixing the method name with
68     // "Java_<Class>_"
69     // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
70 
71     // Exported to C++ as:
72     // Java_SampleForTests_javaMethod(JNIEnv* env, jobject caller, jint foo, jint bar)
73     // Typically the C++ code would have obtained the jobject via the Init() call described above.
74     @CalledByNative
javaMethod(int foo, int bar)75     public int javaMethod(int foo, int bar) {
76         return 0;
77     }
78 
79     // Exported to C++ as Java_SampleForTests_staticJavaMethod(JNIEnv* env)
80     // Note no jobject argument, as it is static.
81     @CalledByNative
staticJavaMethod()82     public static boolean staticJavaMethod() {
83         return true;
84     }
85 
86     // No prefix, so this method is package private. It will still be exported.
87     @CalledByNative
packagePrivateJavaMethod()88     void packagePrivateJavaMethod() {
89     }
90 
91     // Method signature with generics in params.
92     @CalledByNative
methodWithGenericParams( Map<String, Map<String, String>> foo, LinkedList<Integer> bar)93     public void methodWithGenericParams(
94             Map<String, Map<String, String>> foo, LinkedList<Integer> bar) {}
95 
96     // Constructors will be exported to C++ as:
97     // Java_SampleForTests_Constructor(JNIEnv* env, jint foo, jint bar)
98     @CalledByNative
SampleForTests(int foo, int bar)99     public SampleForTests(int foo, int bar) {}
100 
101     // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that
102     // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to
103     // call ClearException() and act as appropriate.
104     // See more details at the "@CalledByNativeUnchecked" annotation.
105     @CalledByNativeUnchecked
methodThatThrowsException()106     void methodThatThrowsException() throws Exception {}
107 
108     // The generator is not confused by inline comments:
109     // @CalledByNative void thisShouldNotAppearInTheOutput();
110     // @CalledByNativeUnchecked public static void neitherShouldThis(int foo);
111 
112     /**
113      * The generator is not confused by block comments:
114      * @CalledByNative void thisShouldNotAppearInTheOutputEither();
115      * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo);
116      */
117 
118     // String constants that look like comments don't confuse the generator:
119     private String mArrgh = "*/*";
120 
121     private @interface SomeAnnotation {}
122 
123     // The generator is not confused by @Annotated parameters.
124     @CalledByNative
javaMethodWithAnnotatedParam(@omeAnnotation int foo)125     void javaMethodWithAnnotatedParam(@SomeAnnotation int foo) {
126     }
127 
128     // ---------------------------------------------------------------------------------------------
129     // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
130     // prevent them being eliminated when unreferenced code is stripped.
131     @AccessedByNative
132     private int mJavaField;
133 
134     // ---------------------------------------------------------------------------------------------
135     // The following methods demonstrate declaring methods to call into C++ from Java.
136     // The generator detects the "native" and "static" keywords, the type and name of the first
137     // parameter, and the "native" prefix to the function name to determine the C++ function
138     // signatures. Besides these constraints the methods can be freely named.
139 
140     // This declares a C++ function which the application code must implement:
141     // static jint Init(JNIEnv* env, jobject caller);
142     // The jobject parameter refers back to this java side object instance.
143     // The implementation must return the pointer to the C++ object cast to jint.
144     // The caller of this method should store it, and supply it as a the nativeCPPClass param to
145     // subsequent native method calls (see the methods below that take an "int native..." as first
146     // param).
nativeInit(String param)147     private native long nativeInit(String param);
148 
149     // This defines a function binding to the associated C++ class member function. The name is
150     // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e.
151     // native prefixes stripped).
152     //
153     // The |nativeCPPClass| is automatically cast to type CPPClass*, in order to obtain the object
154     // on
155     // which to invoke the member function. Replace "CPPClass" with your particular class name!
nativeDestroy(long nativeCPPClass)156     private native void nativeDestroy(long nativeCPPClass);
157 
158     // This declares a C++ function which the application code must implement:
159     // static jdouble GetDoubleFunction(JNIEnv* env, jobject caller);
160     // The jobject parameter refers back to this java side object instance.
nativeGetDoubleFunction()161     private native double nativeGetDoubleFunction();
162 
163     // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather than
164     // jobject param, as the function is declared static.
nativeGetFloatFunction()165     private static native float nativeGetFloatFunction();
166 
167     // This function takes a non-POD datatype. We have a list mapping them to their full classpath
168     // in jni_generator.py JavaParamToJni. If you require a new datatype, make sure you add to that
169     // function.
nativeSetNonPODDatatype(Rect rect)170     private native void nativeSetNonPODDatatype(Rect rect);
171 
172     // This declares a C++ function which the application code must implement:
173     // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject caller);
174     // The jobject parameter refers back to this java side object instance.
175     // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
176     // deleting the JNI local reference. This is similar with Strings and arrays.
nativeGetNonPODDatatype()177     private native Object nativeGetNonPODDatatype();
178 
179     // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass type
180     // and call its Method member function. Replace "CPPClass" with your particular class name!
nativeMethod(long nativeCPPClass)181     private native int nativeMethod(long nativeCPPClass);
182 
183     // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from the
184     // annotation rather than parameter name, which can thus be chosen freely.
185     @NativeClassQualifiedName("CPPClass::InnerClass")
nativeMethodOtherP0(long nativePtr)186     private native double nativeMethodOtherP0(long nativePtr);
187 
188     // This "struct" will be created by the native side using |createInnerStructA|,
189     // and used by the java-side somehow.
190     // Note that |@CalledByNative| has to contain the inner class name.
191     static class InnerStructA {
192         private final long mLong;
193         private final int mInt;
194         private final String mString;
195 
InnerStructA(long l, int i, String s)196         private InnerStructA(long l, int i, String s) {
197             mLong = l;
198             mInt = i;
199             mString = s;
200         }
201 
202         @CalledByNative("InnerStructA")
create(long l, int i, String s)203         private static InnerStructA create(long l, int i, String s) {
204             return new InnerStructA(l, i, s);
205         }
206     }
207 
208     private List<InnerStructA> mListInnerStructA = new ArrayList<InnerStructA>();
209 
210     @CalledByNative
addStructA(InnerStructA a)211     private void addStructA(InnerStructA a) {
212         // Called by the native side to append another element.
213         mListInnerStructA.add(a);
214     }
215 
216     @CalledByNative
iterateAndDoSomething()217     private void iterateAndDoSomething() {
218         Iterator<InnerStructA> it = mListInnerStructA.iterator();
219         while (it.hasNext()) {
220             InnerStructA element = it.next();
221             // Now, do something with element.
222         }
223         // Done, clear the list.
224         mListInnerStructA.clear();
225     }
226 
227     // This "struct" will be created by the java side passed to native, which
228     // will use its getters.
229     // Note that |@CalledByNative| has to contain the inner class name.
230     static class InnerStructB {
231         private final long mKey;
232         private final String mValue;
233 
InnerStructB(long k, String v)234         private InnerStructB(long k, String v) {
235             mKey = k;
236             mValue = v;
237         }
238 
239         @CalledByNative("InnerStructB")
getKey()240         private long getKey() {
241             return mKey;
242         }
243 
244         @CalledByNative("InnerStructB")
getValue()245         private String getValue() {
246             return mValue;
247         }
248     }
249 
250     List<InnerStructB> mListInnerStructB = new ArrayList<InnerStructB>();
251 
iterateAndDoSomethingWithMap()252     void iterateAndDoSomethingWithMap() {
253         Iterator<InnerStructB> it = mListInnerStructB.iterator();
254         while (it.hasNext()) {
255             InnerStructB element = it.next();
256             // Now, do something with element.
257             nativeAddStructB(mNativeCPPObject, element);
258         }
259         nativeIterateAndDoSomethingWithStructB(mNativeCPPObject);
260     }
261 
nativeAddStructB(long nativeCPPClass, InnerStructB b)262     native void nativeAddStructB(long nativeCPPClass, InnerStructB b);
nativeIterateAndDoSomethingWithStructB(long nativeCPPClass)263     native void nativeIterateAndDoSomethingWithStructB(long nativeCPPClass);
nativeReturnAString(long nativeCPPClass)264     native String nativeReturnAString(long nativeCPPClass);
265 
266     // This inner class shows how to annotate native methods on inner classes.
267     static class InnerClass {
268         @NativeCall("InnerClass")
nativeGetInnerIntFunction()269         private static native int nativeGetInnerIntFunction();
270     }
271 
272     interface InnerInterface {}
273     enum InnerEnum {}
274 
275     @CalledByNative
getInnerInterface()276     static InnerInterface getInnerInterface() {
277         return null;
278     }
279 
280     @CalledByNative
getInnerEnum()281     static InnerEnum getInnerEnum() {
282         return null;
283     }
284 }
285