java 远程调用native 方法_从 Java 调用一个 Native 函数

Java 调用Native函数,实际就是 JNI 调用。

我们将关注 Java端如何把参数传递到 Native,Java调用Native函数时,额外的做了哪些事情。

在前面分析Native 调用Java 函数时,直接打断点,就能得到调用 backtrace,那是得益于 GDB 对 Native代码的调试支持,

可以根据包含 symbols的 so库,自动帮忙我们理清 pc 对应的代码以及其所在文件,行号,函数等信息;这极大的帮助了我们分析流程;

而 Java 调用 Native 就不那么方便的调试了;因为:1.GDB 并不是调试 java 代码的工具 2.当 java代码存在native code时,其native code

是存放在 oat 文件中,虽然其是一个 ELF文件,但是其代码和都嵌入新建的 "oatdata" 和 “oatexec” 段,其组织结构并不能被 GDB 所识别;

JNI 方法的执行有两种情况:

1.在 java 中声明的 native 限定的方法在APP安装时,已经被编译了,那么从其他 java 方法调用该方法时,会直接跳转到其native code;

2.声明为 native 的java方法没有被编译,那么会经过 trampoline 以及 art_jni_dlsym_lookup_stub 配合完成调用;

在安装APP,编译dex时,根据compiler-filter决定是否编译 JNI method:

bool CompilerFilter::IsJniCompilationEnabled(Filter filter) {

switch (filter) {

case CompilerFilter::kVerifyNone:

case CompilerFilter::kVerifyAtRuntime: return false;

case CompilerFilter::kVerifyProfile:

case CompilerFilter::kInterpretOnly:

case CompilerFilter::kSpaceProfile:

case CompilerFilter::kSpace:

case CompilerFilter::kBalanced:

case CompilerFilter::kTime:

case CompilerFilter::kSpeedProfile:

case CompilerFilter::kSpeed:

case CompilerFilter::kEverythingProfile:

case CompilerFilter::kEverything: return true;

}

UNREACHABLE();

}

static bool InstructionSetHasGenericJniStub(InstructionSet isa) {

switch (isa) {

case kArm:

case kArm64:

case kThumb2:

case kMips:

case kMips64:

case kX86:

case kX86_64: return true;

default: return false;

}

}

如果compiler-filter是下面的 10种的一个,则必定会编译 JNI method;

如果是 kVerifyNone 或者 kVerifyAtRuntime ,且是所支持的指令集,则不会编译 JNI method;

在这里我们先分析第一种情况,即 Native java Method被编译的情况,此时,如果其他java 函数调用该函数,

会直接跳转到其被编译出来的 native 代码;

举个栗子:

SystemClock.java 的一个 native 函数 :    native public static long uptimeMillis();

Thread 1 "miui.yellowpage" hit Breakpoint 1, art::JniMethodStart (self=0x7f86e96a00) at art/runtime/entrypoints/quick/quick_jni_entrypoints.cc:39

39    if (!native_method->IsFastNative()) {

(gdb) bt

#0  art::JniMethodStart (self=0x7f86e96a00) at art/runtime/entrypoints/quick/quick_jni_entrypoints.cc:39

#1  0x00000000751aa338 in ?? ()

Backtrace stopped: previous frame inner to this frame (corrupt stack?)

(gdb) p self->tlsPtr_->managed_stack->top_quick_frame_

$2 = (art::ArtMethod **) 0x7ff85caa80

(gdb) x 0x7ff85caa80

0x7ff85caa80:   0x7147c530

(gdb) art_get_method_name_by_method_id 0x7147c530

android.os.SystemClock.uptimeMillis "()J"

JNI Method的编译是通过 ArtJniCompileMethodInternal 这个函数来为Jni Method生成代码的,我们先了解一下 JNI method的编译流程:

看下运行时 这个函数的Native code,实际上这个 code 就是 uptimeMillis() 这个函数被编译成native code在 oat文件中的存放;

72f2c000-748ae000 r--p 00000000 103:1d 2065 /system/framework/arm64/boot-framework.oat

748ae000-759d9000 r-xp 01982000 103:1d 2065 /system/framework/arm64/boot-framework.oat

759d9000-759da000 r--p 02aad000 103:1d 2065 /system/framework/arm64/boot-framework.oat

759da000-759db000 rw-p 02aae000 103:1d 2065 /system/framewor

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值