• Android加载SO整个流程


    java_vm_ext.cc -> JavaVMExt::LoadNativeLibrary

    bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
                                      const std::string& path,
                                      jobject class_loader,
                                      jstring library_path,
                                      std::string* error_msg) {
      error_msg->clear();
    
      // See if we've already loaded this library.  If we have, and the class loader
      // matches, return successfully without doing anything.
      // TODO: for better results we should canonicalize the pathname (or even compare
      // inodes). This implementation is fine if everybody is using System.loadLibrary.
      SharedLibrary* library;
      Thread* self = Thread::Current();
      {
        // TODO: move the locking (and more of this logic) into Libraries.
        MutexLock mu(self, *Locks::jni_libraries_lock_);
        library = libraries_->Get(path);
      }
      void* class_loader_allocator = nullptr;
      {
        ScopedObjectAccess soa(env);
        // As the incoming class loader is reachable/alive during the call of this function,
        // it's okay to decode it without worrying about unexpectedly marking it alive.
        ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader);
    
        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
        if (class_linker->IsBootClassLoader(soa, loader.Ptr())) {
          loader = nullptr;
          class_loader = nullptr;
        }
    
        class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Ptr());
        CHECK(class_loader_allocator != nullptr);
      }
      if (library != nullptr) {
        // Use the allocator pointers for class loader equality to avoid unnecessary weak root decode.
        if (library->GetClassLoaderAllocator() != class_loader_allocator) {
          // The library will be associated with class_loader. The JNI
          // spec says we can't load the same library into more than one
          // class loader.
          StringAppendF(error_msg, "Shared library \"%s\" already opened by "
              "ClassLoader %p; can't open in ClassLoader %p",
              path.c_str(), library->GetClassLoader(), class_loader);
          LOG(WARNING) << error_msg;
          return false;
        }
        VLOG(jni) << "[Shared library \"" << path << "\" already loaded in "
                  << " ClassLoader " << class_loader << "]";
        if (!library->CheckOnLoadResult()) {
          StringAppendF(error_msg, "JNI_OnLoad failed on a previous attempt "
              "to load \"%s\"", path.c_str());
          return false;
        }
        return true;
      }
    
      // Open the shared library.  Because we're using a full path, the system
      // doesn't have to search through LD_LIBRARY_PATH.  (It may do so to
      // resolve this library's dependencies though.)
    
      // Failures here are expected when java.library.path has several entries
      // and we have to hunt for the lib.
    
      // Below we dlopen but there is no paired dlclose, this would be necessary if we supported
      // class unloading. Libraries will only be unloaded when the reference count (incremented by
      // dlopen) becomes zero from dlclose.
    
      Locks::mutator_lock_->AssertNotHeld(self);
      const char* path_str = path.empty() ? nullptr : path.c_str();
      bool needs_native_bridge = false;
      void* handle = android::OpenNativeLibrary(env,
                                                runtime_->GetTargetSdkVersion(),
                                                path_str,
                                                class_loader,
                                                library_path,
                                                &needs_native_bridge,
                                                error_msg);
    
      VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_NOW) returned " << handle << "]";
    
      if (handle == nullptr) {
        VLOG(jni) << "dlopen(\"" << path << "\", RTLD_NOW) failed: " << *error_msg;
        return false;
      }
    
      if (env->ExceptionCheck() == JNI_TRUE) {
        LOG(ERROR) << "Unexpected exception:";
        env->ExceptionDescribe();
        env->ExceptionClear();
      }
      // Create a new entry.
      // TODO: move the locking (and more of this logic) into Libraries.
      bool created_library = false;
      {
        // Create SharedLibrary ahead of taking the libraries lock to maintain lock ordering.
        std::unique_ptr<SharedLibrary> new_library(
            new SharedLibrary(env,
                              self,
                              path,
                              handle,
                              needs_native_bridge,
                              class_loader,
                              class_loader_allocator));
    
        MutexLock mu(self, *Locks::jni_libraries_lock_);
        library = libraries_->Get(path);
        if (library == nullptr) {  // We won race to get libraries_lock.
          library = new_library.release();
          libraries_->Put(path, library);
          created_library = true;
        }
      }
      if (!created_library) {
        LOG(INFO) << "WOW: we lost a race to add shared library: "
            << "\"" << path << "\" ClassLoader=" << class_loader;
        return library->CheckOnLoadResult();
      }
      VLOG(jni) << "[Added shared library \"" << path << "\" for ClassLoader " << class_loader << "]";
    
      bool was_successful = false;
      void* sym = library->FindSymbol("JNI_OnLoad", nullptr);
      if (sym == nullptr) {
        VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";
        was_successful = true;
      } else {
        // Call JNI_OnLoad.  We have to override the current class
        // loader, which will always be "null" since the stuff at the
        // top of the stack is around Runtime.loadLibrary().  (See
        // the comments in the JNI FindClass function.)
        ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));
        self->SetClassLoaderOverride(class_loader);
    
        VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";
        typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
        JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
        int version = (*jni_on_load)(this, nullptr);
    
        if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {
          // Make sure that sigchain owns SIGSEGV.
          EnsureFrontOfChain(SIGSEGV);
        }
    
        self->SetClassLoaderOverride(old_class_loader.get());
    
        if (version == JNI_ERR) {
          StringAppendF(error_msg, "JNI_ERR returned from JNI_OnLoad in \"%s\"", path.c_str());
        } else if (JavaVMExt::IsBadJniVersion(version)) {
          StringAppendF(error_msg, "Bad JNI version returned from JNI_OnLoad in \"%s\": %d",
                        path.c_str(), version);
          // It's unwise to call dlclose() here, but we can mark it
          // as bad and ensure that future load attempts will fail.
          // We don't know how far JNI_OnLoad got, so there could
          // be some partially-initialized stuff accessible through
          // newly-registered native method calls.  We could try to
          // unregister them, but that doesn't seem worthwhile.
        } else {
          was_successful = true;
        }
        VLOG(jni) << "[Returned " << (was_successful ? "successfully" : "failure")
                  << " from JNI_OnLoad in \"" << path << "\"]";
      }
    
      library->SetResult(was_successful);
      return was_successful;
    }
    

    native_loader.cpp -> android::OpenNativeLibrary

    void* OpenNativeLibrary(JNIEnv* env,
                            int32_t target_sdk_version,
                            const char* path,
                            jobject class_loader,
                            jstring library_path,
                            bool* needs_native_bridge,
                            std::string* error_msg) {
    #if defined(__ANDROID__)
      UNUSED(target_sdk_version);
      if (class_loader == nullptr) {
        *needs_native_bridge = false;
        return dlopen(path, RTLD_NOW);
      }
    
      std::lock_guard<std::mutex> guard(g_namespaces_mutex);
      NativeLoaderNamespace ns;
    
      if (!g_namespaces->FindNamespaceByClassLoader(env, class_loader, &ns)) {
        // This is the case where the classloader was not created by ApplicationLoaders
        // In this case we create an isolated not-shared namespace for it.
        if (!g_namespaces->Create(env,
                                  target_sdk_version,
                                  class_loader,
                                  false /* is_shared */,
                                  false /* is_for_vendor */,
                                  library_path,
                                  nullptr,
                                  &ns,
                                  error_msg)) {
          return nullptr;
        }
      }
    
      if (ns.is_android_namespace()) {
        android_dlextinfo extinfo;
        extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
        extinfo.library_namespace = ns.get_android_ns();
    
        void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo);
        if (handle == nullptr) {
          *error_msg = dlerror();
        }
        *needs_native_bridge = false;
        return handle;
      } else {
        void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns.get_native_bridge_ns());
        if (handle == nullptr) {
          *error_msg = NativeBridgeGetError();
        }
        *needs_native_bridge = true;
        return handle;
      }
    #else
      UNUSED(env, target_sdk_version, class_loader, library_path);
      *needs_native_bridge = false;
      void* handle = dlopen(path, RTLD_NOW);
      if (handle == nullptr) {
        if (NativeBridgeIsSupported(path)) {
          *needs_native_bridge = true;
          handle = NativeBridgeLoadLibrary(path, RTLD_NOW);
          if (handle == nullptr) {
            *error_msg = NativeBridgeGetError();
          }
        } else {
          *needs_native_bridge = false;
          *error_msg = dlerror();
        }
      }
      return handle;
    #endif
    }
    

    http://aospxref.com/android-8.1.0_r81/xref/bionic/libdl/libdl.c

    http://aospxref.com/android-8.1.0_r81/xref/bionic/linker/linker.cpp?fi=do_dlopen#do_dlopen

    do_dlopen,dlopen真正的代码

    void* do_dlopen(const char* name, int flags,
                    const android_dlextinfo* extinfo,
                    const void* caller_addr) {
      std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
      ScopedTrace trace(trace_prefix.c_str());
      ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
      soinfo* const caller = find_containing_library(caller_addr);
      android_namespace_t* ns = get_caller_namespace(caller);
    
      LD_LOG(kLogDlopen,    
             "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",9
             name,
             flags,
             android_dlextinfo_to_string(extinfo).c_str(),
             caller == nullptr ? "(null)" : caller->get_realpath(),
             ns == nullptr ? "(null)" : ns->get_name(),
             ns);
    
      auto failure_guard = android::base::make_scope_guard(
          [&]() { LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer()); });
    
      if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
        DL_ERR("invalid flags to dlopen: %x", flags);
        return nullptr;
      }
    
      if (extinfo != nullptr) {
        if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
          DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
          return nullptr;
        }
    
        if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
            (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
          DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
              "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
          return nullptr;
        }
    
        if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
            (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
          DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
                 "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
          return nullptr;
        }
    
        if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
          if (extinfo->library_namespace == nullptr) {
            DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
            return nullptr;
          }
          ns = extinfo->library_namespace;
        }
      }
    
      std::string asan_name_holder;
    
      const char* translated_name = name;
      if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
        char original_path[PATH_MAX];
        if (realpath(name, original_path) != nullptr) {
          asan_name_holder = std::string(kAsanLibDirPrefix) + original_path;
          if (file_exists(asan_name_holder.c_str())) {
            soinfo* si = nullptr;
            if (find_loaded_library_by_realpath(ns, original_path, true, &si)) {
              PRINT("linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name,
                    asan_name_holder.c_str());
            } else {
              PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
              translated_name = asan_name_holder.c_str();
            }
          }
        }
      }
    
      ProtectedDataGuard guard;
      soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
      loading_trace.End();
    
      if (si != nullptr) {
        void* handle = si->to_handle();
        LD_LOG(kLogDlopen,
               "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
               si->get_realpath(), si->get_soname(), handle);
        si->call_constructors(); // 最后dloepn的地方
        failure_guard.Disable();
        LD_LOG(kLogDlopen,
               "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
               si->get_realpath(), si->get_soname(), handle);
        return handle;
      }
    
      return nullptr;
    }
    

    http://aospxref.com/android-8.1.0_r81/xref/bionic/linker/linker_soinfo.cpp

    call_constructors

    void soinfo::call_constructors() {
      if (constructors_called) {
        return;
      }
    
      // We set constructors_called before actually calling the constructors, otherwise it doesn't
      // protect against recursive constructor calls. One simple example of constructor recursion
      // is the libc debug malloc, which is implemented in libc_malloc_debug_leak.so:
      // 1. The program depends on libc, so libc's constructor is called here.
      // 2. The libc constructor calls dlopen() to load libc_malloc_debug_leak.so.
      // 3. dlopen() calls the constructors on the newly created
      //    soinfo for libc_malloc_debug_leak.so.
      // 4. The debug .so depends on libc, so CallConstructors is
      //    called again with the libc soinfo. If it doesn't trigger the early-
      //    out above, the libc constructor will be called again (recursively!).
      constructors_called = true;
    
      if (!is_main_executable() && preinit_array_ != nullptr) {
        // The GNU dynamic linker silently ignores these, but we warn the developer.
        PRINT("\"%s\": ignoring DT_PREINIT_ARRAY in shared library!", get_realpath());
      }
    
      get_children().for_each([] (soinfo* si) {
        si->call_constructors();
      });
    
      if (!is_linker()) {
        bionic_trace_begin((std::string("calling constructors: ") + get_realpath()).c_str());
      }
    
      // DT_INIT should be called before DT_INIT_ARRAY if both are present.
      call_function("DT_INIT", init_func_, get_realpath()); // .init_proc
      call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false, get_realpath()); // init_array
    
      if (!is_linker()) {
        bionic_trace_end();
      }
    }
    

    http://aospxref.com/android-8.1.0_r81/xref/bionic/linker/linker_soinfo.cpp

    call_function

    static void call_function(const char* function_name __unused,
                              linker_dtor_function_t function,
                              const char* realpath __unused) {
      if (function == nullptr || reinterpret_cast<uintptr_t>(function) == static_cast<uintptr_t>(-1)) {
        return;
      }
    
      TRACE("[ Calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
      function();
      TRACE("[ Done calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
    }
    

    http://aospxref.com/android-8.1.0_r81/xref/bionic/linker/linker_soinfo.cpp

    call_array

    template <typename F>
    static void call_array(const char* array_name __unused,
                           F* functions,
                           size_t count,
                           bool reverse,
                           const char* realpath) {
      if (functions == nullptr) {
        return;
      }
    
      TRACE("[ Calling %s (size %zd) @ %p for '%s' ]", array_name, count, functions, realpath);
    
      int begin = reverse ? (count - 1) : 0;
      int end = reverse ? -1 : count;
      int step = reverse ? -1 : 1;
    
      for (int i = begin; i != end; i += step) {
        TRACE("[ %s[%d] == %p ]", array_name, i, functions[i]);
        call_function("function", functions[i], realpath);
      }
    
      TRACE("[ Done calling %s for '%s' ]", array_name, realpath);
    }
    

    elf理解的paper:https://paper.seebug.org/papers/Archive/refs/elf/Understanding_ELF.pdf

  • 相关阅读:
    爬虫必备的web知识
    pythoth 中常用的魔法方法
    Python数据分析matplotlib可视化之绘图
    前端(HTML)+后端(Django)+数据库(MySQL):用户注册及登录演示
    用python文件操作实现复制图片、视频
    彩票购买系统(26选5)-初级版本
    封装系统字符串内置函数,实现类似功能
    部署live555到云
    腾讯云:基于 Ubuntu 搭建 VNC 远程桌面服务
    2.Linux文件IO编程
  • 原文地址:https://www.cnblogs.com/Tu9oh0st/p/16177195.html
Copyright © 2020-2023  润新知