Webrtc中Java層和C++層JNI對應規則和代碼查找方法

1. WebRTC JNI接口文件生成

Webrtc 中,Java API是C++層的一層接口包裝,但是沒有像Android中那樣,可以直接對應的找到Java層類
對應的C++層的JNI接口文件。

1. Webrtc中Java類中的註解

在Webrtc中,Java層使用註解的方式來標記需要進行JNI接口生成的頭文件和函數選項:
用到的註解:

  1. @JNINamespace(“webrtc::jni”) 標記生成的頭文件中的函數聲明位於哪個命名空間,
    這個表示生成的函數形式爲
namespace webrtc {
    namespace jni {
      ///函數...  
    }
}

  1. @NativeClassQualifiedName(“CPPClass::InnerClass”) 制定要調用的目標對象的方法,這個表示要調用的是CPPClass::InnerClass的本地方法(CPPClass指的是對應的包含生成的.h文件的.cpp/.cc文件中的類 CPPclass)

沒有指定NativeClassQualifiedName的時候,調用的就是include 了生成的頭文件的源文件的同名方法實現;

    @NativeClassQualifiedName("CPPClass::InnerClass")
    private native double nativeMethodOtherP0(long nativePtr);

對應調用c++層的

JNI_GENERATOR_EXPORT jdouble
    Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethodOtherP0(JNIEnv*
    env, jobject jcaller,
    jlong nativePtr) {
    //指定調用用CPPClass::InnerClass中的方法
  CPPClass::InnerClass* native =
      reinterpret_cast<CPPClass::InnerClass*>(nativePtr);
  CHECK_NATIVE_PTR(env, jcaller, native, "MethodOtherP0", 0);
  //調用方法
  return native->MethodOtherP0(env, base::android::JavaParamRef<jobject>(env,
      jcaller));
}
  1. @CalledByNative(“InnerClass”) 指定該標記對象是由native向Java層調用的,參數告訴底層該方法屬於哪一個類中的方法(底層需要獲取Java層的包名路徑來調用該方法)。 比如這個表示底層應該調用的是java層的InnerClass中的方法。

2. JNI頭文件生成和代碼跟蹤方法

上面講的Java層的註解只是一個標記,並不是用Java的註解處理器來進行處理的,而是使用Python腳本來解析和生成文件,類,函數聲明和函數實現的。

  1. JNI接口的頭文件生成是使用文件:
    src\base\android\jni_generator\jni_generator.py
    來進行解析和生成的。

  2. 生成的文件爲 “java_name” + _jni.h
    比如Java文件爲AudioTest, 那麼如果有JNINamespace註解,那就會生成一個AudioTest_jni.h文件

  3. 調用跟蹤方法:
    比如:

  • 1.java層:
@org.webrtc.JNINamespace("webrtc::jni") //首先有這個註解,命名空間爲webrtc::jni
public class AudioTrack extends org.webrtc.MediaStreamTrack {
  public AudioTrack(long nativeTrack) {
    super(nativeTrack);
  }

 ...
  public void setVolume(double volume) {
    nativeSetVolume(super.nativeTrack, volume);
  }

  private static native void nativeSetVolume(long track, double volume); //找這個native方法
}
  • 2.生成的對應頭文件爲"AudioTrack_jni.h", 那麼就找那個文件include了AudioTrack_jni.h:

這個只生成頭文件,源文件需要自己實現,我們只需要找到對應的源文件就可以知道調用的對象是那個函數;

//src\sdk\android\src\jni\pc\audiotrack.cc
#include "api/mediastreaminterface.h"
#include "sdk/android/generated_peerconnection_jni/jni/AudioTrack_jni.h"

namespace webrtc {
namespace jni {

//調用的native方法就是這個
static void JNI_AudioTrack_SetVolume(JNIEnv*,
                                     const JavaParamRef<jclass>&,
                                     jlong j_p,
                                     jdouble volume) {
  rtc::scoped_refptr<AudioSourceInterface> source(
      reinterpret_cast<AudioTrackInterface*>(j_p)->GetSource());
  source->SetVolume(volume);
}

}  // namespace jni
}  // namespace webrtc

2. 生成規則

  1. 一般默認生成的頭文件和Java的函數所在類的報名/類型/函數名拼接規則相匹配
  2. 在WebRTC中,也是同樣適用,但是在沒有生成的前提下,我們發現我們所調用的函數名字並不適應於上述規則,這個是因爲在匹配生成的時候,也同時生成了一個簡單的Native接口,作爲JNI接口的轉換,該轉換接口就是我們在生成之前找到的源碼中看到的函數接口,規則是:

JNI_ + "class_name" + "Method_name()" //注意,method匹配的方法去掉了native前綴的大駝峯形式;

比如:

package org.chromium.example.jni_generator;
@JNINamespace("base::android")
class SampleForTests {
   	private native void nativeSetNonPODDatatype(Rect rect);
}

會生成爲

namespace base {
namespace android {
//轉換的簡單匹配接口,我們在生成之前看到的接口就是這個,原文件中會對這個接口進行實現;
static void JNI_SampleForTests_SetNonPODDatatype(JNIEnv* env, const
    base::android::JavaParamRef<jobject>& jcaller,
    const base::android::JavaParamRef<jobject>& rect);

//這個是生成的JNI規則匹配接口
JNI_GENERATOR_EXPORT void
    Java_org_chromium_example_jni_1generator_SampleForTests_nativeSetNonPODDatatype(JNIEnv*
    env, jobject jcaller,
    jobject rect) {
    //接口中默認調用了生成的轉換的簡單匹配接口
  return JNI_SampleForTests_SetNonPODDatatype(env,
      base::android::JavaParamRef<jobject>(env, jcaller),
      base::android::JavaParamRef<jobject>(env, rect));
}

}
}

3. 總結

代碼跟蹤流程可以總結如下:

  1. 比如Java類是AudioTest, 其中有一個native方法 nativeTest:
@JNINamespace("base::android")
public class AudioTest {
 public void nativeTest();
}
  1. 找include了 AudioTest_jni.h 的源文件;
  2. 找到之後, 就可找到調用的目標函數: JNI_AudioTest_Test();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章