Android and JNI (ii)----Java call C dynamic call (reprint)

Source: Internet
Author: User

Directory:

1. Introduction
2. Entry functions for JNI components
3. Using the Registernativemethods method
4. Testing
5. JNI Help method
6. References

1. Introduction

Directory:

1. Introduction
2. Entry functions for JNI components
3. Using the Registernativemethods method
4. Testing
5. JNI Help method
6. References

1. Introduction

Android and JNI (i) have briefly described how to use JNI in an Android environment. But following the basic steps of JNI development seems a bit stiff, and the local function name gets ugly. So it is very necessary to introduce another method of implementation here.

2. Entry functions for JNI components

The previous article said static {System.loadlibrary ("Hellojni");} loads the dynamic library libhellojni.so the first time the class is used. When an Android VM executes to the system.loadlibrary () function, the Jni_onload () function is executed first. This corresponds to a call to Jni_onunload () when uninstalling.

The intention to first invoke the Jni_onload () in the C component includes:

(1) Tell the VM that this C component uses that JNI version. If Jni_onload () is not available in the dynamic library, the VM defaults to the oldest JNI 1.1 version of the dynamic library. Because of the many extensions to the new version of JNI, if you need to use the new features of JNI, such as the java.nio.ByteBuffer of JNI 1.4, you must tell the VM by using the Jni_onload () function.
(2) Another function is initialization, such as pre-application of resources.

Now let's start with the reality of a very simple jni_onload () and see if there is really a call to it. Add code to HELLOJNI.C:

1 jint jni_onload (javavm* vm, void *reserved) 2 {3     logd ("%s called.\n", __function__); 4 5     return jni_version_1_4; Note that this is going to go back to the JNI version, or it will go wrong. 6}

Compile:

$NDK-build Compile thumb  : Hellojni <= hellojni.csharedlibrary  : libhellojni.so/home/eddy/workspace/ hellojni/obj/local/armeabi/objs/hellojni/hellojni.o:in function ' jni_onload ':/home/eddy/workspace/hellojni/jni/ hellojni.c:35:undefined reference to ' LOGD ' Collect2:ld returned 1 exit statusmake: * * * [/HOME/EDDY/WORKSPACE/HELLOJNI/O Bj/local/armeabi/libhellojni.so] Error 1

Add header files #include <utils/Log.h> before compiling:

$NDK-build Compile thumb  : Hellojni <= hellojni.c/home/eddy/workspace/hellojni/jni/hellojni.c:20:23:error: Utils/log.h:no such file or directorymake: * * * [/home/eddy/workspace/hellojni/obj/local/armeabi/objs/hellojni/ HELLOJNI.O] Error 1

Tip the specified header file could not be found. Since we did not put this jni in the entire Android source code compiled, so it is normal to encounter this error, the solution is to add the source code in the Android.mk the path of the header file.

Local_cflags + =-iyour_path/android4.0/include/frameworks/base/includelocal_cflags +-Iyour_path/android4.0/ Include/system/core/includelocal_cflags + =-iyour_path/android4.0/include/frameworks/base/opengl/includelocal_ CFLAGS + =-iyour_path/android4.0/include/system/core/include

Re-compile:

$NDK-build Compile thumb  : Hellojni <= hellojni.csharedlibrary  : libhellojni.so/home/eddy/workspace/ hellojni/obj/local/armeabi/objs/hellojni/hellojni.o:in function ' jni_onload ':/home/eddy/workspace/hellojni/jni/ hellojni.c:36:undefined reference to ' __android_log_print ' Collect2:ld returned 1 exit statusmake: * * * [/home/eddy/works Pace/hellojni/obj/local/armeabi/libhellojni.so] Error 1

OK, it's wrong again. But it is not compiled error, is a link error, this is very simple, as long as the link liblog.so this library can be. Add in Android.mk:

Local_ldlibs + =-lc-lm-llog

Re-compile:

$NDK-build Compile thumb  : Hellojni <= hellojni.csharedlibrary  : Libhellojni.soinstall        : libhellojni.so = libs/armeabi/libhellojni.so

OK, you are done. If there is no accident, after running you will find such printing in Logcat:

/DALVIKVM (1956): Trying to load lib/data/data/com.example.hellojni/lib/libhellojni.so 0X41345548D/DALVIKVM (1956): Added shared lib/data/data/com.example.hellojni/lib/libhellojni.so 0x41345548d/        (1956): Jni_onload called.

This shows that jni_onload () is indeed called when the JNI dynamic library is loaded. What's the use of calling this library? Here's what you're announcing.

3. Using the Registernativemethods method

