Well, the technology to share here on the end, if the blog trouble, can see the introduction to the home page, looking for me to take the PDF version of oh

Java based article

Android Basics (1)

Android Basics (2)


ART stands for Android Runtime and handles application execution In a completely different way than Dalvik, which relies on a just-in-time (JIT) compiler to interpret bytecode. Application code compiled by developers needs to run on users’ devices through an interpreter, which is not efficient, but makes it easier for applications to run on different hardware and architectures. ART changes this completely by precompiling the bytecode into the machine language at application installation, a mechanism called Ahead-of-time (AOT) compilation. By removing the process of interpreting code, the application executes more efficiently and starts faster.

ART function

AOT compilation

ART introduces a pre-compilation mechanism to improve application performance. ART also has more stringent installation-time validation than Dalvik. At installation time, ART uses the dex2OAT tool that comes with the device to compile the application. The utility takes a DEX file as input and generates a compiled application executable for the target device. The tool should be able to compile all valid DEX files smoothly.

Garbage collection optimization

Garbage collection (GC) can compromise application performance, resulting in unstable displays, slow interface response times, and other issues. ART has optimized garbage collection in several ways:

  • There is only one GC pause, not two
  • Parallel processing while the GC remains paused
  • In the special case of cleaning up recently allocated short-duration objects, the collector’s total GC time is shorter
  • Optimized garbage collection ergonomics for more timely parallel garbage collection, making GC_FOR_ALLOC events extremely rare in typical use cases
  • Compress GC to reduce background memory usage and fragmentation

Optimizations for development and debugging

  • Sampling analyzer support

Historically, developers have used the Traceview tool, which tracks application execution, as a profiler. While Traceview can provide useful information, the overhead of each method call can skew the results of Dalvik analysis, and the use of the tool clearly affects runtime performance

ART adds support for dedicated sampling analyzers without these limitations, providing a more accurate picture of application execution without significantly slowing it down. The KitKat version adds sampling support to Dalvik’s Traceview.

  • Supports more debugging functions

ART supports many new debugging options, especially those related to monitoring and garbage collection. For example, see which locks are held in the stack trace and then jump to the thread that holds the lock; Asks for the number of currently active instances of a given class, requests to see instances, and references to keep objects in a valid state; Filter instance specific events, such as breakpoints.

  • Optimized diagnostic details in exception and crash reports

When a runtime exception occurs, ART gives you as much context and detail as possible. ART provides a Java. Lang. ClassCastException, Java, lang. ClassNotFoundException and Java. Lang. NullPointerException more abnormal details (higher version Dalvik will provide Java. Lang. ArrayIndexOutOfBoundsException and Java. Lang. ArrayStoreException exceptionally detailed information more, these information now including the array size and offset seams; ART also provides this information).


ART has several different GC schemes, including running different garbage collectors. The default scheme is a CMS (Concurrent Mark Clearing) scheme, which mainly uses sticky CMS and partial CMS. Sticky CMS is ART’s non-moving generational garbage collector. It scans only the parts of the heap that have been modified since the last GC and can only reclaim objects allocated since the last GC. With the exception of the CMS scheme, ART performs heap compression when the application changes the process state to a state where lag is not detected (for example, background or cache).

In addition to the new garbage collector, ART also introduced a new bitmap-based memory allocator called RosAlloc (slot run Allocator). This new allocator performs better than DlMalloc because it has a shard lock and can add a thread’s local buffer when the allocation size is small.

Compared to Dalvik, the ART CMS garbage collection plan has some improvements in many aspects:

  • Compared to Dalvik, the number of pauses was reduced from 2 to 1. Dalvik’s first pause is mainly for root marking, that is, concurrent marking in the ART, allowing the thread to mark its own root and then immediately resuming running.
  • Like Dalvik, the ART GC pauses once before the cleanup process begins. The main difference between the two is that during this pause, some Dalvik segments are concurrent in the ART. These include java.lang.ref.Reference processing, system weak cleanup (for example, JNI weak global, etc.), re-marking of non-threaded roots, and card pre-cleanup. The stages that continue during ART pauses include scanning for dirty cards and relabeling thread roots, which help shorten pause times.
  • A final improvement in ART GC over Dalvik is that the sticky CMS collector increases GC throughput. Unlike normal generational GC, viscous CMS does not move. Young objects are stored in an allocation stack (basically a java.lang.Object array) rather than having a dedicated region for them. This avoids moving the objects needed to keep the pause times low, but has the disadvantage of making the stack longer by adding a large number of complex object images.

