Android 9.0 supports third-party applications to reference system libraries (so)

platform

RK3288 + Android 9

problem

  • Official original text:
    "Starting from Android 7.0, the system will prevent apps from dynamically linking non-public NDK libraries, which may cause your app to crash. This behavior change aims to provide a unified app experience for cross-platform updates and different devices. Even Your code may not link private libraries, but third-party static libraries in your application may do so. Therefore, all developers should check accordingly to ensure that their applications will not crash on devices running Android 7.0 . If your app uses native code, you can only use the public NDK API."
  • What's the problem?
    Many apps that use JNI will not be able to be used normally like the low-version SDK. When using 7.1, the system will have related prompts. When using 9.0, it will directly crash and report an error.
        java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libserial_port.so" needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace"
        at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
        at java.lang.System.loadLibrary(System.java:1669)
    
    常见:UnsatisfiedLinkError

solution

Plan 1 modify the APP side

See below to record that 7.0 failed to load the so file: java.lang.UnsatisfiedLinkError: dlopen failed: library "libsqlite.so" not found

Option 2 Modify the system SDK

|-- Part of the error output code: bionic/linker/linker.cpp

static bool load_library(android_namespace_t* ns,
                         LoadTask* task,
                         LoadTaskList* load_tasks,
                         int rtld_flags,
                         const std::string& realpath,
                         bool search_linked_namespaces) {
    
    
  off64_t file_offset = task->get_file_offset();
  const char* name = task->get_name();
  const android_dlextinfo* extinfo = task->get_extinfo();

  if ((file_offset % PAGE_SIZE) != 0) {
    
    
    DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
    return false;
  }
  if (file_offset < 0) {
    
    
    DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
    return false;
  }

  struct stat file_stat;
  if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
    
    
    DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
    return false;
  }
  if (file_offset >= file_stat.st_size) {
    
    
    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
        name, file_offset, file_stat.st_size);
    return false;
  }

  // Check for symlink and other situations where
  // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
  if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
    
    
    soinfo* si = nullptr;
    if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
    
    
      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
            "will return existing soinfo", name, si->get_realpath());
      task->set_soinfo(si);
      return true;
    }
  }

  if ((rtld_flags & RTLD_NOLOAD) != 0) {
    
    
    DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
    return false;
  }

  struct statfs fs_stat;
  if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) {
    
    
    DL_ERR("unable to fstatfs file for the library \"%s\": %s", name, strerror(errno));
    return false;
  }

  // do not check accessibility using realpath if fd is located on tmpfs
  // this enables use of memfd_create() for apps
  if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) {
    
    
    // TODO(dimitry): workaround for http://b/26394120 - the grey-list

    // TODO(dimitry) before O release: add a namespace attribute to have this enabled
    // only for classloader-namespaces
    const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
    if (is_greylisted(ns, name, needed_by)) {
    
    
      // print warning only if needed by non-system library
      if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
    
    
        const soinfo* needed_or_dlopened_by = task->get_needed_by();
        const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
                                                      needed_or_dlopened_by->get_realpath();
        DL_WARN_documented_change(__ANDROID_API_N__,
                                  "private-api-enforced-for-api-level-24",
                                  "library \"%s\" (\"%s\") needed or dlopened by \"%s\" "
                                  "is not accessible by namespace \"%s\"",
                                  name, realpath.c_str(), sopath, ns->get_name());
        add_dlwarning(sopath, "unauthorized access to",  name);
      }
    } else {
    
    
      // do not load libraries if they are not accessible for the specified namespace.
      const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
                                          "(unknown)" :
                                          task->get_needed_by()->get_realpath();

      DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
             name, needed_or_dlopened_by, ns->get_name());

      // do not print this if a library is in the list of shared libraries for linked namespaces
      if (!maybe_accessible_via_namespace_links(ns, name)) {
    
    
        PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
              " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
              " permitted_paths=\"%s\"]",
              name, realpath.c_str(),
              needed_or_dlopened_by,
              ns->get_name(),
              android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
              android::base::Join(ns->get_default_library_paths(), ':').c_str(),
              android::base::Join(ns->get_permitted_paths(), ':').c_str());
      }
      return false;
    }
  }

  soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
  if (si == nullptr) {
    
    
    return false;
  }

  task->set_soinfo(si);

  // Read the ELF header and some of the segments.
  if (!task->read(realpath.c_str(), file_stat.st_size)) {
    
    
    soinfo_free(si);
    task->set_soinfo(nullptr);
    return false;
  }

  // find and set DT_RUNPATH and dt_soname
  // Note that these field values are temporary and are
  // going to be overwritten on soinfo::prelink_image
  // with values from PT_LOAD segments.
  const ElfReader& elf_reader = task->get_elf_reader();
  for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
    
    
    if (d->d_tag == DT_RUNPATH) {
    
    
      si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
    }
    if (d->d_tag == DT_SONAME) {
    
    
      si->set_soname(elf_reader.get_string(d->d_un.d_val));
    }
  }

  for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
    
    
    load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
  });

  return true;
}

Error output:

DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
             name, needed_or_dlopened_by, ns->get_name());

The idea of ​​the modification is not to follow the code of this part of the branch that reports the error, the entry point is_greylisted

diff --git a/bionic/linker/linker.cpp b/bionic/linker/linker.cpp
old mode 100644
new mode 100755
index c78b9ab..0aa83bc
--- a/bionic/linker/linker.cpp
+++ b/bionic/linker/linker.cpp
@@ -200,12 +200,14 @@ static bool is_greylisted(android_namespace_t* ns, const char* name, const soinf
     "libui.so",
     "libutils.so",
     "libvorbisidec.so",
+       "libserial_port.so",
     nullptr
   };
 
   // If you're targeting N, you don't get the greylist.
   if (g_greylist_disabled || get_application_target_sdk_version() >= __ANDROID_API_N__) {
    
    
-    return false;
+       //make system lib can be loaded.
+    //return false;
   }
 
   // if the library needed by a system library - implicitly assume it

Modification points:

  • Add the called SO to the greylist list, here is a libserial_port.so
  • Comment to judge the return of SDK and greylist enable judgment, of course, you can also force to return true , depending on the needs

There is a Warning prompt after modification, ignore:

Warning: library "/system/lib/libserial_port.so" ("/system/lib/libserial_port.so") needed or dlopened by "/system/lib/libnativeloader.so" is not accessible by namespace "classloader-namespace" and will not work when the app moves to API level 24 or later (https://android.googlesource.com/platform/bionic/+/master/private-api-enforced-for-api-level-24) (allowing for now because this app's target API level is still 26)

Uploaded resources: linker
use:

adb root
adb remount
adb push linker /system/bin/
adb reboot

The second question that follows:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++.so" not found
        at java.lang.Runtime.loadLibrary0(Runtime.java:1016)
        at java.lang.System.loadLibrary(System.java:1669)

| –Bionic / linker / linker.cpp

@@ -2342,6 +2344,10 @@ android_namespace_t* create_namespace(const void* caller_addr,
 
   parse_path(ld_library_path, ":", &ld_library_paths);
   parse_path(default_library_path, ":", &default_library_paths);
+  if(strcmp(name, "classloader-namespace") == 0){
    
    
+    parse_path("/system/lib", ":", &default_library_paths);
+  }
   parse_path(permitted_when_isolated_path, ":", &permitted_paths);
 
   android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();

solve!!

Full patch: linker_patch.tar.gz

Related

Guess you like

Origin blog.csdn.net/ansondroider/article/details/106907174