Having said so much, I finally came to the point. First, the modified HELLOJNI.C listed, and then slowly analysis.

  1/* 2 * Copyright (C) The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0  (the "License");  5 * You are not a use this file except in compliance with the License. 6 * Obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * Ten * unles s required by applicable/agreed to in writing, software one * distributed under the License is distributed "A" S is "BASIS," without warranties or CONDITIONS of any KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * * * #include <string.h> #include <jni.h> #include "com_example_hellojni_hellojni.h" #incl Ude <utils/Log.h> #ifdef __cplusplus "C" {#endif, static const char* ClassName = "Com/exa Mple/hellojni/hellojni "; */* This was a trivial JNI example where we use a native method 29 * To return a new VM String. See the corresponding Java source * file located at:31 * * Apps/samples/hello-jni/project/src/com/example/hell  Ojni/hellojni.java *///jstring Java_com_example_hellojni_hellojni_stringfromjni (JNIEnv *env, jobject this) 35//{ //Return (*ENV)->newstringutf (env, "Hello from JNI!"); PNS////return "Hello from Jni!"; //} jstring Stringfromjni (jnienv* env, jobject This) (env, "Hello form JNI", *env) !"); Jninativemethod gmethods[] = {"Stringfromjni", "() ljava/lang/string;", (void *) Stringfromjni }, 46}; Registers the native methods, and is called from Jni_onload int register_location_methods ( JNIEnv *env) {Jclass clazz; */* Look up the class * * Clazz = (*env)->findclass (env, Classna ME); //clazz = Env->findclass (env, className); if (clazz = = NULL) {LOGE ("Can ' t find class%s\n ", className); return-1; LOGD ("Register native Methods"); */* Register all the methods * * (*ENV)->registernatives (env, Clazz, Gmethods, sizeof (gmethods)/s Izeof (gmethods[0])) = JNI_OK) +//if (env->registernatives (env, Clazz, Gmethods, sizeof (gmethods)/sizeof (Gmetho     DS[0])!! = JNI_OK) ("Failed Registering Methods for%s\n", ClassName), LOGE return-1; 69 } */* Fill out the rest of the ID cache */return 0;     The Jint jni_onload (javavm* vm, void *reserved), {jnienv*, env = NULL; Jint result =-1; 79 80 Logd ("%s: +", __function__);     Bayi *VM//For C if (()->getenv (VM, (void**) &env, jni_version_1_4)! = JNI_OK) {//For C + + 85         if (vm->getenv (void**) &env, jni_version_1_4)! = JNI_OK) {LOGE ("error:getenv failed.\n"); 87 return result; if (Register_location_methods (ENV) < 0) LOGE ("Error:register location Methods failed.\n"), and return result; 94} 9 5 jni_version_1_4 return; 98 101 void Jni_onunload (javavm* vm, void *reserved) 102 {103 return;104}105 106 #ifdef __cplusplus107}1 #endif

Let's say what this code does, and he's exactly the same as [1], implementing the Stringfromjni native method declared in JAVA, returning a string. As for why no longer need to be named Java_com_example_hellojni_hellojni_stringfromjni, it will be analyzed slowly.

Or start with the Jni_onload () function. The actions of this function include getting the JNI environment object, registering the local method, and finally returning the JNI version. Noteworthy is the 83rd and 85 lines, compiled in C environment, using line 83rd, C + + environment, using line 85th, otherwise compile error.

Registering a local method is a function of mapping C + + functions to JAVA, and in this case it is the structural body jninativemethod that plays a key role. He is defined in the jni.h.

