[Reprint]--android JNI Knowledge Point

Source: Internet
Author: User
Tags comparison table

The Java Native Interface (JNI) standard is part of the Java platform that allows Java code to interact with code written in other languages. JNI is a local programming interface that enables Java code running inside a Java Virtual machine (VM) to interoperate with applications and libraries written in other programming languages such as C, C + +, and assembly language.

1. Starting from how to load. So files

Since the Android application layer classes are written in Java, these Java classes must be executed by Dalvik virtual machines (vm:virtual machine) after they have been compiled into the Dex type bytecode. VMS play an important role in the Android platform.

In addition, in the course of executing Java classes, if the Java class needs to communicate with the C component, the VM will load the C component and then let the Java function successfully invoke the functions of the C component. At this point, the VM plays the role of a bridge, allowing Java and C components to communicate with each other through a standard JNI interface.

The Java class of the application layer is executed on the virtual machine (vm:vitual machines), and the C piece is not executed on the VM, then how does the Java program require the VM to load the C component specified by (load)? The following directives can be used:

System.loadlibrary (*.so's file name);

For example, the Mediaplayer.java class, provided in the Android framework, contains directives:

     public class mediaplayer{   
static {
System.loadlibrary ("Media_jni");
}
}

This requires the VM to be loaded into Android's/system/lib/libmedia_jni.so file. After loading the *.so, the Java class and the *.so file converge and execute together.

2. How to write the *.so entry function

----The purpose of the Jni_onload () and jni_onunload () functions

When the Android VM (Virtual machine) executes to the system.loadlibrary () function, it first executes the jni_onload () function in the C component. Its use has two:

(1) Tell the VM that this C component uses that JNI version. If your *.so file does not provide the jni_onload () function, the VM will default to the *.so file using the oldest JNI version 1.1. 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) as the VM executes to the System.loadlibrary () function, the Jni_onload () is called immediately, so the developer of the C component can set the initial value (initialization) in the C component by Jni_onload ().

For example, in Android's/system/lib/libmedia_jni.so file, the Jni_onload () function is provided with the code snippet:

#define LOG_NDEBUG 0

#define LOG_TAG "Mediaplayer-jni"

Jint jni_onload (javavm* vm, void* reserved)

{
jnienv* env = NULL;
Jint result =-1;
if (vm->getenv (void**) &env, jni_version_1_4)! = JNI_OK) {
LOGE ("Error:getenv failed\n");
Goto bail;
}
ASSERT (env! = NULL);
if (Register_android_media_mediaplayer (env) < 0) {
LOGE ("Error:mediaplayer native registration failed\n");
Goto bail;
}
if (Register_android_media_mediarecorder (env) < 0) {
LOGE ("Error:mediarecorder native registration failed\n");
Goto bail;
}
if (Register_android_media_mediascanner (env) < 0) {
LOGE ("Error:mediascanner native registration failed\n");
Goto bail;
}
if (Register_android_media_mediametadataretriever (env) < 0) {
LOGE ("Error:mediametadataretriever native registration failed\n");
Goto bail;
}
/* Success--Return valid version number */
result = Jni_version_1_4;
Bail:
return result;
}

This function callbacks the Jni_version_1_4 value to the VM, so the VM knows the JNI version it is using. In addition, it also does some initial action (can call any local function), such as directives:

   if (Register_android_media_mediaplayer (env) < 0) {
LOGE ("Error:mediaplayer native registration failed\n");
Goto bail;
}

The individual local functions provided by this component (Native function) are enlisted in the VM to speed up the efficiency of subsequent call local functions.

The Jni_onunload () function corresponds to the jni_onload (). When the C component is loaded, Jni_onload () is called immediately to perform the initial action within the component, and when the VM releases the C component, the Jni_onunload () function is called to perform the cleanup action. When the VM calls the Jni_onload () or jni_unload () function, the VM's pointers (Pointer) are passed to them with the following parameters:

Jint jni_onload (javavm* vm, void* reserved) {}

Jint jni_onunload (javavm* vm, void* reserved) {}

