Android源码中学习JNI那些事--关键技巧

92 篇文章 66 订阅
92 篇文章 73 订阅

hi,粉丝朋友们大家好:
今天来给大家分享一下JNI的一个关键技术知识点,也是经常在JNI面试中会被面试问道一个问题,一般问题如下:
“JNI开发中请问如果想要一个存native线程中执行的native方法需要调用到Java层应该要怎么做?”
大家注意这个问题哈,是纯native线程和方法,即没有我们正常jni调用的env环境的,正常的如果jni方法是由java层调用到jni一般都是自带了JNIEnv变量如下:
在这里插入图片描述

拿getMemInfo举例子,如:
java层:

public static native void getMemInfo(long[] outSizes);

转变成了native层面代码就是如下:

static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)

大家看这里是不是自带了一个变量JNIEnv *env,有了这里env后再想调用Java层面的方法就很简单,具体看参考如下:
比如经常Java调用jni时候。

tatic void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray out)
{
    char buffer[1024];
    size_t numFound = 0;

    if (out == NULL) {
        jniThrowNullPointerException(env, "out == null");//抛出空指针到java
        return;
    }
    //省略。。。。
}

jniThrowNullPointerException方法就需要传递env,jniThrowNullPointerException最后调用到了jniThrowException:如下

// libnativehelper/JNIHelp.cpp
extern "C" int jniThrowException(C_JNIEnv* env, const char* className, const char* msg) {
    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);

    if ((*env)->ExceptionCheck(e)) {
        /* TODO: consider creating the new exception with this as "cause" */
        scoped_local_ref<jthrowable> exception(env, (*env)->ExceptionOccurred(e));
        (*env)->ExceptionClear(e);

        if (exception.get() != NULL) {
            std::string text;
            getExceptionSummary(env, exception.get(), text);
            ALOGW("Discarding pending exception (%s) to throw %s", text.c_str(), className);
        }
    }

    scoped_local_ref<jclass> exceptionClass(env, findClass(env, className));
    if (exceptionClass.get() == NULL) {
        ALOGE("Unable to find exception class %s", className);
        /* ClassNotFoundException now pending */
        return -1;
    }

    if ((*env)->ThrowNew(e, exceptionClass.get(), msg) != JNI_OK) {
        ALOGE("Failed throwing '%s' '%s'", className, msg);
        /* an exception, most likely OOM, will now be pending */
        return -1;
    }

    return 0;
}


这里就需要使用env来获取对应的java类,及对应属性,方法等

回到面试题目,人家要求没有纯native线程里面native方法,即说明这种情况下肯定不自带JNIEnv的,故这里该怎么办呢?
在这里插入图片描述

不自带JNIEnv,但是调用java又需要JNIEnv,故得想方法构造出JNIEnv具体如下:
在这里插入图片描述

下面以一个Android源码中实战例子来说明:
源码位子参考:

frameworks/base/core/jni/android/graphics/SurfaceTexture.cpp

1、获取JavaVM,通过AndroidRuntime::getJavaVM()获取JavaVM
2、通过JavaVM绑定到当前线线程获取JNIEnv,通过vm->AttachCurrentThread方法中参数赋值JNIEnv

JNIEnv* JNISurfaceTextureContext::getJNIEnv(bool* needsDetach) {
    *needsDetach = false;
    JNIEnv* env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        JavaVMAttachArgs args = {
            JNI_VERSION_1_4, "JNISurfaceTextureContext", NULL };
        JavaVM* vm = AndroidRuntime::getJavaVM();//获取JavaVM
        int result = vm->AttachCurrentThread(&env, (void*) &args);//赋值env
        if (result != JNI_OK) {
            ALOGE("thread attach failed: %#x", result);
            return NULL;
        }
        *needsDetach = true;
    }
    return env;
}

3、使用env:

void JNISurfaceTextureContext::onFrameAvailable(const BufferItem& /* item */)
{
    bool needsDetach = false;
    JNIEnv* env = getJNIEnv(&needsDetach);
    if (env != NULL) {
        env->CallStaticVoidMethod(mClazz, fields.postEvent, mWeakThiz);//使用env调用java方法
    } else {
        ALOGW("onFrameAvailable event will not posted");
    }
    if (needsDetach) {
        detachJNI();
    }
}

4、不需要使用了记得与当前线程解绑定,调用JavaVM的DetachCurrentThread方法

void JNISurfaceTextureContext::detachJNI() {
    JavaVM* vm = AndroidRuntime::getJavaVM();
    int result = vm->DetachCurrentThread();//解绑定
    if (result != JNI_OK) {
        ALOGE("thread detach failed: %#x", result);
    }
}

如果需要学习更多framework只是和视频可以b站关注:千里马学框架,购买课程最好加入422901085群里找千里马要优惠和答疑

课程答疑和新课信息:QQ交流群:422901085进行课程讨论,加群主qq享受 优惠
FrameWork入门课视频链接:https://edu.csdn.net/course/detail/30298
FrameWork实战课1视频链接:https://edu.csdn.net/course/detail/30275
FrameWork跨进程通信视频链接:https://edu.csdn.net/course/detail/35911
专题博客系列:
Android 8.1 zygote 启动过程源码
Android Framework实战视频–Zygote的fork进程篇
Android Framework实战视频–SystemServer启动篇
Android Framework实战视频–SystemServer启动FallbackHome篇
Android Framework实战视频–FallbackHome进程启动及Activity启动篇
Android Framework实战视频–FallbackHome结束启动Launcher篇
Android Framework实战视频–BootAnimation的启动源码分析(Android8.1)

Android Framework实战视频–init进程的bootanimation启动源码分析(补充Android 10部分的BootAnimation的启动源码分析)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值