android的native_bridge

开门见山。native_bridge就是让不同指令集能够运行。这里主要是在X86上跑ARM

后续的均以android6.0为例

在加载so文件的时候。最后调用到了

art/runtime/java_vm_ext.cc当中的

JavaVMExt::LoadNativeLibrary

void* handle = dlopen(path_str, RTLD_NOW);
  bool needs_native_bridge = false;
  if (handle == nullptr) {
    if (android::NativeBridgeIsSupported(path_str)) {
      handle = android::NativeBridgeLoadLibrary(path_str, RTLD_NOW);
      needs_native_bridge = true;
    }
  }

dlopen此时打开so动态库肯定会出现错误。因为so是ARM的

然后检查NativeBridgeIsSupported.如果支持的话将

调用asndroid::nativeBridgeLoadLibrary()加载这个库

needs_native_bridge=true

主要代码在

system/core/libnativebridge/native_bridge.cc

检查NativeBridgeInitialized成功以后对于callback->isSupported()对路径执行检查。支持的话返回true

bool NativeBridgeIsSupported(const char* libpath) {
  if (NativeBridgeInitialized()) {
    return callbacks->isSupported(libpath);
  }
  return false;
}

NativeBridgeInitialized应该是art启动虚拟机的时候通过调用

PreInitializeNativeBridge

InitializeNativeBridge

初始化成功以后返回True的。

在zygote启动app进程会调用Runtime::Start

if (is_zygote_) {
    if (!InitZygote()) {
      return false;
    }
  } else {
    if (is_native_bridge_loaded_) {
      PreInitializeNativeBridge(".");
    }
    NativeBridgeAction action = force_native_bridge_
        ? NativeBridgeAction::kInitialize
        : NativeBridgeAction::kUnload;
    InitNonZygoteOrPostFork(self->GetJniEnv(),
                            /* is_system_server */ false,
                            action,
                            GetInstructionSetString(kRuntimeISA));
  }

就是在初始化的时候会指定一个nativebridge的so名字让你加载.这个就是nativebirdge

在/frameworkd/base/core/jni/AndroidRuntime.cpp里面

char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];

在startvm函数中

// Native bridge library. "0" means that native bridge is disabled.
    property_get("ro.dalvik.vm.native.bridge", propBuf, "");
    if (propBuf[0] == '\0') {
        ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
    } else if (strcmp(propBuf, "0") != 0) {
        snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
                 "-XX:NativeBridge=%s", propBuf);
        addOption(nativeBridgeLibrary);
    }
这个设置是在/default.prop里面可以看到的


说明Android-x86使用的nativebridge就是libnb.so


另外还有一处在

framworks\base\core\jni\com_android_internal_os_Zygote.cpp 中

 bool use_native_bridge = !is_system_server && (instructionSet != NULL)
        && android::NativeBridgeAvailable();
    if (use_native_bridge) {
      ScopedUtfChars isa_string(env, instructionSet);
      use_native_bridge = android::NeedsNativeBridge(isa_string.c_str());
    }
    if (use_native_bridge && dataDir == NULL) {
      // dataDir should never be null if we need to use a native bridge.
      // In general, dataDir will never be null for normal applications. It can only happen in
      // special cases (for isolated processes which are not associated with any app). These are
      // launched by the framework and should not be emulated anyway.
      use_native_bridge = false;
      ALOGW("Native bridge will not be used because dataDir == NULL.");
    }
    if (use_native_bridge) {
      ScopedUtfChars isa_string(env, instructionSet);
      ScopedUtfChars data_dir(env, dataDir);
      android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());

    }

1 不是属于SystemServer进程

2指令集不为NULL

system\core\libnativebridge\native_bridge.cc

bool NeedsNativeBridge(const char* instruction_set) {
  if (instruction_set == nullptr) {
    ALOGE("Null instruction set in NeedsNativeBridge.");
    return false;
  }
  return strncmp(instruction_set, kRuntimeISA, strlen(kRuntimeISA) + 1) != 0;
}