In the Jni_onload () function, the indicator value of jnienv is obtained through the indicator of the VM and stored in the env indicator variable, as in the following instruction:

Jint jni_onload (javavm* vm, void* reserved) {
jnienv* env = NULL;
Jint result =-1;
if (vm->getenv (void**) &env, jni_version_1_4)! = JNI_OK) {
LOGE ("Error:getenv failed\n");
Goto bail;
}
}

Because VMS are typically the execution environment for multiple threads (multi-threading). When each thread calls Jni_onload (), the values of the JNIEnv metrics passed in are different. In order to accommodate this multi-threading environment, C component developers can avoid the data conflict of threads by jnienv the value of the indicator when composing local functions to ensure that the written local function is safely executed in the Android multi-thread VM. For this reason, when the function of the C component is called, the jnienv indicator value is passed to it, as follows:

Jint jni_onload (javavm* vm, void* reserved) {
jnienv* env = NULL;
if (Register_android_media_mediaplayer (env) < 0) {
}
}

When this jni_onload () calls the Register_android_media_mediaplayer (ENV) function, the env indicator value is passed past. Thus, the Register_android_media_mediaplayer () function can distinguish different threads by this indicator value in order to resolve the problem of data conflicts.

For example, in the Register_android_media_mediaplayer () function, the following commands can be written:

if (*env)->monitorenter (env, obj)! = JNI_OK) {

}

Check to see if there are other threads entering the object, and if not, the thread will go into the object and execute it. Also, you can write the following directives:

if (*env)->monitorexit (env, obj)! = JNI_OK) {

}

Check to see if this thread is executing within this object, and if so, the thread will leave immediately.

Purpose of the 3.registerNativeMethods () function

Application-level Java classes call to local functions through the VM. It is generally dependent on the VM to find local functions in the *.so. If you need to call a number of times, you need to look it over and spend a lot of time. At this point, the component developer can register the local function with the VM itself. For example, the code snippet in the Android/system/lib/libmedia_jni.so file is as follows:

#define LOG_NDEBUG 0
#define LOG_TAG "Mediaplayer-jni"
Static Jninativemethod gmethods[] = {
{"Setdatasource", "(ljava/lang/string;) V",
(void *) Android_media_mediaplayer_setdatasource},
{"Setdatasource", "(Ljava/io/filedescriptor; JJ) V ",
(void *) ANDROID_MEDIA_MEDIAPLAYER_SETDATASOURCEFD},
{"Prepare", "() V", (void *) Android_media_mediaplayer_prepare},
{"Prepareasync", "() V", (void *) Android_media_mediaplayer_prepareasync},
{"_start", "() V", (void *) Android_media_mediaplayer_start},
{"_stop", "() V", (void *) Android_media_mediaplayer_stop},
{"Getvideowidth", "() I", (void *) Android_media_mediaplayer_getvideowidth},
{"Getvideoheight", "() I", (void *) Android_media_mediaplayer_getvideoheight},
{"Seekto", "(I) V", (void *) Android_media_mediaplayer_seekto},
{"_pause", "() V", (void *) Android_media_mediaplayer_pause},
{"IsPlaying", "() Z", (void *) android_media_mediaplayer_isplaying},
{"GetCurrentPosition", "() I", (void *) Android_media_mediaplayer_getcurrentposition},
{"Getduration", "() I", (void *) Android_media_mediaplayer_getduration},
{"_release", "() V", (void *) Android_media_mediaplayer_release},
{"_reset", "() V", (void *) Android_media_mediaplayer_reset},
{"Setaudiostreamtype", "(I) V", (void *) Android_media_mediaplayer_setaudiostreamtype},
{"Setlooping", "(Z) V", (void *) android_media_mediaplayer_setlooping},
{"SetVolume", "(FF) V", (void *) Android_media_mediaplayer_setvolume},
{"Getframeat", "(I) Landroid/graphics/bitmap;",
(void *) Android_media_mediaplayer_getframeat},
{"Native_setup", "(Ljava/lang/object;) V",
(void *) Android_media_mediaplayer_native_setup},
{"Native_finalize", "() V", (void *) Android_media_mediaplayer_native_finalize},
};
static int Register_android_media_mediaplayer (JNIEnv *env) {
Return Androidruntime::registernativemethods (env,
"Android/media/mediaplayer", Gmethods, Nelem (gmethods));
}
Jint jni_onload (javavm* vm, void* reserved) {
if (Register_android_media_mediaplayer (env) < 0) {
LOGE ("Error:mediaplayer native registration failed\n");
Goto bail;
}
}

