前言
上一章节已经梳理了通过加载libart.so, JNI_CreateJavaVM成功返回,虚拟机就处于就绪状态了,可以接受jni调用了。
虚拟机分为java和native两个层面,这两层间的通信就是jni,通常虚拟机的创建和管理都是在native层,然后通过jni来与java层互访,会有一个JNIEnv类型的指针变量,就是pEnv,他是以指向指针的指针做为参数的。这个JNIEnv指针是访问JVM的关键,真正的实现是JNIEnvExt。
art/runtime/jni_env_ext.h
#include <jni.h> ===> libnativehelper/include/include_jni/jni.h
struct JNIEnvExt : public JNIEnv {
static JNIEnvExt* Create(Thread* self, JavaVMExt* vm);
~JNIEnvExt();
}
涉及源码
platform/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/core/jni/android_util_Binder.cpp
/frameworks/base/core/jni/core_jni_helpers.h
/libnativehelper/JNIHelp.cpp
/art/runtime/jni_internal.cc
一、虚拟机启动回调-onVmCreated
注册jni之前,虚拟机已经启动成功后,一个回调onVmCreated
onVmCreated,虚拟机成功创建完成,需要通过回调函数onVmCreate()通知用户,这里的调用者就是AndroidRuntime的继承类AppRuntime来完成,如果是zygote启动的,则不做任何逻辑,直接return。
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
... //打印一些日志,获取ANDROID_ROOT环境变量
onVmCreated(env);//表示虚拟创建完成,但是里面是空实现
if (startReg(env) < 0) {注册JNI函数
ALOGE("Unable to register all android natives\n");
return;
}
... //JNI方式调用ZygoteInit类的main函数
}
二、注册JNI
2.1 startReg
定义在platform/frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startReg(JNIEnv* env)
{
ATRACE_NAME("RegisterAndroidNatives");
/*
* This hook causes all future threads created in this process to be
* attached to the JavaVM. (This needs to go away in favor of JNI
* Attach calls.)
*/
androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
//设置Android创建线程的函数javaCreateThreadEtc,这个函数内部是通过Linux的clone来创建线程的,这个调用会让后面创建的新线程都会hooked到JavaVM上。后续线程专项会重点介绍
....
env->PushLocalFrame(200);//创建一个200容量的局部引用作用域,这个局部引用其实就是局部变量
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) { //注册JNI函数
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);//释放局部引用作用域
return 0;
}
startReg首先是设置了Android创建线程的处理函数,然后创建了一个200容量的局部引用作用域,用于确保不会出现OutOfMemoryException,
最后就是调用register_jni_procs进行JNI注册
2.1.1 register_jni_procs
定义在platform/frameworks/base/core/jni/AndroidRuntime.cpp
static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env)
{
for (size_t i = 0; i < count; i++) {
if (array[i].mProc(env) < 0) { //调用mProc, 是一个函数指针
return -1;
}
}
return 0;
}
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
它的处理是交给RegJNIRec的mProc,RegJNIRec是个很简单的结构体,mProc是个函数指针
我们看看register_jni_procs传入的RegJNIRec数组gRegJNI,里面就是一堆的函数指针
extern int register_android_os_Binder(JNIEnv* env);
extern int register_android_os_Process(JNIEnv* env);
static const RegJNIRec gRegJNI[] = {
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_com_android_internal_os_ZygoteInit),//重点拿这个Zygote的JNI 注册来分析
......
REG_JNI(register_android_os_Binder), //重点拿这个binder的JNI 注册来分析
.....
}
REG_JNI是一个宏定义
#define REG_JNI(name) { name }
struct RegJNIRec {
int (*mProc)(JNIEnv*);
};
也就是说REG_JNI(register_com_android_internal_os_ZygoteInit)这句就相当于,{register_com_android_internal_os_ZygoteInit},
也就是将register_com_android_internal_os_ZygoteInit强转为 int (mProc)(JNIEnv) 这样一个方法指针,于是就可以array[i].mProc(env)这样调用,
等同于调用register_com_android_internal_os_ZygoteInit(JNIEnv* env)这个方法
再看看register_com_android_internal_os_ZygoteInit,这实际上是自定义JNI函数并进行动态注册的标准写法,
内部是调用JNI的RegisterNatives,这样注册后,Java类ZygoteInit的native方法nativeZygoteInit就会调用com_android_internal_os_ZygoteInit_nativeZygoteInit函数
int register_com_android_internal_os_ZygoteInit(JNIEnv* env)
{
const JNINativeMethod methods[] = {
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_ZygoteInit_nativeZygoteInit },
};
return jniRegisterNativeMethods(env, "com/android/internal/os/ZygoteInit",
methods, NELEM(methods));
}
/frameworks/base/core/jni/android_util_Binder.cpp
/frameworks/base/core/jni/android_util_Binder.cpp
int register_android_os_Binder(JNIEnv* env)
{
//注册Binder
if (int_register_android_os_Binder(env) < 0)
return -1;
//注册BinderInternal
if (int_register_android_os_BinderInternal(env) < 0)
return -1;
//注册BinderProxy
if (int_register_android_os_BinderProxy(env) < 0)
return -1;
jclass clazz = FindClassOrDie(env, "android/util/Log");
gLogOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gLogOffsets.mLogE = GetStaticMethodIDOrDie(env, clazz, "e",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
clazz = FindClassOrDie(env, "android/os/ParcelFileDescriptor");
gParcelFileDescriptorOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gParcelFileDescriptorOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>",
"(Ljava/io/FileDescriptor;)V");
clazz = FindClassOrDie(env, "android/os/StrictMode");
gStrictModeCallbackOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gStrictModeCallbackOffsets.mCallback = GetStaticMethodIDOrDie(env, clazz,
"onBinderStrictModePolicyChange", "(I)V");
return 0;
}
2.1.2 int_register_android_os_Binder
const char* const kBinderPathName = "android/os/Binder";
static int int_register_android_os_Binder(JNIEnv* env)
{
jclass clazz = FindClassOrDie(env, kBinderPathName); //通过classlinker加载jclass
gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");
return RegisterMethodsOrDie( env, kBinderPathName, gBinderMethods, NELEM(gBinderMethods));
}
2.1.3 RegisterMethodsOrDie
/frameworks/base/core/jni/core_jni_helpers.h
static inline int RegisterMethodsOrDie(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods) {
int res = AndroidRuntime::registerNativeMethods(env, className, gMethods, numMethods);
return res;
}
2.1.4 AndroidRuntime::registerNativeMethods
/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
const char* className, const JNINativeMethod* gMethods, int numMethods)
{
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
/libnativehelper/JNIHelp.cpp
extern "C" int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods)
{
JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
ALOGV("Registering %s's %d native methods...", className, numMethods);
scoped_local_ref<jclass> c(env, findClass(env, className));
if ((*env)->RegisterNatives(e, c.get(), gMethods, numMethods) < 0) {
char* tmp;
const char* msg;
if (asprintf(&tmp, "RegisterNatives failed for '%s'; aborting...", className) == -1) {
// Allocation failed, print default warning.
msg = "RegisterNatives failed; aborting...";
} else {
msg = tmp;
}
e->FatalError(msg);
}
return 0;
}
2.1.5 RegisterNatives
/art/runtime/jni_internal.cc
static jint RegisterNatives(JNIEnv* env, jclass java_class, const JNINativeMethod* methods,
jint method_count) {
return RegisterNativeMethods(env, java_class, methods, method_count, true);
}
static jint RegisterNativeMethods(JNIEnv* env, jclass java_class, const JNINativeMethod* methods,
jint method_count, bool return_errors) {
ScopedObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> c = hs.NewHandle(soa.Decode<mirror::Class>(java_class));
CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods, JNI_ERR);
for (jint i = 0; i < method_count; ++i) {
const char* name = methods[i].name;
const char* sig = methods[i].signature;
const void* fnPtr = methods[i].fnPtr;
bool is_fast = false;
// Note: the right order is to try to find the method locally
// first, either as a direct or a virtual method. Then move to
// the parent.
ArtMethod* m = nullptr;
// 根据java_class找到匹配的methods里面的名字,找到匹配的java类,可能native在父类
for (ObjPtr<mirror::Class> current_class = c.Get();
current_class != nullptr;
current_class = current_class->GetSuperClass()) {
// Search first only comparing methods which are native.
// 找到匹配的ArtMethod m
m = FindMethod<true>(current_class.Ptr(), name, sig);
if (m != nullptr) {
break;
}
.....
}
.....
const void* final_function_ptr = m->RegisterNative(fnPtr, is_fast);
UNUSED(final_function_ptr);
}
return JNI_OK;
}
2.1.6 ArtMethod::RegisterNative
const void* ArtMethod::RegisterNative(const void* native_method, bool is_fast) {
CHECK(IsNative()) << PrettyMethod();
CHECK(!IsFastNative()) << PrettyMethod();
CHECK(native_method != nullptr) << PrettyMethod();
if (is_fast) {
AddAccessFlags(kAccFastNative);
}
void* new_native_method = nullptr;
Runtime::Current()->GetRuntimeCallbacks()->RegisterNativeMethod(this,
native_method,
/*out*/&new_native_method);
SetEntryPointFromJni(new_native_method);
return new_native_method;
}
最后有RegisterNative完成注册工作,它要做的就是将native method在内存中地址通过SetEntryPointFromJni设置为对应ArtMethod的JNI入口。在JNI环境下,当java层的函数被调用后,首先找到它的ArtMethod对象,然后通过GetEntryPoint得到JNI入口代码的地址。
这就完成了java层跟native层函数的JNI映射。
2.1.7 Fast Native
这块简单介绍一下 fast jni模式
下文参考资料(《深入理解ART虚拟机》)
安卓 函数执行 分为两条线 第一种是 Java层,第二种JNI层 也就是 so层
当函数调用Java层进入到JNI层的是时候,虚拟机会将执行线程的状态从Runnable转换为Native。
如果JNI层又调用Java层相关函数的时候,执行线程的状态又得从Native层转换为Runnable。
线程的切换需要浪费时间,所以,对于某个特别强调执行速度的JNI函数可以设置成 fast jni模式
这种模式下执行这个native函数 将不会进行 状态切换,即执行线程的状态 始终为Runnable。
当然,这种模式的使用对GC有一些影响,所哟最好在那些本身函数执行时间段的,又不会阻塞的情况下使用。
另外,这种模式目前在art虚拟机内部 很多java native都有使用
为了和其他Native函数 进行区分,当使用fast jni模式的函数的签名信息 必须以 “!”开头