解读Nativebridge对于houdin的支持

二、应用程序在加载so文件时的变化

原本功能是在javaVMExt::LoadNativeLibrary函数中实现的
(art\runtime\jin_internal.cc文件中):
该函数正常情况下使用dlopen打开so文件,但当x86系统试图打开arm版本的so ,返回错误时,这时就会使用NativeBridge自带的加载过程。

Created with Raphaël 2.2.0 开始 dlopen ? break NativeBridgeIsSupported ? NativeBridgeLoadLibrary FindSymbolWithNativeBridge 结束 yes no yes no
bool JavaVMExt::LoadNativeLibrary(const std::string& path,
                                  Handle class_loader,
                                  std::string* detail) {
  ......
  const char* path_str = path.empty() ? nullptr : path.c_str();
  void* handle = dlopen(path_str, RTLD_LAZY);
  bool needs_native_bridge = false;
  if (handle == nullptr) {
    if (android::NativeBridgeIsSupported(path_str)) {
      handle = android::NativeBridgeLoadLibrary(path_str, RTLD_LAZY);
      needs_native_bridge = true;
    }
  }
  ......
  bool created_library = false;
  {
    MutexLock mu(self, libraries_lock);
    library = libraries->Get(path);
    if (library == nullptr) {  // We won race to get libraries_lock
      library = new SharedLibrary(path, handle, class_loader.Get());
      libraries->Put(path, library);
      created_library = true;
    }
  }
  ......
  bool was_successful = false;
  void* sym = nullptr;
  if (UNLIKELY(needs_native_bridge)) {
    library->SetNeedsNativeBridge();
    sym = library->FindSymbolWithNativeBridge("JNI_OnLoad", nullptr);
  } else {
    sym = dlsym(handle, "JNI_OnLoad");
  }
  ......
}

android::NativeBridgeRuntimeCallbacks

android::NativeBridgeCallbacks全局变量

callbacks->isSupported
callbacks->loadLibrary(libpath, flag)
callbacks->getTrampoline

一、对于部分NativeBridge源代码的更改

添加链接描述

“ro.dalvik.vm.native.bridge” 指定动态链接库

  1. 有自己的数据目录,一般应用程序是有的,在/data/data/目录下。

如果决定要启用NativeBridge,则还需要调用android::PreInitializeNativeBridge对其做预初始化:

2)android.os.Build.SUPPORTED_ABIS,
更正过的

struct NativeBridgeCallbacks {
  // Version number of the interface.
  uint32_t version;
  bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
                     const char* instruction_set);
  void* (*loadLibrary)(const char* libpath, int flag);
  void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
  bool (*isSupported)(const char* libpath);
  const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
  bool (*isCompatibleWith)(uint32_t bridge_version);
  NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
};

多出两个函数一个叫做isCompatibleWith,一个叫做getSignalHandler。
3)persist.sys.nativebridge系统属性设置为1
4)ro.product.cpu.abilist系统属性
这个属性会控制特定版本的系统可以安装的app类型,为了是x86系统可以安装只包含arm指令集的apk,我没就需要更改这个属性。
ro.product.cpu.abilist=x86,armeabi-v7a,armeabi
ro.product.cpu.abilisit32=x86,armeabi-v7a,armeabi
5)ro.dalvik.vm.isa.arm系统属性(Android-X86系统中的build.prop)
ro.dalvik.vm.isa.arm=x86
ro.dalvik.vm.isa.=

其他更改部分

看了半天发现好像剩下的只剩使用指定程序打开某一类程序

而原始NativeBridgeCallbacks结构体的定义如下(代码位于system\core\include\nativebridge\native_bridge.h文件中):

struct NativeBridgeCallbacks {
  uint32_t version;
  bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
                     const char* instruction_set);
  void* (*loadLibrary)(const char* libpath, int flag);
  void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);
  bool (*isSupported)(const char* libpath);
  const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);
};

但这里的实现却是在libnb.so里面,libnb.so里面的实现又是通过回调转到libhoudini.so。所以,这个所谓的nativebridge本质上就是实现以上几个接口后实现的功能。

system的native_bridge.cpp通过外部实现的这几个接口来传递编码转换的初始化函数。

总结:
libnb里面有7个回调接口,原本native_bridge.cpp里面只利用了5个,为了增加houdin我们利用增加的在native_bridge里面做了检查和信号处理。
getsignalHandler利用在这里调用这个函数的地方在这里(代码位于art\runtime\native_bridge_art_interface.cc文件中):

void InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
  if (android::InitializeNativeBridge(env, instruction_set)) {
    if (android::NativeBridgeGetVersion() >= 2U) {
#ifdef _NSIG
      for (int signal = 0; signal < _NSIG; ++signal) {
        android::NativeBridgeSignalHandlerFn fn = android::NativeBridgeGetSignalHandler(signal);
        if (fn != nullptr) {
          SetSpecialSignalHandlerFn(signal, fn);
        }
      }
#endif
    }
  }
}

最后函数就会利用getTrampoline跳到转化指令集里面执行。

不过有一点还不清楚,那就是绑定指定程序执行的操作有啥用。先不管了。

android 5.0 具体变化文件:
art/runtime/sigchainlib/sigchain_dummy.cc 、 sigchain.cc 、 sigchain.h
art/runtime/jni_internal.cc 、 native_bridge_art_interface.cc 、native_bridge_art_interaface.h

libnb.so位置      device/generic/common/nativebridge/
native_bridge.cc 位于、system/core/libnativebridge/native_bridge.cc

结果

经过对代码的不断跟踪和错误修正,最终结果如下:
解读Nativebridge对于houdin的支持_第1张图片
我们这仅仅是编译了简单的jni函数,实现了native层的hello world但根据日志中显示加载文件为arm/libplthook-lib.so
可以看出我们成功的执行了arm指令下的so文件中的字符串转换。并且我们编译的程序so库中只包含arm指令,没有x86的so。感兴趣的同学可以自己试试。

并且,那个标定指令使用指定程序打开某一类程序
这一部分的东西并没什么卵用,因为我到这里根本没有设置相应的文件。

大功告成。

学习源码这么长时间,第一次添加自己的逻辑,感觉不错。哈哈哈哈

你可能感兴趣的:(android内核及源码)