3有dataDir。一般的程序是有的。

4 native_bridge已经准备好了

如果前面的加载nativeso好了的话 一般是么有问题的。





    if (use_native_bridge) {
      ScopedUtfChars isa_string(env, instructionSet);
      ScopedUtfChars data_dir(env, dataDir);
      android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
    }

if (use_native_bridge) {
      ScopedUtfChars isa_string(env, instructionSet);
      ScopedUtfChars data_dir(env, dataDir);
      android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
    }

if (use_native_bridge) {
      ScopedUtfChars isa_string(env, instructionSet);
      ScopedUtfChars data_dir(env, dataDir);
      android::PreInitializeNativeBridge(data_dir.c_str(), isa_string.c_str());
    }

最终LoadNativeBridge进入了 /system/core/libnativebridge/native_bridge.cc

bool LoadNativeBridge(const char* nb_library_filename,const NativeBridgeRuntimeCallbacks* runtime_cbs) 

{

函数参数

nb_library_filename 是路径名

runtime_cbs 是callback /art/runtime/native_bridge_art_interface.cc 里面的

static android::NativeBridgeRuntimeCallbacks native_bridge_art_callbacks_ {

GetMethodShorty, GetNativeMethodCount, GetNativeMethods};

主要是一组回调函数。 

The interface is expected to expose the following methods:
getMethodShorty(): in the case of native method calling JNI native function CallXXXXMethodY(),
native bridge calls back to VM for the shorty of the method so that it can prepare based on
host calling convention.
getNativeMethodCount() and getNativeMethods(): in case of JNI function UnregisterNatives(),
native bridge can call back to get all native methods of specified class so that all

corresponding trampolines can be destroyed.


关键部分 

1 打开这个nativebridge

2调用dlsym取得函数 static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf";

这个函数叫做 NativeBridgeItf

3 这个函数NativeBridgeItf类型是 NativeBridgeCallbacks ()

定义在

/system/core/include/nativebridge/native_bridge.h

// Native bridge interfaces to runtime.
struct NativeBridgeCallbacks {
  // Version number of the interface.
  uint32_t version;

  // Initialize native bridge. Native bridge's internal implementation must ensure MT safety and
  // that the native bridge is initialized only once. Thus it is OK to call this interface for an
  // already initialized native bridge.
  //
  // Parameters:
  //   runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
  // Returns:
  //   true iff initialization was successful.
  bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
                     const char* instruction_set);

  // Load a shared library that is supported by the native bridge.
  //
  // Parameters:
  //   libpath [IN] path to the shared library
  //   flag [IN] the stardard RTLD_XXX defined in bionic dlfcn.h
  // Returns:
  //   The opaque handle of the shared library if sucessful, otherwise NULL
  void* (*loadLibrary)(const char* libpath, int flag);

  // Get a native bridge trampoline for specified native method. The trampoline has same
  // sigature as the native method.
  //
  // Parameters:
  //   handle [IN] the handle returned from loadLibrary
  //   shorty [IN] short descriptor of native method
  //   len [IN] length of shorty
  // Returns:
  //   address of trampoline if successful, otherwise NULL
  void* (*getTrampoline)(void* handle, const char* name, const char* shorty, uint32_t len);

  // Check whether native library is valid and is for an ABI that is supported by native bridge.
  //
  // Parameters:
  //   libpath [IN] path to the shared library
  // Returns:
  //   TRUE if library is supported by native bridge, FALSE otherwise
  bool (*isSupported)(const char* libpath);

  // Provide environment values required by the app running with native bridge according to the
  // instruction set.
  //
  // Parameters:
  //    instruction_set [IN] the instruction set of the app
  // Returns:
  //    NULL if not supported by native bridge.
  //    Otherwise, return all environment values to be set after fork.
  const struct NativeBridgeRuntimeValues* (*getAppEnv)(const char* instruction_set);

  // Added callbacks in version 2.

  // Check whether the bridge is compatible with the given version. A bridge may decide not to be
  // forwards- or backwards-compatible, and libnativebridge will then stop using it.
  //
  // Parameters:
  //     bridge_version [IN] the version of libnativebridge.
  // Returns:
  //     true iff the native bridge supports the given version of libnativebridge.
  bool (*isCompatibleWith)(uint32_t bridge_version);

  // A callback to retrieve a native bridge's signal handler for the specified signal. The runtime
  // will ensure that the signal handler is being called after the runtime's own handler, but before
  // all chained handlers. The native bridge should not try to install the handler by itself, as
  // that will potentially lead to cycles.
  //
  // Parameters:
  //     signal [IN] the signal for which the handler is asked for. Currently, only SIGSEGV is
  //                 supported by the runtime.
  // Returns:
  //     NULL if the native bridge doesn't use a handler or doesn't want it to be managed by the
  //     runtime.
  //     Otherwise, a pointer to the signal handler.
  NativeBridgeSignalHandlerFn (*getSignalHandler)(int signal);
};