Another major difference between the ART GC and Dalvik is that the ART GC introduces a mobile garbage collector. The purpose of using mobile GC is to reduce the memory used by background applications through heap compression. Currently, the event that triggers heap compression is a change in the ActivityManager process state. When the application goes into the background, it notifies ART that it has entered a process state that no longer “senses” lag. At this point, the ART does something (for example, compression and monitor compression) that causes the application thread to pause for a long time. The two mobile GCS currently in use are isomorphic space compression and half-space compression.

  • Half-space compression moves objects between two tightly aligned collision pointer Spaces. This mobile GC is suitable for small memory devices because it can save slightly more memory than isomorphic space compression. The extra space saved comes mainly from tightly packed objects, which avoids the RosAlloc/DlMalloc allocator overhead. Since the CMS is still in use in the foreground and cannot be collected from the collision pointer space, the half-space has to be transformed again when the application is used in the foreground. This is not ideal as it may cause a long pause.
  • Isomorphic space compression is achieved by copying objects from one RosAlloc space to another. This helps reduce memory usage by reducing heap fragmentation. This is currently the default compression mode for non-low memory devices. The main advantage of isomorphic space compression over half-space compression is that there is no heap conversion required to switch applications from background to foreground.


The basic flow

1, according to the requirements to determine the object to hook 2, find the owner of the object to hook, get the object to hook 3, define the “object to hook” proxy class, and create the object to hook 4, using the object created in the previous step, replace the object to hook

Use the sample

