• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
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.jni_zero.samples;
6 
7 import android.graphics.Rect;
8 
9 import org.jni_zero.AccessedByNative;
10 import org.jni_zero.CalledByNative;
11 import org.jni_zero.CalledByNativeUnchecked;
12 import org.jni_zero.JNINamespace;
13 import org.jni_zero.NativeClassQualifiedName;
14 import org.jni_zero.NativeMethods;
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 SampleForTestsJni.get().init() function. Replace "CPPClass" with your
40     // particular class name!
41     long mNativeCPPObject;
42 
43     // You can define methods and attributes on the java class just like any other.
44     // Methods without the @CalledByNative annotation won't be exposed to JNI.
SampleForTests()45     public SampleForTests() {}
46 
startExample()47     public void startExample() {
48         // Calls C++ Init(...) method and holds a pointer to the C++ class.
49         mNativeCPPObject = SampleForTestsJni.get().init(this, "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         SampleForTestsJni.get().method(mNativeCPPObject, this);
58     }
59 
60     // Just a comment to ensure we aren't reading comments:
61     // private native void thisShouldNotExist();
62 
finishExample()63     public void finishExample() {
64         // We're done, so let's destroy nativePtr object.
65         SampleForTestsJni.get().destroy(mNativeCPPObject, this);
66     }
67 
68     // ---------------------------------------------------------------------------------------------
69     // The following methods demonstrate exporting Java methods for invocation from C++ code.
70     // Java functions are mapping into C global functions by prefixing the method name with
71     // "Java_<Class>_"
72     // This is triggered by the @CalledByNative annotation; the methods may be named as you wish.
73 
74     // Exported to C++ as:
75     // Java_SampleForTests_javaMethod(JNIEnv* env, jobject caller, jint foo, jint bar)
76     // Typically the C++ code would have obtained the jobject via the Init() call described above.
77     @CalledByNative
javaMethod(int foo, int bar)78     public int javaMethod(int foo, int bar) {
79         return 0;
80     }
81 
82     // Exported to C++ as Java_SampleForTests_staticJavaMethod(JNIEnv* env)
83     // Note no jobject argument, as it is static.
84     @CalledByNative
staticJavaMethod()85     public static boolean staticJavaMethod() {
86         return true;
87     }
88 
89     // No prefix, so this method is package private. It will still be exported.
90     @CalledByNative
packagePrivateJavaMethod()91     void packagePrivateJavaMethod() {}
92 
93     // Method signature with generics in params.
94     @CalledByNative
methodWithGenericParams( Map<String, Map<String, String>> foo, LinkedList<Integer> bar)95     public void methodWithGenericParams(
96             Map<String, Map<String, String>> foo, LinkedList<Integer> bar) {}
97 
98     // Constructors will be exported to C++ as:
99     // Java_SampleForTests_Constructor(JNIEnv* env, jint foo, jint bar)
100     @CalledByNative
SampleForTests(int foo, int bar)101     public SampleForTests(int foo, int bar) {}
102 
103     // Note the "Unchecked" suffix. By default, @CalledByNative will always generate bindings that
104     // call CheckException(). With "@CalledByNativeUnchecked", the client C++ code is responsible to
105     // call ClearException() and act as appropriate.
106     // See more details at the "@CalledByNativeUnchecked" annotation.
107     @CalledByNativeUnchecked
methodThatThrowsException()108     void methodThatThrowsException() {}
109 
110     // The generator is not confused by inline comments:
111     // @CalledByNative void thisShouldNotAppearInTheOutput();
112     // @CalledByNativeUnchecked public static void neitherShouldThis(int foo);
113 
114     /**
115      * The generator is not confused by block comments:
116      * @CalledByNative void thisShouldNotAppearInTheOutputEither();
117      * @CalledByNativeUnchecked public static void andDefinitelyNotThis(int foo);
118      */
119 
120     // String constants that look like comments don't confuse the generator:
121     private String mArrgh = "*/*";
122 
123     private @interface SomeAnnotation {}
124     private @interface AnotherAnnotation {}
125 
126     // The generator is not confused by @Annotated parameters.
127     @CalledByNative
javaMethodWithAnnotatedParam(@omeAnnotation int foo, final @SomeAnnotation int bar, @SomeAnnotation final int baz, @SomeAnnotation final @AnotherAnnotation int bat)128     void javaMethodWithAnnotatedParam(@SomeAnnotation int foo, final @SomeAnnotation int bar,
129             @SomeAnnotation final int baz, @SomeAnnotation final @AnotherAnnotation int bat) {}
130 
131     // ---------------------------------------------------------------------------------------------
132     // Java fields which are accessed from C++ code only must be annotated with @AccessedByNative to
133     // prevent them being eliminated when unreferenced code is stripped.
134     @AccessedByNative
135     private int mJavaField;
136 
137     // This "struct" will be created by the native side using |createInnerStructA|,
138     // and used by the java-side somehow.
139     // Note that |@CalledByNative| has to contain the inner class name.
140     static class InnerStructA {
141         private final long mLong;
142         private final int mInt;
143         private final String mString;
144 
InnerStructA(long l, int i, String s)145         private InnerStructA(long l, int i, String s) {
146             mLong = l;
147             mInt = i;
148             mString = s;
149         }
150 
151         @CalledByNative("InnerStructA")
create(long l, int i, String s)152         private static InnerStructA create(long l, int i, String s) {
153             return new InnerStructA(l, i, s);
154         }
155     }
156 
157     private List<InnerStructA> mListInnerStructA = new ArrayList<InnerStructA>();
158 
159     @CalledByNative
addStructA(InnerStructA a)160     private void addStructA(InnerStructA a) {
161         // Called by the native side to append another element.
162         mListInnerStructA.add(a);
163     }
164 
165     @CalledByNative
iterateAndDoSomething()166     private void iterateAndDoSomething() {
167         Iterator<InnerStructA> it = mListInnerStructA.iterator();
168         while (it.hasNext()) {
169             InnerStructA element = it.next();
170             // Now, do something with element.
171         }
172         // Done, clear the list.
173         mListInnerStructA.clear();
174     }
175 
176     // This "struct" will be created by the java side passed to native, which
177     // will use its getters.
178     // Note that |@CalledByNative| has to contain the inner class name.
179     static class InnerStructB {
180         private final long mKey;
181         private final String mValue;
182 
InnerStructB(long k, String v)183         private InnerStructB(long k, String v) {
184             mKey = k;
185             mValue = v;
186         }
187 
188         @CalledByNative("InnerStructB")
getKey()189         private long getKey() {
190             return mKey;
191         }
192 
193         @CalledByNative("InnerStructB")
getValue()194         private String getValue() {
195             return mValue;
196         }
197     }
198 
199     List<InnerStructB> mListInnerStructB = new ArrayList<InnerStructB>();
200 
iterateAndDoSomethingWithMap()201     void iterateAndDoSomethingWithMap() {
202         Iterator<InnerStructB> it = mListInnerStructB.iterator();
203         while (it.hasNext()) {
204             InnerStructB element = it.next();
205             // Now, do something with element.
206             SampleForTestsJni.get().addStructB(mNativeCPPObject, this, element);
207         }
208         SampleForTestsJni.get().iterateAndDoSomethingWithStructB(mNativeCPPObject, this);
209     }
210     interface InnerInterface {}
211     enum InnerEnum {}
212 
213     @CalledByNative
getInnerInterface()214     static InnerInterface getInnerInterface() {
215         return null;
216     }
217 
218     @CalledByNative
getInnerEnum()219     static InnerEnum getInnerEnum() {
220         return null;
221     }
222 
223     // Test overloads (causes names to be mangled).
224     @CalledByNative
getInnerEnum(int a)225     static InnerEnum getInnerEnum(int a) {
226         return null;
227     }
228 
229     // Test jclass and jthrowable, as well as generics.
230     @CalledByNative
getClass(Class<Map<String, String>> arg0)231     private Class<Map<String, String>> getClass(Class<Map<String, String>> arg0) {
232         return null;
233     }
234     @CalledByNative
getThrowable(Throwable arg0)235     private Throwable getThrowable(Throwable arg0) {
236         return null;
237     }
238 
239     // ---------------------------------------------------------------------------------------------
240     // The following methods demonstrate declaring methods to call into C++ from Java.
241     // The generator detects the type and name of the first parameter.
242     @NativeMethods
243     public interface Natives {
244         // This declares a C++ function which the application code must implement:
245         // static jint Init(JNIEnv* env, jobject caller);
246         // The jobject parameter refers back to this java side object instance.
247         // The implementation must return the pointer to the C++ object cast to jint.
248         // The caller of this method should store it, and supply it as a the nativeCPPClass param to
249         // subsequent native method calls (see the methods below that take an "int native..." as
250         // first param).
init(SampleForTests caller, String param)251         long init(SampleForTests caller, String param);
252 
253         // This defines a function binding to the associated C++ class member function. The name is
254         // derived from |nativeDestroy| and |nativeCPPClass| to arrive at CPPClass::Destroy() (i.e.
255         // native prefixes stripped).
256         //
257         // The |nativeCPPClass| is automatically cast to type CPPClass*, in order to obtain the
258         // object on which to invoke the member function. Replace "CPPClass" with your particular
259         // class name!
destroy(long nativeCPPClass, SampleForTests caller)260         void destroy(long nativeCPPClass, SampleForTests caller);
261 
262         // This declares a C++ function which the application code must implement:
263         // static jdouble GetDoubleFunction(JNIEnv* env, jobject caller);
264         // The jobject parameter refers back to this java side object instance.
getDoubleFunction(SampleForTests caller)265         double getDoubleFunction(SampleForTests caller);
266 
267         // Similar to nativeGetDoubleFunction(), but here the C++ side will receive a jclass rather
268         // than jobject param, as the function is declared static.
getFloatFunction()269         float getFloatFunction();
270 
271         // This function takes a non-POD datatype. We have a list mapping them to their full
272         // classpath in jni_generator.py JavaParamToJni. If you require a new datatype, make sure
273         // you add to that function.
setNonPODDatatype(SampleForTests caller, Rect rect)274         void setNonPODDatatype(SampleForTests caller, Rect rect);
275 
276         // This declares a C++ function which the application code must implement:
277         // static ScopedJavaLocalRef<jobject> GetNonPODDatatype(JNIEnv* env, jobject caller);
278         // The jobject parameter refers back to this java side object instance.
279         // Note that it returns a ScopedJavaLocalRef<jobject> so that you don' have to worry about
280         // deleting the JNI local reference. This is similar with Strings and arrays.
getNonPODDatatype(SampleForTests caller)281         Object getNonPODDatatype(SampleForTests caller);
282 
283         // Test jclass and jthrowable, as well as generics.
getClass(Class<Map<String, String>> arg0)284         Class<Map<String, String>> getClass(Class<Map<String, String>> arg0);
getThrowable(Throwable arg0)285         Throwable getThrowable(Throwable arg0);
286 
287         // Similar to nativeDestroy above, this will cast nativeCPPClass into pointer of CPPClass
288         // type and call its Method member function. Replace "CPPClass" with your particular class
289         // name!
method(long nativeCPPClass, SampleForTests caller)290         int method(long nativeCPPClass, SampleForTests caller);
291 
292         // Similar to nativeMethod above, but here the C++ fully qualified class name is taken from
293         // the annotation rather than parameter name, which can thus be chosen freely.
294         @NativeClassQualifiedName("CPPClass::InnerClass")
methodOtherP0(long nativePtr, SampleForTests caller)295         double methodOtherP0(long nativePtr, SampleForTests caller);
296 
297         // Tests passing a nested class.
addStructB(long nativeCPPClass, SampleForTests caller, InnerStructB b)298         void addStructB(long nativeCPPClass, SampleForTests caller, InnerStructB b);
299 
iterateAndDoSomethingWithStructB(long nativeCPPClass, SampleForTests caller)300         void iterateAndDoSomethingWithStructB(long nativeCPPClass, SampleForTests caller);
returnAString(long nativeCPPClass, SampleForTests caller)301         String returnAString(long nativeCPPClass, SampleForTests caller);
302     }
303 }
304