Android interview in the old is to ask JNI, but I move bricks in a small factory for many years, can not how used ah cry ~~~~ used to understand it.
Edited by guuguo proofread by GuuguoCopy the code
Noun explanation
C + + header file
The: header file is used to place the correspondingc++
Method declaration, in fact, its content is the same as the content of the.cpp file, are C++ source code. But the header file is not compiled. Header files can pass#include
Is included in the.cpp file. Include simply copies the header definition code into a. CPP file. So header files are used to place declarations, not definitions. Definition conflicts occur when multiple source files contain definitions directly, while declarations do not. Header files can also contain definitions, but try not to, if necessary, pass#ifndef... #endif
Let the compiler determine if a name is defined and then decide whether to continue compiling.JNI (Java Native Interface)
A programming framework that allows Java programs in a Java virtual machine to call local applications/libraries and be called by other programs.CMake
Is a cross-platform build tool, support C/C++/Java language engineering build. Used in this article to compile c++ code.
What is the passage about?
A large number of implementations in Android system are native implementations, and Java layer calls are made through JNI. Learning to use JNI will not only help us develop and interview, but also add two more bricks to our understanding of the android source code foundation. State the content and purpose of the passage:
- Understand the basic use of JNI in development
- Java code and c++ native method link principle
- What is the JNI framework? What is it
- What is the Ndk?
Understanding these four little points gives you an initial understanding of JNI that you can use when developing with it.
Small chestnut used by JNI (static registration)
Jni registration can be divided into static registration and dynamic registration.
- Static registration: Find the corresponding JNI function based on the function name, style is
Java_ package name _ Class name _ method name
- Dynamic registration: when we use
System#loadLibarary
Method loads the so library, and the Java virtual machine finds itJNI_OnLoad
Function and actively call. So we can do it inJNI_OnLoad
calljniRegisterNativeMethods
Perform dynamic registration of methods. (If you don’t learn this method, please Google)
Let’s talk about static registration first:
-
Create the Demo JNI SDK module
Let’s create asdk
Module, carrying native and JNI codes, directory structure is as follows:
The main directories shown in the figure are as follows:
src/main/java
Java source codesrc/main/jni
Native sourcesrc/main/jni/CMakeLists.txt
Cmake configuration file
Configure the jNI source path in build.gradle:
sourceSets {
main {
jni.srcDirs = ['src/main/jni']}}Copy the code
-
Define native Java methods
In Kotlin, the keyword external is used to identify the method as a JNI method. When the method is called, the Java_ package name _ class name _ method name c++ function. Let’s first create the JNI entry Java class jni. Java, define the Java native method. The method is as follows:
package top.guuguo.myapplication
class JNI {
/** Returns the signed string */
external fun signString(str: String): String
companion object {
/// The instance must be created after the native code is loaded, as in this example
///System.loadLibrary("jni-test")
val instance by lazy { JNI() }
}
}
Copy the code
We define a simple native method signString that mimics the method of signing a string.
-
Generate the corresponding header file for the pair
Javah tools are provided in Java. It can automatically generate native methods corresponding to c++ header files. Take a look at the instructions for the tool using Javah-h:
Javah [options] <classes> where [options] includes: -o <file> Output file (either -d or -o can only be used) -d <dir> Output directory -v -verbose Enable detailed output -h --help -? -version Output version information -jni Generates a JNI-style header file (default) -force always writes to the output file -classpath <path> the path from which the class is loaded -cp <path> the path from which the class is loaded -bootclasspath <path> The path from which to load the bootclass <classes> is specified using its fully qualified name (for example, java.lang.object).Copy the code
It can be used as follows: -cp is equivalent to -classpath, which specifies the class file path to generate the header file
javah -d app/src/main/cpp/header -cp "./app/build/tmp/kotlin-classes/debug/" top.guuguo.myapplication.JNI
Copy the code
You can see that the.h file was successfully generated after the command was executedThere are the.h
After the JNI declaration file, we completed the implementation of the corresponding method in jni. CPP, the code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include "header/top_guuguo_myapplication_JNI.h"
JNIEXPORT jstring JNICALL Java_top_guuguo_myapplication_JNI_signString(JNIEnv *env, jobject obj, jstring jStr) {
const char *cstr = env->GetStringUTFChars(jStr, NULL);
std::string str = std::string(cstr);
env->ReleaseStringUTFChars(jStr, cstr);
std::string cres = "signed:" + str;
jstring jres = env->NewStringUTF(cres.c_str());
return jres;
}
Copy the code
The definition implementation of the method is simple, just concatenating the signed: string in front of the string passed in.
-
Perfect cmakelist. TXT and build.gradle compilation. So product
There are currently two options for compiling native source code: cmake and NDK-build. CMake is a little more popular, so let’s introduce CMake. CMake is a cross-platform build tool that supports engineering builds in C/C++/Java languages. By configuring the CMake build script cmakelists. TXT, we can use the CMake command to do the custom compilation. This is the main instruction used by cmake
set(all_src "./src")
: The directive can be namedall_src
The value of the variableadd_library
The main effect of this directive is to generate a link file from the specified source file and then add it to the project
CMakeLists.txt
Let’s edit the configuration file to use the following
# Copyright (c) 2019 - 2020 The Alibaba DingTalk Authors. All rights reserved.PROJECT (jni - test) cmake_minimum_required (VERSION 3.4.1 track)
#Assign to some c++ compile-time identifiers
#set(CMAKE_CXX_COMPILER "clang++" ) # display the C++ compiler specified
#set(CMAKE_CXX_FLAGS "-std=c++11 -O2") # c++11
#set(CMAKE_CXX_FLAGS "-g") # Debug message
#set(CMAKE_CXX_FLAGS "-Wall") # Enable all alerts
#set(CMAKE_CXX_FLAGS_DEBUG "-O0" ) Debugging packages are not optimized
#set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG " ) # Release package optimization
set(CMAKE_CXX_FLAGS_RELEASE "-std=c++11 -O2 ")
set(CMAKE_CXX_FLAGS_DEBUG "-std=c++11 -O2 ")
#Assign to the variable SRC_ROOT
set(SRC_ROOT "./")
#Traverses all. CPP files directly under the directory and saves them in variables
file(GLOB all_src
"${SRC_ROOT}/*.hpp"
"${SRC_ROOT}/*.cpp"
"${SRC_ROOT}/src/*.h"
"${SRC_ROOT}/src/*.hpp"
"${SRC_ROOT}/header/*.h"
"${SRC_ROOT}/header/*.hpp"
)
#Add the source file to the build dynamic library
add_library(jni-test SHARED ${all_src})
Copy the code
Build. Gradle adds native configuration:
defaultConfig {
/ * *... * /
externalNativeBuild {
cmake {
/// Compile target name
targets 'jni-test'
// Precompiled behavior configuration :-fexceptions enables exception handling
cppFlags "-std=c++11 -fexceptions -frtti"
arguments "-DANDROID_STL=c++_shared"
}
}
}
externalNativeBuild {
cmake {
version '3.6.0'
path 'src/main/jni/CMakeLists.txt'}}Copy the code
Specify the necessary parameters in the code above, along with the cmake version and configuration file path
Compile:
The following compilation will automatically compile the relevant libraries, or you can directly package the corresponding so libraries and AAR packages with the gradle command
./gradlew :sdk:aR
Copy the code
Also is to use aR (assembleRelease) commands to compile the release package, in the build/intermediates/cmake/release can find corresponding product.
-
Simple c++ method calls
With the definition completed, we simply implement the call:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
System.loadLibrary("jni-test")
findViewById<Button>(R.id.button).setOnClickListener {
Toast.makeText(this,JNI.instance.signString("hello world"),Toast.LENGTH_LONG).show()
}
}
}
Copy the code
After we click the button, directly pop up the string after the toast display signature.
This one needs to be noticed!!
The steps to get the JNI instance need to come after System.loadLibrary. In this way, the corresponding native method can be called correctly.
Summary:
At this point, a JNI sample of the minimization implementation is complete, implementing the native method definition and Java calls to it. And with that, we can go a lot further in the future
- We can learn more about cross-platform
native
How the SDK works in Android. - Ability to read aOSP source code to increase their own basic skills
How do Java code and c++ native methods connect
When Java invokes native methods, the ART VM performs special processing accordingly. Refer to the implementation process of the Android ART class method. The VIRTUAL machine determines whether the method is native and executes the method. The implementation of the client side is very simple, is the above mentioned static registration and dynamic registration.
What is the JNI framework and what does it include?
JNIEnv represents the context in which Java calls native languages and is a pointer that encapsulates almost all JNI methods. We see the jni. H source (aosp source path source/libnativehelper/include_jni/jni. H). Find the definition of JNIEnv: typedef _JNIEnv JNIEnv; You can see that this is an alias of type _JNIEnv. _JNIEnv = _JNIEnv
truct _JNIEnv {
/* do not rename this; it does not seem to be entirely opaque */
const struct JNINativeInterface* functions;
#if defined(__cplusplus)
jint GetVersion(a)
{ return functions->GetVersion(this); }
jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
jsize bufLen)
{ return functions->DefineClass(this, name, loader, buf, bufLen); }
// ...
}
Copy the code
It can be seen that all JNIEnv methods are indirectly called methods of JNINativeInterface, just a layer of encapsulation of JNINativeInterface structure. Most of our JNI operations go through it.
What is NDK and how does it relate to JNI?
ndk:Native Development Kit
Copy the code
The Android NDK supports compiling application C and C++ code using CMake. The NDK is a collection of tools.
- The NDK provides a set of tools to help developers quickly develop dynamic libraries for C (or C++) and automatically package so and Java applications together as APK. These tools can be tremendously helpful to developers.
- The NDK integrates a cross-compiler and provides mk files to isolate differences in CPU, platform, ABI, etc. Developers can create SO by simply modifying mk files (indicating “which files need to be compiled”, “compile feature requirements”, etc.).
- The NDK can automatically package so and Java applications together, greatly reducing the developer’s packaging effort.
The NDK provides a stable, limited API header declaration. Including: C11 standard library (libc), standard mathematics library (libm), c++17 library, Log library (liblog), compression library (libz), Vulkan rendering library (libvulkan), openGl library (libGLESv3) and so on. NDK can generate C/C++ dynamically linked libraries for us. Our development of Native is NDK based development.
NDK has nothing to do with JNI, but is a dynamic library based on NDK that needs to be communicated through JNI and Java.
The last
Jni: What do you mean by “123”?
- How to associate jNI native code? Through static registration and dynamic registration.
- What should I pay attention to when loading the SO library? The corresponding implementation can be called only after obtaining the instance of System. LoadLibrary and calling the native method.
- How to build so library? The NDK supports code compilation and build through cmake.
- What is the difference between NDK and JDK?
Only learning can be my growth, only learning can be my progress, I want to study hard, to contribute to the construction of the motherland ~~~
Reference article:
- Android JNI Introduction (eight) – The use of CMakeLists
- JNI method registration and loading principle analysis
- JNI implementation source code analysis
- The process by which Android ART executes class methods