* The only purpose of this method: With their own click events, * * @param View hook limited to this DiscouragedPrivateApi */ @suppresslint ({"DiscouragedPrivateApi", "PrivateApi"}) public static void hook(Context Context, final View View) {// try {// To v mListenerInfo object, the object is the holder of a click event Method Method = the class. The getDeclaredMethod (" getListenerInfo "); method.setAccessible(true); Object mListenerInfo = method.invoke(view); // Invoke (view); // Get the current click event from the mListenerInfo object Class<? > listenerInfoClz = Class.forName("android.view.View$ListenerInfo"); / / this is the inner class representation method of Field Field. = listenerInfoClz getDeclaredField (" mOnClickListener "); final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo); // Get the real mOnClickListener object. Create our own click-event proxy class // Approach 1: Create your own proxy class // ProxyOnClickListener ProxyOnClickListener = new ProxyOnClickListener(onClickListenerInstance); View.OnClickListener is an interface, so you can directly use dynamic Proxy mode // proxy. newProxyInstance with 3 parameters respectively: // local class loader; // The actual logic of the proxy Class, Object proxyOnClickListener = proxy.newProxyInstance (context.getClass().getClassLoader(), new Class[]{View.OnClickListener.class}, new InvocationHandler() { @Override public Object invoke(Object proxy, Method Method, Object[] args) throws Throwable {log. d("HookSetOnClickListener", "clickListener is hooked "); // Add your own logic return method.invoke(onClickListenerInstance, args); // execute proxied object logic}}); Set (mListenerInfo, proxyOnClickListener) to "Holder" using our own clickevent proxy class; } catch (Exception e) { e.printStackTrace(); Static class ProxyOnClickListener implements view.onClickListener {view.onClickListener oriLis; public ProxyOnClickListener(View.OnClickListener oriLis) { this.oriLis = oriLis; } @override public void onClick(View v) {log. d("HookSetOnClickListener", "HookSetOnClickListener"); if (oriLis ! = null) { oriLis.onClick(v); }}}Copy the code


Proguard has the following three functions:

  • Shrink: Detects and deletes unused classes, fields, methods, and features
  • Optimize: Analyze and Optimize Java bytecode
  • Obfuscate: Rename classes, fields, and methods using short, meaningless names

The rules

  • The keyword
The keyword describe
keep Preserves classes and members of classes to prevent confusion or removal
keepnames Preserves classes and members of classes to prevent confusion, and members that are not referenced are removed
keepclassmembers Keep only members of the class to prevent confusion or removal
keepclassmembernames Only members of the class are retained to prevent confusion, and members without references are removed
keepclasseswithmembers Preserves classes and members of classes, preventing confusion or removal, and preserves specified members
keepclasseswithmembernames Retain classes and members of classes to prevent confusion, retain specified members, and remove members that do not have references
  • The wildcard
The wildcard describe
Matches all fields in the class
Matches all methods in a class
Matches all constructors in a class
* Matches characters of any length, excluding package name delimiters (.)
** Matches characters of any length, including the package name delimiter (.)
* * * Matches any parameter type
  • Specifies that dictionaries can be used when obfuscating
-applymapping filename specifies to reuse a written map file as a mapping between old and new element names. -obfuscationdictionary filename Specifies a text file to generate the obfuscationdictionary name. Confused - classobfuscationdictionary filename to specify a class name dictionary - packageobfuscationdictionary filename specifies a confusing package name dictionary - Overloadaggressively confuses a large number of overloads and allows multiple method names to use the same confounding name (caution)Copy the code

Common template

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # for some basic instructions to add # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # code mixed compression ratio, Optimizationpasses 5 # OptimizationPasses 5 # optimizationPasses 5 # Blend to class called lowercase - dontusemixedcaseclassnames # specified not to ignore the public library classes - dontskipnonpubliclibraryclasses # this sentence can make us generate mapping file # after the confusion of the project Contains the name of the class - > confusion after the mapping relationship between the name of the class - verbose # specified not to ignore the class members of the public library - dontskipnonpubliclibraryclassmembers # don't do the divverify, preverify is one of the four steps of proguard, Android does not require PreVerify, and removing this step can speed up obfuscation. - DontPreVerify # Preserve annotations without obfuscating - KeepAttributes *Annotation*,InnerClasses # Avoid obfuscating generics - KeepAttributes Signature # Throw an exception when keep code line number - keepattributes SourceFile, LineNumberTable # specified confusion is to use an algorithm, the parameter is a filter behind the # this filter is recommended by the Google algorithm, generally do not change - optimizations. code/simplification/cast,! field/*,! Class/done / * # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # Android development in some of the need to keep the part # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # to retain the four major components, we use -keep public class * extends Android.app. Activity -keep public class * extends android.app.Appliction -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -keep public Class * extends android. View. The view - keep public class com. Android. Vending. Licensing. ILicensingService # support Keep class android.support.** {*; ** -keep public class * extends Android.support.v7.** -keep Public class * extends android. Support. The annotation. * * # retain R the following resources - keep class * * * R ${*; } # retain local native method is not be confused - keepclasseswithmembernames class * {native < the methods >; } # Keep the method arguments in the Activity as view methods, Keepclassmembers class extends Android.app.activity {public void keepClassMembers extends Android.app.activity {public void keepClassMembers extends Android.app.activity {public void keepClassMembers extends Android.app.activity {public void keepClassMembers extends Android.app.activity {public void keepClassMembers extends Android.app.activity *(android.view.View); {public static **[] values();} # keepClassMembers enum * {public static **[] values(); public static ** valueOf(java.lang.String); } # public class extends android.view.View {*** get*(); void set*(***); public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); } # keep class * implements android.os.Parcelable {public static final android.os.Parcelable$Creator *; } # keep Serializable classes from being confused-keepNames * implements java.io.Serializable -keepclassmembers * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; ! static ! transient <fields>; ! private <fields>; ! private <methods>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); Keepclassmembers class * {void *(**On*Event); keepclassMembers class * {void *(**On*Event); void *(**On*Listener); } # webView handling, project did not use to the webView can be ignored - keepclassmembers class FQCN. Of the javascript. Interface. For. WebView {public *; } -keepclassmembers class * extends android.webkit.webViewClient { public void *(android.webkit.WebView, java.lang.String, android.graphics.Bitmap); public boolean *(android.webkit.WebView, java.lang.String); } -keepclassmembers class * extends android.webkit.webViewClient { public void *(android.webkit.webView, java.lang.String); } # js -keepattributes JavascriptInterface -keep class android.webkit.JavascriptInterface { *; } -keepclassmembers class * { @android.webkit.JavascriptInterface <methods>; } # @Keep -keep,allowobfuscation @interface android.support.annotation.Keep -keep @android.support.annotation.Keep class  * -keepclassmembers class * { @android.support.annotation.Keep *; }Copy the code

Common custom obfuscation rules

# Wildcard * matches any length of character, but does not contain the package name delimiter (.) # wildcard ** matches characters of any length and contains the package name delimiter (.). Keep public class com.jasonwu.demo.Test {*; } # keep class com.jasonwu.demo.test.** {*; } # keep public class * com.jasonwu.demo.test {*; } # keep public class **.*model*.** {*; } # don't confuse the implementation of an interface - keep class * implements com. Jasonwu. Demo. TestInterface {*; } # keepclassMembers class com.jasonwu.demo.test {public <init>(); } # keepClassMembers class com.jasonwu.demo.Test {public void Test (java.lang.string); }Copy the code

Add separate obfuscated configuration to aar


Android {··· · defaultConfig {··· ··· ··· ··· ··· ··}Copy the code

Check for confusion and track anomalies

When Proguard is enabled, Proguard outputs the following files each build:

  • Dump. TXT describes the internal structure of all class files in APK.
  • Mapping.txt provides conversions between original and obfuscated class, method, and field names.
  • Seeds.txt lists classes and members that have not been obfuscated.
  • Usage.txt lists the code removed from APK.

These files are stored in the/build/outputs/mapping/release /. We can look at seeds.txt to see if it’s the one we want to keep, and usage.txt to see if it’s deleted incorrectly. The mapping.txt file is very important, because part of our code has been renamed, if there is a bug in this part, the classes or members in the corresponding exception stack information have also been renamed, so it is difficult to locate the problem. We can use the retrace script (retrace.bat on Windows; Retrace.sh) on Mac/Linux. It is located in the /tools/proguard/ directory. This script uses the mapping.txt file and your exception stack file to generate an unscrambled exception stack file so you can see where the problem is. The syntax for using retrace is as follows:

retrace.bat|retrace.sh [-verbose] mapping.txt [<stacktrace_file>]
Copy the code



In Android, the relationship between the three is as follows:

Since XML layout is so weak on Android, the Activity does most of the work, so MVC on Android is more like:


  • There’s some level of layering, model decoupling, controller and View not decoupling
  • Controller and View cannot be completely separated in Android, and controller becomes bloated
  • Easy to understand, fast development, high maintainability


By introducing the interface BaseView, let the corresponding view components such as activities, fragments to achieve BaseView, put the business logic in the Presenter layer, weaken the Model only view-related operations are completed by the View layer.


  • Completely solve the MVC View and Controller silly confused problem
  • However, as the business logic increases, a page can be very complex, the UI can change a lot, and there will be a lot of cases, which will cause the View interface to be very large
  • Easier to unit test


In MVP, views and Presenters hold each other so that they can call each other. In MVP, views and ViewModels are associated with Binding, and their previous association is handled by DataBinding.


  • Good solution for MVC and MVP issues
  • A ViewModel with more view states is expensive to build and maintain
  • However, the bidirectional binding of data and view makes it difficult to locate the source of a problem



Use the sample


Android {··· dataBinding {enabled = true}} Dependencies {··· implementation "androidx.fragment:fragment-ktx:$rootProject.fragmentVersion" implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.lifecycleVersion" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$rootProject.lifecycleVersion" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$rootProject.lifecycleVersion" }Copy the code


<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> <data> <variable name="viewModel" type="com.google.samples.apps.sunflower.viewmodels.PlantDetailViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" Android: layout_height = "match_parent" > < TextView... android: text = "@ {viewModel. Plant. The name}" / > </androidx.constraintlayout.widget.ConstraintLayout> </layout> PlantDetailFragment.kt class PlantDetailFragment : Fragment() { private val args: PlantDetailFragmentArgs by navArgs() private lateinit var shareText: String private val plantDetailViewModel: PlantDetailViewModel by viewModels { InjectorUtils.providePlantDetailViewModelFactory(requireActivity(), args.plantId) } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val binding = DataBindingUtil.inflate<FragmentPlantDetailBinding>( inflater, R.layout.fragment_plant_detail, container, false).apply { viewModel = plantDetailViewModel lifecycleOwner = this@PlantDetailFragment } PlantDetailViewModel. Plant. Observe (this) {plant - > / / update related UI} return binding. The root}}Copy the code


data class Plant (
    val name: String
Copy the code


class PlantDetailViewModel(
    plantRepository: PlantRepository,
    private val plantId: String
) : ViewModel() {

    val plant: LiveData<Plant>

    override fun onCleared() {

    init {
        plant = plantRepository.getPlant(plantId)
Copy the code


class PlantDetailViewModelFactory(
    private val plantRepository: PlantRepository,
    private val plantId: String
) : ViewModelProvider.NewInstanceFactory() {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return PlantDetailViewModel(plantRepository, plantId) as T
Copy the code


object InjectorUtils { private fun getPlantRepository(context: Context): PlantRepository {...} fun providePlantDetailViewModelFactory (context: context, plantId: String) : PlantDetailViewModelFactory { return PlantDetailViewModelFactory(getPlantRepository(context), plantId) } }Copy the code

The NDK development

The NDK stands for Native Development Kit. It is a set of tools that allow you to write and implement C/C++ in Android applications. You can build your own source code in your project or use existing pre-built libraries.

The NDK is used for the following purposes:

  • Get better performance from devices for computationally intensive applications, such as games or physics simulations
  • Reuse your own or other developers’ C/C++ libraries for cross-platform convenience.
  • The NDK integrates specific implementations of API specifications such as OpenSL and Vulkan to do things that cannot be done in the Java layer, such as improving audio performance
  • Increased decompilation difficulty

JNI basis

The data type

  • Basic data types
Java type Native type Symbol attribute Word length
boolean jboolean unsigned eight
byte jbyte unsigned eight
char jchar unsigned 16
short jshort A signed 16
int jnit A signed 32 –
long jlong A signed A 64 – bit
float jfloat A signed 32 –
double jdouble A signed A 64 – bit
  • Reference data type
Java reference types Native type Java reference types Native type
All objects jobject char[] jcharArray
java.lang.Class jclass short[] jshortArray
java.lang.String jstring int[] jintArray
Object[] jobjectArray long[] jlongArray
boolean[] jbooleanArray float[] jfloatArray
byte[] jbyteArray double[] jdoubleArray
java.lang.Throwable jthrowable

String String function operation

JNI function describe
GetStringChars / ReleaseStringChars Get or release a pointer to a Unicode encoded string (C/C++ string)
GetStringUTFChars / ReleaseStringUTFChars Get or release a pointer to a UTF-8 encoded string (C/C++ string)
GetStringLength Returns the length of the Unicode encoded string
getStringUTFLength Returns the length of the UTF-8 encoded string
NewString Converts a Unicode encoded C/C++ string to a Java string
NewStringUTF Converts utF-8 encoded C/C++ strings to Java strings
GetStringCritical / ReleaseStringCritical Gets or releases a pointer to the contents of a string (Java string)
GetStringRegion Gets or sets the content of the specified range of Unicode encoded strings
GetStringUTFRegion Gets or sets the contents of the specified range of utF-8 encoded strings

JNI is commonly used to access Java object methods


package com.example.myjniproject; public class MyJob { public static String JOB_STRING = "my_job"; private int jobId; public MyJob(int jobId) { this.jobId = jobId; } public int getJobId() { return jobId; }}Copy the code


#include <jni.h> extern "C" JNIEXPORT jint JNICALL Java_com_example_myjniproject_MainActivity_getJobId(JNIEnv *env, Jclass jobClz = env->GetObjectClass(job); / / according to the name of the class for class object jclass jobClz = env - > FindClass (" com/example/myjniproject/MyJob "); JfieldID fieldId = env->GetFieldID(jobClz, "jobId", "I"); JfieldID sFieldId = env->GetStaticFieldID(jobClz, "JOB_STRING", "Ljava/lang/String; ); JmethodID methodId = env->GetMethodID(jobClz, "getJobId", "()I"); JmethodID initMethodId = env->GetMethodID(jobClz, "<init>", "(I)V); Jint id = env->GetIntField(job, fieldId); Jint id = env->CallIntMethod(job, methodId); // create NewObject jobject newJob = env->NewObject(jobClz, initMethodId, 10); return id; }Copy the code

The NDK development

Basic development process

  • Declare native methods in Java
public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {

    protected void onCreate(Bundle savedInstanceState) {

        Log.d("MainActivity", stringFromJNI());

    private native String stringFromJNI();
Copy the code
  • inapp/src/mainCreate a CPP directory under the directory, create related CPP files, and implement related methods (shortcut keys can be used to quickly generate AS)


#include <jni.h>

extern "C" JNIEXPORT jstring JNICALL
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
Copy the code
  • The format of function names is as follows: Java_package name_class name_method name.
  • Extern “C” specifies that C naming styles are used to compile; otherwise, functions cannot be found when linking due to C and C++ naming styles
  • JNIEnv* : represents a pointer to the JNI environment through which to access the interface methods provided by JNI
  • Jobject: represents this in a Java object
  • JNIEXPORT and JNICALL: Macros defined by JNI can be found in the jni.h header file
  • Build the dynamic library using CMake or ndK-build



public static void load(String filename) {
    Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
Copy the code
  • callRuntimeRelevant native method


private static native String nativeLoad(String filename, ClassLoader loader, Class<? > caller);Copy the code
  • The implementation of native method is as follows:


Static void Dalvik_java_lang_Runtime_nativeLoad(const u4* args, JValue* pResult) {··· bool SUCCESS; assert(fileNameObj ! = NULL); // Convert Java library path String to native String fileName = dvmCreateCstrFromString(fileNameObj); // Convert Java library path String to native String fileName = dvmCreateCstrFromString(fileNameObj); success = dvmLoadNativeCode(fileName, classLoader, &reason); if (! success) { const char* msg = (reason ! = NULL) ? reason : "unknown failure"; result = dvmCreateStringFromCstr(msg); dvmReleaseTrackedAlloc((Object*) result, NULL); }...}Copy the code
  • dvmLoadNativeCodeFunction implementation is as follows:


bool dvmLoadNativeCode(const char* pathName, Object* classLoader, char** detail) { SharedLib* pEntry; void* handle; Detail... * = NULL; // If already loaded, return true pEntry = findSharedLibEntry(pathName); if (pEntry ! = NULL) { if (pEntry->classLoader ! = classLoader) {··· return false; }... the if (! checkOnLoadResult(pEntry)) return false; return true; } Thread* self = dvmThreadSelf(); ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_VMWAIT); Handle = dlopen(pathName, RTLD_LAZY); handle = dlopen(pathName, RTLD_LAZY); dvmChangeStatus(self, oldStatus); // Create a new entry SharedLib* pNewEntry; pNewEntry = (SharedLib*) calloc(1, sizeof(SharedLib)); pNewEntry->pathName = strdup(pathName); pNewEntry->handle = handle; pNewEntry->classLoader = classLoader; dvmInitMutex(&pNewEntry->onLoadLock); pthread_cond_init(&pNewEntry->onLoadCond, NULL); pNewEntry->onLoadThreadId = self->threadId; SharedLib* pActualEntry = addSharedLibEntry(pNewEntry); if (pNewEntry ! = pActualEntry) {freeSharedLibEntry(pNewEntry); return checkOnLoadResult(pActualEntry); } else {··· bool result = true; void* vonLoad; int version; // Call the so library JNI_OnLoad method vonLoad = dlsym(handle, "JNI_OnLoad"); If (vonLoad == NULL) {···} else {// call JNI_Onload to override the classloader. OnLoadFunc func = (OnLoadFunc)vonLoad; Object* prevOverride = self->classLoaderOverride; self->classLoaderOverride = classLoader; oldStatus = dvmChangeStatus(self, THREAD_NATIVE); ··· version = (*func)(gDVMjni.jnivm, NULL); dvmChangeStatus(self, oldStatus); self->classLoaderOverride = prevOverride; if (version ! = JNI_VERSION_1_2 && version ! = JNI_VERSION_1_4 && version ! = JNI_VERSION_1_6) {··· result = false; } else {···}} if (result) pNewEntry->onLoadResult = kOnLoadOkay; else pNewEntry->onLoadResult = kOnLoadFailed; pNewEntry->onLoadThreadId = 0; // Release the lock resource dvmLockMutex(&pNewEntry->onLoadLock); pthread_cond_broadcast(&pNewEntry->onLoadCond); dvmUnlockMutex(&pNewEntry->onLoadLock); return result; }}Copy the code

CMake builds NDK projects

CMake is an open source cross-platform tool for building, testing, and packaging software. Starting with Android Studio 2.2, Android Sudio uses CMake by default to build native libraries in conjunction with Gradle.

To start, just add relevant information in app/build.gradle:

Android {··· defaultConfig {··· · externalNativeBuild {cmake {cppFlags ""}} NDK {abiFilters 'arm64-v8a', 'armeabi-v7a' {externalNativeBuild {cmake {path "cmakelists.txt"}}Copy the code

Then create a new cmakelists. TXT file in the corresponding directory:

The cmake_minimum_required(VERSION 3.4.1) # add_library() command is used to add library # native-lib corresponding to the name of the generated library # SHARED # SRC /main/ CPP /native-lib. CPP specifies the path to the source file. add_library( # Sets the name of the library. native-lib # Sets the library as a shared library. SHARED # Provides a Relative path to your source file(s).src /main/ CPP /native lib.cpp) # find_library And store its path as a variable. You can use this variable to reference the NDK library find_library(# Sets the name of the path variable.log -lib # Specifies the name of the NDK in other parts of the build script Library that # you want CMake to locate.log) # The pre-built NDK library already exists on the Android platform, so there is no need to build or package it into APK. # Since NDK libraries are already part of CMake's search path, you only need to provide CMake with the name of the library you want to use, Native libraries(# Specifies the target library. native-lib # Links the target Library to the log library # included in the NDK. ${log-lib}) ···Copy the code

Common Android NDK native API

Support for THE NDK API level Key native apis including
3 Java native interface #include <jni.h>
3 Android logging API #include <android/log.h>
5 OpenGL ES 2.0 #include <GLES2/gl2.h> #include <GLES2/gl2ext.h>
8 Android bitmap API #include <android/bitmap.h>
9 OpenSL ES #include <SLES/OpenSLES.h> #include <SLES/OpenSLES_Platform.h> #include <SLES/OpenSLES_Android.h> #include <SLES/OpenSLES_AndroidConfiguration.h>
9 Native application API #include<android/ rect.h> #include<android/ window.h> #include<android/native_activity.h> ··· ·
18 OpenGL ES 3.0 #include <GLES3/gl3.h> #include <GLES3/gl3ext.h>
21 Native media API #include <media/ ndkMediacodec. h> #include <media/ ndkMediacrypto.h > ··· ·
24 Native Camera API # include < camera/NdkCameraCaptureSession. H > # include < > camera/NdkCameraDevice. H · · ·

Class loader

Parental delegation pattern

When a specific class loader receives a request to load a class, it first delegates the loading task to the parent class loader, recursively. If the parent class loader can complete the class loading task, it returns successfully. Only if the parent class loader is unable to complete the load task, do the load itself.

Because this avoids double loading, there is no need for the child ClassLoader to load the class again when the parent has already loaded the class. Without this delegate pattern, we can use custom classes to dynamically replace some core classes at any time, which is a huge security risk.


The DexClassLoader overloads the findClass method and calls its internal DexPathList to load the class. The DexPathList is generated when the DexClassLoader is constructed and contains the DexFile.

DexPathList.java public Class findClass(String name) { for (Element element : dexElements) { DexFile dex = element.dexFile; if (dex ! = null) { Class clazz = dex.loadClassBinaryName(name, definingContext); if (clazz ! = null) { return clazz; } } } return null; }Copy the code