Problem description
This exception occurs when JVM cannot find the specified native method.
Solution
This exception occurs when JVM cannot find the specified native method. Check whether the .so files exist, whether their paths are correct, and whether the files are loaded. An app runs on devices that have different CPU architectures. It is necessary to compile and generate the .so files that support different CPU architectures.
java.lang.UnsatisfiedLinkError:Native method not found: com.baidu.android.moplus.systemmonitor.security.md5.MD5.Transform_native:([I[BII)V
at com.c.h.systemmonitor.security.md5.MD5.Transform_native(NativeMethod)
at com.c.h.systemmonitor.security.md5.MD5.update(UnknownSource)
at com.c.h.systemmonitor.security.md5.MD5.update(UnknownSource)
at com.c.h.systemmonitor.security.md5.MD5InputStream.read(UnknownSource)
at java.io.InputStream.read(InputStream.java:163)Sample code
Step 1: Write the Application.mk file
Create the Application.mk file in the jni directory (at the same level as the hello-jni.c directory) and add the following code to the file:
APP_ABI := armeabi armeabi-v7a x86The code means that you can generate .so files for three processors at a time. If the Application.mk file does not exist or is not to be used, add the following code to the ndk-build parameter:
APP_ABI="armeabi armeabi-v7a x86 mips"The following code is executed:
ndk-build APP_ABI="armeabi armeabi-v7a x86 mips"Step 2: Generate .so files
After you write the Android.mk file, you can use the ndk-build script in the Android NDK package to generate .so files by using the following method:
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ ls
AndroidManifest.xml assets bin default.properties gen jni libs obj res src
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ ndk-build
Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libhello-jni.so => libs/armeabi/libhello-jni.so Then, three armeabi/armeabi-v7a/x86 folders are generated in the hello-jni/libs directory and the libhello-jni.so files are generated in these folders.
Step 3: Recompile the HelloJni project in Eclipse to generate an APK file
Recompile the HelloJni project in Eclipse to generate an APK file. The libhello-jni.so files are contained in the APK file.
Appendix
NDK program development details:
Step 1: Build a development environment
1. Android NDK programs are developed in Linux. The code written in C or C++ is used to generate .so files that can run in ARM. This requires cross-compilation which can be provided in the Linux system.
2. Install the Android NDK package. You can download it from the Google Android official website. Only the tool in this package can be used to compile the C/C++ code of the Android JNI project and generate .so files.
3. Android app development environments include Eclipse, Java, Android SDK, and ADT.
4: Add the android-ndk path to the PATH environment variable after the Android NDK package is installed:
sudo gedit /etc/environment5. Add the android-ndk installation path to the PATH environment variable and immediately validate the PATH environment variable: source/etc/environment
Enter the following command in the CLI:
ndk-buildIf the following message, instead of the "ndk-build not found" message, is displayed, the Android NDK package is installed.
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
/home/mqc/workspace/android/android-ndk-r5/build/core/build-local.mk:85: *** Android NDK: Aborting . Stop.Step 2: Write Java code
Create the HelloJni project and the HelloJni.java file.
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
public class HelloJni 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);
}
/* A native method that is implemented by the 'hello-jni' native library, which is packaged with this application. */
public native String stringFromJNI();
public native String unimplementedStringFromJNI();
/* this is used to load the 'hello-jni' library on application startup. The library has already been unpacked into
/data/data/com.example.HelloJni/lib/libhello-jni.so at installation time by the package manager. */
static {
System.loadLibrary("hello-jni");
}
}The static code block in the preceding code indicates that the hello-jni.so file will be loaded when your program starts. The code declared in the static code block will be executed in advance of the onCreate method. If your program contains multiple classes and the HelloJni class is not the entry point of your app, the hello-jni (full name is libhello-jni.so) library will be loaded the first time you use the HelloJni class.
publicnativeString stringFromJNI();
publicnativeString unimplementedStringFromJNI();In the preceding code, the two methods have the native keyword in their declarations. The keyword indicates that the two methods are native one. The two methods are implemented by native code in C or C++, but they are only declarations in the Java code. You must compile the project in Eclipse to generate the .class file, which will be used to generate the .h file.
Step 3: Write C or C++ code
Run the javah command to generate the .h file and then write C or C++ code based on the .h file.
1. Generate the .h file.
Go to the directory of the HelloJni project in the terminal.
mqc@ubuntu:~$ cd workspace/android/NDK/hello-jni/View the project files.
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ ls
AndroidManifest.xml assets bin default.properties gen res srcOnly a few standard Android app files (or folders) exist. Create a jni folder in the project directory.
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ mkdir jni
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ ls
AndroidManifest.xml assets bin default.properties gen jni res srcRun the following command to generate the .h file:
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ javah -classpath bin -d jni com.example.hellojni.HelloJni-classpath bin: the path of the class.-d JNI: the directory that contains the generated header file.com.example.hellojni.HelloJni: the complete class name.
The successful generation of the .h file depends on whether the HelloJni.class is generated in the bin/com/example/hellojni/ directory. Confirm that the .h file exists in the jni folder.
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ cd jni/
mqc@ubuntu:~/workspace/android/NDK/hello-jni/jni$ ls
com_example_hellojni_HelloJni.hThe content of the com_example_hellojni_HelloJni.h file:
com_example_hellojni_HelloJni.h :
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_hellojni_HelloJni */
#ifndef _Included_com_example_hellojni_HelloJni
#define _Included_com_example_hellojni_HelloJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_hellojni_HelloJni
* Method: stringFromJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI
(JNIEnv *, jobject);
/*
* Class: com_example_hellojni_HelloJni
* Method: unimplementedStringFromJNI
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_unimplementedStringFromJNI
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endifThe functions in the preceding source code are named in the java_pacakege_class_mathod format:
The
stringFromJNI()method in theHello.javafile corresponds to theJava_com_example_hellojni_HelloJni_stringFromJNI()method in C or C++ file.The
unimplementedStringFromJNI()method in theHelloJni.javafile corresponds to theJava_com_example_hellojni_HelloJni_unimplementedStringFromJNI()method in the C or C++ file.
Step 4: Write the .c file
hello-jni.c :
#include <string.h>
#include <jni.h>
/* This is a trivial JNI example where we use a native method
* to return a new VM String. See the corresponding Java source
* file located at:
* apps/samples/hello-jni/project/src/com/example/HelloJni/HelloJni.java
*/
jstring Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
{
return (*env)->NewStringUTF(env, "Hello from JNI !");
}The Java_com_example_hellojni_HelloJni_stringFromJNI() function returns a jstring object of "Hello from JNI !" (corresponding to the string object in Java).
Step 5: Compile the hello-jni.c file to generate the library files
1. Write the Android.mk file.
Create the Application.mk file in the jni directory (at the same level as the hello-jni.c directory). The Android.mk file is an Android makefile with the following content:
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "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 := hello-jni
LOCAL_SRC_FILES := hello-jni.c
include $(BUILD_SHARED_LIBRARY)Details about the Android.mk file:
LOCAL_PATH := $(call my-dir)The LOCAL_PATH variable must be defined first for an Android.mk file. This variable is used to find source files in the development tree. In the preceding example, the my-dir macro function provided by the compilation system is used to return the current path (the directory containing the Android.mk file).
include $( CLEAR_VARS)The CLEAR_VARS function provided by the compilation system instructs GNU makefile to clear multiple LOCAL_XXX variables (except LOCAL_PATH) such as LOCAL_MODULE, LOCAL_SRC_FILES, and LOCAL_STATIC_LIBRARIES. This is necessary because all compilation control files are in the same GNU MAKE execution environment and all variables are global.
LOCAL_MODULE := hello-jniThe LOCAL_MODULE variable must be defined and is used to identify each module described in the Android.mk file. The module name must be unique and contain no spaces.
The compilation system will automatically generate appropriate prefixes and suffixes. A
libhello-jni.sofile is automatically generated after the shared library module named hello-jni is created.If you name the library libhello-jni, the compilation system will generate the
libhello-jni.sofile without adding the lib prefix. This is to support theAndroid.mkfile of Android source code.
LOCAL_SRC_FILES := hello-jni.cThe LOCAL_SRC_FILES variable must contain the C or C++ source code files to be compiled and packaged into the module.
The header files and included files are not required here, because the compilation system will automatically find dependent files. You just list the source code files that will be passed directly to the compiler.
include $(BUILD_SHARED_LIBRARY)The BUILD_SHARED_LIBRARY variable is provided by the compilation system to indicated that the file is compiled to generate the library files. The variable points to a GNU makefile script. It collects all information defined in the LOCAL_XXX variable after the include $(CLEAR_VARS) was invoked last time. The variable also determines what to compile and how to do it. The BUILD_STATIC_LIBRARY variable indicates that the lib$(LOCAL_MODULE).a static library is to be generated. The BUILD_EXECUTABLE variable indicates an executable file is to be generated.
2. Write the Application.mk file
Create the Application.mk file in the jni directory (at the same level as the hello-jni.c directory) and add the following code to the file:
APP_ABI := armeabi armeabi-v7a x86The code means that you can generate .so files for three processors at a time. If the Application.mk file does not exist or is not to be used, add the following code to the ndk-build parameter:
APP_ABI="armeabi armeabi-v7a x86 mips"The following code is executed:
ndk-build APP_ABI="armeabi armeabi-v7a x86 mips"3. Generate .so files.
After you write the Android.mk file, you can use the ndk-build script in the Android NDK package to generate .so files by using the following method:
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ ls
AndroidManifest.xml assets bin default.properties gen jni libs obj res src
mqc@ubuntu:~/workspace/android/NDK/hello-jni$ ndk-build
Gdbserver : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libhello-jni.so => libs/armeabi/libhello-jni.soThe libhello-jni.so files are correctly generated.
4. Recompile the HelloJni project in Eclipse to generate an APK file.
Recompile the HelloJni project in Eclipse to generate an APK file. The libhello-jni.so files are contained in the APK file.