Android NDK模拟native crash

最近需要模拟出一个native crash,简单来说就是声明一个native方法,然后在c/c++层实现这个方法并触发一个异常即可。由于之前没有接触过这些,所以实现起来还是花费了挺多的时间的,这期间也涉及到了很多知识点或概念,如NDKJNI,abi以及so等。

JNI的全称为Java Native Interface,即Java本地接口,类似于AIDL,提供了若干的API实现了Java和其他语言的通信(主要是CC++),目的是使Java方法能够调用C实现的一些函数。

NDK全称为Native Development Kit,它是一个工具集,NDK允许用户使用类似C/C++之类的原生原生代码执行部分程序,其内部还是采用JNI机制实现的。

在对上述概念有了一个基础了解后,才好理解后面要做的事情都是在干什么,下面就以楼主现在需要实现的这个小功能为例阐述一个如何通过NDK实现一个native方法:

一、配置安装NDK

楼主的运行环境是Ubuntu,开发工具选用的Android Studio。所以NDK的安装比较简单:

  1. 打开Android Studio,File->Settings->Appearance & Behavior->System Settings->Android SDK,然后选中安装SDK Tools中的NDK即可。

  2. 安装好NDK后还需要给项目设置NDK版本,点击File->Project Structure->SDK Location,然后设置NDK的目录,我这里下来了多个NDK版本,所以我选择了其中一个版本。

  3. 安装好NDK后可以先尝试在Android StudioTerminal终端中输入ndk-build命令看是否有反应。如果报错未找到命令的话就还需要配置一下环境变量,命令如下(详细内容参考Android JNI和NDK学习(01)--搭建NDK开发环境):
    NDK路径就用上面自己配置的那个路径就可以了。

    # 替换成自己的ndk路径
    export NDK_HOME=/home/hy/Android/Sdk/ndk/21.3.6528147
    export PATH=$PATH:$NDK_HOME
    source ~/.bashrc
    

    配置完成后在终端输入ndk-build命令应该就会有输出了,如果Studio中的Terminal还是未找到命令可以重启或者在系统终端中cd到项目目录再输入命令。

二、编写so库准备工作

NDK环境配置好了之后就可以开始编写代码了。

  1. 创建TestJNI.Java声明一个native方法
    public class TestJNI {
    
        static {
            System.loadLibrary("TestJNI");
        }
    
        public native void crashTest();
    }
    
  2. 使用javac生成.class文件
    javac TestJNI.java
    
  3. 使用javah生成.h文件,注意此时命令所处的位置应该是项目的java目录下
    以我的项目为例此时命令应到是在~/AndroidStudioProjects/NativeCrashTest/app/src/main/java目录下执行的,否则会报找不到类文件的错误。
    javah  -jni com.example.nativecrashtest.jni.TestJNI
    
  4. 编写C/C++实现native方法:
    #include "jni.h"
    #include "com_example_nativecrashtest_jni_TestJNI.h"
    #include <cstdio>
    
    JNIEXPORT void JNICALL 
    Java_com_example_nativecrashtest_jni_TestJNI_crashTest(JNIEnv *, jobject) {
        printf("make a crash");
        //TODO 制造一个native carash
        int *p = 0; //空指针
        *p = 1; //写空指针指向的内存,产生SIGSEGV信号,造成crash
    }
    
  5. 创建Android.mk文件,添加如下代码:
    记得将LOCAL_MODULELOCAL_SRC_FILES替换成你自己的文件名。
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE        := TestJNI         
    LOCAL_SRC_FILES     := TestJni.cpp      
    include $(BUILD_SHARED_LIBRARY)
    
  6. 配置app下的build.gradle文件
    android {
        ...
    
        defaultConfig {
            ...
    
            ndk {
                moduleName "TestJNI"
                abiFilters "armeabi-v7a"
            }
        }
    
        externalNativeBuild {
            ndkBuild {
                path "src/main/java/com/example/nativecrashtest/jni/Android.mk"
            }
        }
    
        sourceSets {
            main() {
                jniLibs.srcDirs = ['libs']
            }
        }
    
        ...
    }
    

同样这里需要根据自己的情况修改相应的文件名或者路径,其中abiFilters相关知识可以参考Android ABI,如果仅是测试的话可以通过adb shell cat /proc/cpuinfo命令查看自己的测试机类型(参考如何查看Android设备的ABI)。

最后的项目目录结构图如下:


项目结构图

三、生成.so文件并调用实现方法

  1. 相关准备工作完成之后,进入到Android.mk所在目录执行ndk-build命令即可:
hy@hy-OptiPlex-7070:~/AndroidStudioProjects/NativeCrashTest/app/src/main/java/com/example/nativecrashtest/jni$ ndk-build
Android NDK: APP_PLATFORM not set. Defaulting to minimum supported version android-16.    
[arm64-v8a] Compile++      : TestJNI <= TestJni.cpp
[arm64-v8a] SharedLibrary  : libTestJNI.so
[arm64-v8a] Install        : libTestJNI.so => libs/arm64-v8a/libTestJNI.so
[armeabi-v7a] Compile++ thumb: TestJNI <= TestJni.cpp
[armeabi-v7a] SharedLibrary  : libTestJNI.so
[armeabi-v7a] Install        : libTestJNI.so => libs/armeabi-v7a/libTestJNI.so
[x86] Compile++      : TestJNI <= TestJni.cpp
[x86] SharedLibrary  : libTestJNI.so
[x86] Install        : libTestJNI.so => libs/x86/libTestJNI.so
[x86_64] Compile++      : TestJNI <= TestJni.cpp
[x86_64] SharedLibrary  : libTestJNI.so
[x86_64] Install        : libTestJNI.so => libs/x86_64/libTestJNI.so

命令执行完成后可以看到项目目录下多出来一个libs文件夹,里面有生成的.so文件。
ps:如果Studio的终端命令行还是提示未找到命令就通过系统终端跳转到.mk文件所在目录然后执行命令即可。

  1. 添加一个button按钮点击事件,在点击按钮时触发crash
//MainActivity.java
public class MainActivity extends WearableActivity {

    private TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTextView = (TextView) findViewById(R.id.text);

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                com.example.nativecrashtest.jni.TestJNI testJNI = new TestJNI();
                testJNI.crashTest();
            }
        });

        // Enables Always-on
        setAmbientEnabled();
    }
}
  1. 启动demo点击按钮触发崩溃,然后执行adb shell ls -l /data/system/dropbox命令,可以看到多出来了一个data_app_native_crash@1595486083697.txt.gz文件,取出解压就可以看到完整的crash调用栈信息了。

参考文章

?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351