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