这个函数是由nativebridge so 提供的

编写自己的nativebridge so关键就是要实现这个函数


4另外把前面传入的  NativeBridgeRuntimeCallbacks runtime_callback也保存了起来到了runtime_callbacks里面

// Runtime interfaces to native bridge.
struct NativeBridgeRuntimeCallbacks {
  // Get shorty of a Java method. The shorty is supposed to be persistent in memory.
  //
  // Parameters:
  //   env [IN] pointer to JNIenv.
  //   mid [IN] Java methodID.
  // Returns:
  //   short descriptor for method.
  const char* (*getMethodShorty)(JNIEnv* env, jmethodID mid);

  // Get number of native methods for specified class.
  //
  // Parameters:
  //   env [IN] pointer to JNIenv.
  //   clazz [IN] Java class object.
  // Returns:
  //   number of native methods.
  uint32_t (*getNativeMethodCount)(JNIEnv* env, jclass clazz);

  // Get at most 'method_count' native methods for specified class 'clazz'. Results are outputed
  // via 'methods' [OUT]. The signature pointer in JNINativeMethod is reused as the method shorty.
  //
  // Parameters:
  //   env [IN] pointer to JNIenv.
  //   clazz [IN] Java class object.
  //   methods [OUT] array of method with the name, shorty, and fnPtr.
  //   method_count [IN] max number of elements in methods.
  // Returns:
  //   number of method it actually wrote to methods.
  uint32_t (*getNativeMethods)(JNIEnv* env, jclass clazz, JNINativeMethod* methods,
                               uint32_t method_count);
};
这个是安卓源码提供的。




void* handle = dlopen(nb_library_filename, RTLD_LAZY);
      if (handle != nullptr) {
        callbacks = reinterpret_cast<NativeBridgeCallbacks*>(dlsym(handle,
                                                                   kNativeBridgeInterfaceSymbol));
        if (callbacks != nullptr) {
          if (VersionCheck(callbacks)) {
            // Store the handle for later.
            native_bridge_handle = handle;
          } else {
            callbacks = nullptr;
            dlclose(handle);
            ALOGW("Unsupported native bridge interface.");
          }
        } else {
          dlclose(handle);
        }
      }

      // Two failure conditions: could not find library (dlopen failed), or could not find native
      // bridge interface (dlsym failed). Both are an error and close the native bridge.
      if (callbacks == nullptr) {
        CloseNativeBridge(true);
      } else {
        runtime_callbacks = runtime_cbs;
        state = NativeBridgeState::kOpened;
      }

}

下一集在看如何编写吧。

https://github.com/openthos/device-generic-common

这个就是android-x86的libns.so 的例子




猜你喜欢

转载自blog.csdn.net/groundhappy/article/details/80493358