Native开发涉及的一些知识点

32 阅读1分钟

关于extern "C"

  1. 如果我们使用c++想要调用c语言写的库中的函数,需要使用

  2. c++面向对象,支持重载,会对类进行“名称修饰”。

    eg:c++中想要调用c中的add(int a,int b),它可能寻找的函数名称是add_int_int(int,int),不写的话会导致找不到

  3. 如下:

#ifdef __cplusplus
extern "C" {
#endif
// xxx
#ifdef __cplusplus
}
#endif

关于jnienv

  1. 它是执行jni函数表的指针,用于jvm跟本地代码之间的通信。
  2. 每个线程都有自己的jnienv

两个lib的native依赖

可以参考matrix的方式

github.com/Tencent/mat…

子线程获取env

// native中用来获取每个线程的JniEnv指针

#include "managed_jnienv.h"
#include <pthread.h>
#include <cstdlib>
namespace JniInvocation {
    static JavaVM *g_VM = nullptr;
    static pthread_once_t g_onceInitTls = PTHREAD_ONCE_INIT;
    static pthread_key_t g_tlsJavaEnv;
    void init(JavaVM *vm) {
        if (g_VM) return;
        g_VM = vm;
    }

    JavaVM *getJavaVM() {
        return g_VM;
    }

    JNIEnv *getEnv() {
        JNIEnv *env;
        int ret = g_VM->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
        if (ret != JNI_OK) {
            pthread_once(&g_onceInitTls, []() {
                pthread_key_create(&g_tlsJavaEnv, [](void *d) {
                    if (d && g_VM)
                        g_VM->DetachCurrentThread();
                });
            });

            if (g_VM->AttachCurrentThread(&env, nullptr) == JNI_OK) {
                pthread_setspecific(g_tlsJavaEnv, reinterpret_cast<const void*>(1));
            } else {
                env = nullptr;
            }
        }
        return env;
    }
}   // namespace JniInvocation

子线程无法获取应用的类

原因是通过上面的方式获取的env只能加载系统类,不能加载自己写的类。

解决:

定义全局的jclass,在JNI_OnLoad回调中初始化

关于JNI_OnLoad

JNI_OnLoad(JavaVM *vm, void *)

可以理解为jni的入口,java中调用system.loadLibrary("xx")加载so库的时候会调用该方法,可以做几件事

  1. 保存javaVm方便其他线程使用env
  2. 注册跟java方法对应的native方法
  3. 获取子线程需要使用的jclass设置为全局变量(注意释放)

Crash的时候如何定位具体的代码行号

gitbash里面输入:

$ adb logcat | C:/Users/wangzeqi/AppData/Local/Android/Sdk/ndk/21.1.6352462/prebuilt/windows-x86_64/bin/ndk-stack.cmd -sym D:/github/AnrMonitor/lib_anr/build/intermediates/merged_native_libs/debug/out/lib/arm64-v8a


static void *quitSigRunnable(void *args) {

    bool fromMyself = *(bool *) args;

    if (!fromMyself) {

        callBackQuitSigFromOtherProcess();

    }

    sendQuit2SignalCatcher();

    return nullptr;//void * 必须return!!!!否则编译不报错,但是运行的时候会出错!!!!!

}