1 typedef struct {   2    const char* name;  /* Local method name declared in Java */3    const char* signature; /* Describes the function's parameters and return values */4    void*       

Declaring an instance is line 44th to 46th.

1 static Jninativemethod gmethods[] = {2     {"Stringfromjni", "() ljava/lang/string;", (void *) Stringfromjni},3};

Parametric analysis:

"Stringfromjni": The local method name declared in Java;
(void *) Stringfromjni: Mapping object, local C/C + + function, name can be inconsistent with the local method name declared in Java.
"() ljava/lang/string;" : This should be the most difficult to understand, that is, the structure of the signature. He describes the parameters and return values of the local method. For example
"() V"
"(II) V"
"(ljava/lang/string; ljava/lang/string;) V "
These characters are actually corresponding to the parameter type one by one of the function.
The characters in "()" represent the parameters, followed by the return values. For example, "() V" means void Func ();
"(II) V" denotes void Func (int, int);
The corresponding relationship of each character is as follows
Character Java Type C type
V void void
Z Jboolean Boolean
I Jint int
J Jlong Long
D jdouble Double
F jfloat Float
B Jbyte Byte
C Jchar Char
S Jshort Short
The array starts with a "[" and is represented by two characters
[I Jintarray int[]
[F Jfloatarray float[]
[B Jbytearray byte[]
[C Jchararray char[]
[S Jshortarray short[]
[D Jdoublearray double[]
[J Jlongarray long[]
[Z Jbooleanarray boolean[]
All of the above are basic types, and if the arguments are Java classes, start with "L" and ";" At the end, the middle is separated by a "/" packet and the class name, and its corresponding C function parameter is Jobject, an exception is the String class, it corresponds to the C type of jstring.
ljava/lang/string; String jstring
Ljava/net/socket; Socket Jobject
If the JAVA function is in an embedded class (also known as an inner class), use $ as the delimiter between the class names, for example: "Landroid/os/fileutils$filestatus;".

Finally, the 64th line of code is used to register all the JNI local methods recorded in the Jninativemethod structure.

Using the Registernativemethods method is not just to change the ugly long method name, the most important thing is to improve the efficiency, because when the Java class through the VM call to the local function, usually rely on the VM to dynamically find the dynamic library of local functions ( Therefore, they need a naming format for a particular rule, and if a method requires successive calls many times, it is searched every time, so using registernatives to register the local function with the VM can make it more efficient to find the function.

Another important use of the Registernativemethods method is that the runtime dynamically adjusts the mapping between the local function and the Java function values, requiring only multiple calls to the Registernativemethods method and passing in different mapping table parameters.

4. Testing

In order to have a better understanding of registernativemethods, I add a local method to Java.

 1 package com.example.hellojni; 2 3 Import Android.os.Bundle; 4 Import android.app.Activity; 5 Import Android.util.Log; 6 Import Android.view.Menu; 7 Import Android.view.MenuItem; 8 Import Android.widget.TextView; 9 Import android.support.v4.app.navutils;10 public class Hellojni extends Activity {@Override14 public vo ID onCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.h  ELLO_JNI); Getactionbar (). Setdisplayhomeasupenabled (TRUE);/* Create a TextView and set its  content.20 * The text is retrieved by calling a NATIVE21 * function.22 */23 TextView TV = new TextView (this), Tv.settext (Stringfromjni ()), Setcontentview (TV), LOG.D         ("JNI", "max =" + Max (),}29 @Override31 Public boolean Oncreateoptionsmenu (Menu menu) {32 Getmenuinflater (). Inflate (R.menu.hello_jni, menu); return true;34}35 @Override38 public boolean onoptionsitemselected (MenuItem item) {39 Switch (Item.getitemid ()) {Max case Android. R.id.home:41 Navutils.navigateupfromsametask (this), return true;43}44 R Eturn super.onoptionsitemselected (item),}46/* A Native method that's implemented by The48 * ' Hellojni ' Native library, which is packaged49 * with this application.50 */51 public native String Stringfromjni (); The another native method declaration that's *not*54 * implemented by ' Hellojni '. This was simply to show that55 * You can declare as many native methods in your Java code56 * as you want, their       Implementation is searched in The57 * currently loaded native libraries only the first TIME58 * Your call them.59 *60 * Trying to call this function would result in A61 * Java.lang.UnsatisfiedLinkErroR exception!62 */63 public native String Unimplementedstringfromjni (); n. public native int Max (int a , int b); used to load the ' Hellojni ' Library on application68 * startup. The library has already been unpacked into69 */data/data/com.example.hellojni/lib/libhellojni.so at70 * Install ation time by the package manager.71 */72 static {system.loadlibrary ("Hellojni"); 74}75}

Add the implementation method for Max in HELLOCJNI.C.

1 int Native_max (jnienv* env, jobject this, int a, int b) 2 {3     return  (a > B a:b); 4}5 6 static Jninativemetho D gmethods[] = {7     {"Stringfromjni", "() ljava/lang/string;", (void *) Stringfromjni},8     {"Max", "(II) I", (void *) n Ative_max},9};

Build a dynamic library with the NDK compilation.

$NDK-build Compile thumb  : Hellojni <= hellojni.csharedlibrary  : Libhellojni.soinstall        : libhellojni.so = libs/armeabi/libhellojni.so

Run as---> Android application on the simulator. You can see the print:

D/DALVIKVM (2174): Trying to load lib/data/data/com.example.hellojni/lib/libhellojni.so 0X413488A8D/DALVIKVM (2174): Added shared lib/data/data/com.example.hellojni/lib/libhellojni.so 0x413488a8d/        (2174): jni_onload: +D/        ( 2174): Register native Methodsd/jni     (2174): max = 100

proves that the Max call succeeded.

By Registernativemethods This method, we can see that in the process of operation, we do not need to use Javah-jni to generate JNI header files. The function name of C + + can also be freely named.

5. JNI Help method

In Android source Your_path/dalvik/libnativehelper/include/nativehelper/jnihelp.h This header file provides some help functions for JNI, including local method registration, Functions such as exception handling. However, using these functions requires linking the dynamic library libnativehelper.so. A macro definition that calculates the length of a method mapping table is also provided.

1 #ifndef NELEM2 # define Nelem (x) ((int) (sizeof (x)/sizeof ((x) [0]))) 3 #endif

With this macro, we can write like this:

1 (*env)->registernatives (env, Clazz, Gmethods, Nelem (gmethods));

6. References

[1]. Android and JNI (i)
[2]. Introduction to Android JNI knowledge
[3]. What's happening with JNI programming in Android
[4]. Android Dynamic Registration JNI

Reprinted from: http://www.cnblogs.com/eddy-he/archive/2012/08/09/2629974.html

Android and JNI (ii)----Java call C dynamic call (reprint)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.