The Jni_onload () function is called when the VM is loaded into the libmedia_jni.so archive. Next, Jni_onload () calls the Register_android_media_mediaplayer () function. At this point, the Androidruntime::registernativemethods () function is called to register the local functions contained in the gmethods[] table with the VM (i.e., androidruntime). In short, the Registernativemethods () function has two uses:

(1) More efficient to find functions.

(2) Externally can be carried out during execution. Because gmethods[] is a < name, the function pointer > comparison table, in the execution of the program, you can call the Registernativemethods () function multiple times to replace the local function pointer, and to achieve the purpose of the elastic externally local function.

4.Andoird uses a different way of traditional Java JNI to define its native functions. The important difference is that Andorid uses a map array of Java and C functions that describes the parameters and return values of the functions. The type of this array is Jninativemethod, which is defined as follows:

typedef struct {
const char* name; The name of the function in/*java */
Const char* Signature; /* Describes the function's parameters and return values */
void* fnptr; /* function pointer, point to C function */
} Jninativemethod;

One of the more difficult to understand is the second parameter, such as

"() 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. If the Java function parameter is class, start with "L" and ";" End, the middle is a "/" separated by the package and the class name. The corresponding C function name parameter is jobject. One exception is the string class, whose corresponding class is jstring

ljava/lang/string; String jstring

Ljava/net/socket; Socket Jobject

If the Java function is in an embedded class, use $ as the delimiter between the class names.

For example "(ljava/lang/string; landroid/os/fileutils$filestatus;) Z "

Android JNI Programming Practice

First, directly using the Java itself JNI interface (Windows/ubuntu)

1. Create a new Android app in Eclipsh. Two classes: One inherits from the Activity,ui display. The other contains the native method. Compile to generate all classes.

Jnitest.java file:

Package com.hello.jnitest;
Import android.app.Activity;
Import Android.os.Bundle;
public class Jnitest extends Activity {
/** called when the activity is first created. */
@Override
public void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
Setcontentview (R.layout.main);
Nadd cal = new Nadd ();
Settitle ("The Native Add Result is" + string.valueof (Cal.nadd (10, 19));
}
}

Nadd.java file:
Package com.hello.jnitest;
public class Nadd {
static {
System.loadlibrary ("Nadd");
}
public native int Nadd (int a, int b);
}

The above is done in Windows.

2. Use the Javah command to generate the. h file for C + +. Note The class wants to include the package name, and the path folder contains all the classes in the package, otherwise the class error is not found. The CLASSPATH parameter is specified to the folder before the package name, and the folder hierarchy conforms to the organization hierarchy of the Java class.

Javah-classpath. /jnitest/bin Com.hello.jnitest.Nadd

Com_hello_jnitest_nadd. h Files:

/* Don't EDIT this file-it are machine generated */
#include <jni.h>
/* Header for class Com_hello_jnitest_nadd */
#ifndef _included_com_hello_jnitest_nadd
#define _included_com_hello_jnitest_nadd
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_hello_jnitest_nadd
* Method: nadd
* Signature: (II) I
*/
Jniexport Jint Jnicall Java_com_hello_jnitest_nadd_nadd
(JNIEnv *, Jobject, Jint, Jint);
#ifdef __cplusplus
}
#endif
#endif

3. Edit the. c file to implement the native method.

COM_HELLO_JNITEST_NADD.C file:

#include <stdlib.h>
#include "Com_hello_jnitest_nadd.h"
Jniexport jint jnicall java_com_hello_jnitest_nadd_nadd (jnienv * env, Jobject C, jint A, Jint b) {
return (A+B);
}

4. Compile the. c File Survival Dynamic Library.

Arm-none-linux-gnueabi-gcc-i/home/a/work/android/jdk1.6.0_17/include-i/home/a/work/android/jdk1.6.0_17/include /linux-fpic-c COM_HELLO_JNITEST_NADD.C

Arm-none-linux-gnueabi-ld-t/home/a/codesourcery/sourcery_g++_lite/arm-none-linux-gnueabi/lib/ldscripts/armelf_ Linux_eabi.xsc-share-o libnadd.so COM_HELLO_JNITEST_NADD.O

Get the libnadd.so file.

The above is done in Ubuntu.

5. Push the corresponding dynamic library file into the system/lib of the AVD: adb push libnadd.so/system/lib. If you are prompted to read-only the file system error, run the ADB remount command.

ADB Push Libnadd.so/system/lib

6. Run the original application in ECLIPSH.

The above is done in Windows.

The so file generated in one can also be compiled into the APK package in two ways. Just build the Libs\armeabi folder in the project folder (the other folder name is not valid, only the Libs folder is not valid), and then copy the so file into the project can be compiled.

Two. Using NDK native cost local law (Ubuntu and Windows)

1. Install NDK: Unzip, then go to the NDK's extracted directory and run build/host-setup.sh (requires make 3.81 and awk). If wrong, modify the host-setup.sh file: Change #!/bin/sh to #!/bin/bash and run again.

2. Create your own project folder under the Apps folder, and then build a file Application.mk and item project folder under that folder.

APPLICATION.MK file:

App_project_path: = $ (call My-dir)/project

App_modules: = Myjni

3. Build a JNI folder under the project folder, and then create a new android.mk and MYJNI.C. There is no need to generate the corresponding. h file with Javah, but the function name should contain the corresponding complete package, class name.

4. Edit the appropriate file contents.

ANDROID.MK file:

# Copyright (C) The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# You are not a use of this file except in compliance with the License.
# Obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# unless required by applicable or agreed to writing, software
# Distributed under the License is distributed on a "as 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.
#
Local_path: = $ (call My-dir)
Include $ (clear_vars)
Local_module : = Myjni
Local_src_files: = Myjni.c
Include $ (build_shared_library)

MYJNI.C file:

#include <string.h>
#include <jni.h>
Jstring
Java_com_hello_ndktest_ndktest_stringfromjni (jnienv* jobject thiz) {
Return (*ENV)->newstringutf (env, "Hello from My-jni!");
}

Myjni File Organization:

[email protected]: ~/work/android/ndk-1.6_r1/apps$ tree Myjni

Myjni

|--application.mk

'--Project

|--JNI

| |--android.mk

| '--MYJNI.C

'--Libs

'--Armeabi

'--libmyjni.so

4 Directories, 4 files

5. Compile: Make App=myjni.

The above content is done in Ubuntu. The following content is done in Windows. Of course it can be done in Ubuntu.

6. Create the Android application in Eclipsh. Copy the automatically generated Libs folder from Myjni to the current project folder, and compile and run.

Ndktest.java file:

Package com.hello.NdkTest;
Import android.app.Activity;
Import Android.os.Bundle;
Import Android.widget.TextView;
public class Ndktest extends Activity {
/** called when the activity is first created. */
@Override
public void OnCreate (Bundle savedinstancestate) {
Super.oncreate (savedinstancestate);
TextView TV = new TextView (this);
Tv.settext (Stringfromjni ());
Setcontentview (TV);
}
Public native String Stringfromjni ();
static {
System.loadlibrary ("Myjni");
}
}

The so file generated in the second can also be run in the AVD using one of the methods.

This article from Csdn Blog, reproduced please indicate the source: http://blog.csdn.net/linweig/archive/2010/03/26/5417319.aspx

[Reprint]--android JNI Knowledge Point

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.