当前位置: 首页 > news >正文

android so载入过程

源自android 9

看源代码的网页

/bionic/libdl/libdl_static.c 好像没用。都是空的

/bionic/libdl/libdl.cpp 主角

22// These functions are exported by the loader
23// TODO(dimitry): replace these with reference to libc.so101// Proxy calls to bionic loader
102__attribute__((__weak__))
103void* dlopen(const char* filename, int flag) {
104  const void* caller_addr = __builtin_return_address(0);
105  return __loader_dlopen(filename, flag, caller_addr);
106}

/bionic/linker/dlfcn.cpp

152void* __loader_dlopen(const char* filename, int flags, const void* caller_addr) {
153  return dlopen_ext(filename, flags, nullptr, caller_addr);
154}131static void* dlopen_ext(const char* filename,
132                        int flags,
133                        const android_dlextinfo* extinfo,
134                        const void* caller_addr) {
135  ScopedPthreadMutexLocker locker(&g_dl_mutex);
136  g_linker_logger.ResetState();
137  void* result = do_dlopen(filename, flags, extinfo, caller_addr);
138  if (result == nullptr) {
139    __bionic_format_dlerror("dlopen failed", linker_get_error_buffer());
140    return nullptr;
141  }
142  return result;
143}

do_dlopen

/bionic/linker/linker.cpp

49void* do_dlopen(const char* name, int flags,
2050                const android_dlextinfo* extinfo,
2051                const void* caller_addr) {
2052  std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
2053  ScopedTrace trace(trace_prefix.c_str());
2054  ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
2055  soinfo* const caller = find_containing_library(caller_addr);
2056  android_namespace_t* ns = get_caller_namespace(caller);
2057
2058  LD_LOG(kLogDlopen,
2059         "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p) ...",
2060         name,
2061         flags,
2062         android_dlextinfo_to_string(extinfo).c_str(),
2063         caller == nullptr ? "(null)" : caller->get_realpath(),
2064         ns == nullptr ? "(null)" : ns->get_name(),
2065         ns);
2066
2067  auto failure_guard = android::base::make_scope_guard(
2068      [&]() { LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer()); });
2069
2070  if ((flags & ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
2071    DL_ERR("invalid flags to dlopen: %x", flags);
2072    return nullptr;
2073  }
2074
2075  if (extinfo != nullptr) {
2076    if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
2077      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo->flags);
2078      return nullptr;
2079    }
2080
2081    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &&
2082        (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
2083      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
2084          "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo->flags);
2085      return nullptr;
2086    }
2087
2088    if ((extinfo->flags & ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS) != 0 &&
2089        (extinfo->flags & (ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT)) != 0) {
2090      DL_ERR("invalid extended flag combination: ANDROID_DLEXT_LOAD_AT_FIXED_ADDRESS is not "
2091             "compatible with ANDROID_DLEXT_RESERVED_ADDRESS/ANDROID_DLEXT_RESERVED_ADDRESS_HINT");
2092      return nullptr;
2093    }
2094
2095    if ((extinfo->flags & ANDROID_DLEXT_USE_NAMESPACE) != 0) {
2096      if (extinfo->library_namespace == nullptr) {
2097        DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo->library_namespace is null");
2098        return nullptr;
2099      }
2100      ns = extinfo->library_namespace;
2101    }
2102  }
2103
2104  std::string asan_name_holder;
2105
2106  const char* translated_name = name;
2107  if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
2108    char original_path[PATH_MAX];
2109    if (realpath(name, original_path) != nullptr) {
2110      asan_name_holder = std::string(kAsanLibDirPrefix) + original_path;
2111      if (file_exists(asan_name_holder.c_str())) {
2112        soinfo* si = nullptr;
2113        if (find_loaded_library_by_realpath(ns, original_path, true, &si)) {
2114          PRINT("linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name,
2115                asan_name_holder.c_str());
2116        } else {
2117          PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
2118          translated_name = asan_name_holder.c_str();
2119        }
2120      }
2121    }
2122  }
2123
2124  ProtectedDataGuard guard;
2125  soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
2126  loading_trace.End();
2127
2128  if (si != nullptr) {
2129    void* handle = si->to_handle();
2130    LD_LOG(kLogDlopen,
2131           "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
2132           si->get_realpath(), si->get_soname(), handle);
2133    si->call_constructors();
2134    failure_guard.Disable();
2135    LD_LOG(kLogDlopen,
2136           "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
2137           si->get_realpath(), si->get_soname(), handle);
2138    return handle;
2139  }
2140
2141  return nullptr;
2142}

排除一大堆分支。可以很清楚的发现 核心代码就是调用find_library 来构造一个soinfo 结构体,然后调用soinfo 的to_handle和call_constructors最后把to_handle函数的返回值返回。

soinfo

/bionic/linker/linker_soinfo.h

soinfo 代码太长了就不贴了。看样子内容和elf 的差不多。所以find_library 的任务应该就是把elf 文件的动态链接库文件加工一下放到soinfo结构体中。然后android 通过管理soinfo 来管理所有动态链接库

find_library

/bionic/linker/linker.cpp

1759static soinfo* find_library(android_namespace_t* ns,
1760                            const char* name, int rtld_flags,
1761                            const android_dlextinfo* extinfo,
1762                            soinfo* needed_by) {
1763  soinfo* si = nullptr;
1764
1765  if (name == nullptr) {
1766    si = solist_get_somain();
1767  } else if (!find_libraries(ns,
1768                             needed_by,
1769                             &name,
1770                             1,
1771                             &si,
1772                             nullptr,
1773                             0,
1774                             rtld_flags,
1775                             extinfo,
1776                             false /* add_as_children */,
1777                             true /* search_linked_namespaces */)) {
1778    if (si != nullptr) {
1779      soinfo_unload(si);
1780    }
1781    return nullptr;
1782  }
1783
1784  si->increment_ref_count();
1785
1786  return si;
1787}

这个name 就do_dlopen前面一大串代码找到的so路径。 所以一般情况下solist_get_somain 是不会运行的。不过我好奇看了一下这个默认行为是做什么的。

/bionic/linker/linker_main.cpp

59// These should be preserved static to avoid emitting
60// RELATIVE relocations for the part of the code running
61// before linker links itself.
62
63// TODO (dimtiry): remove somain, rename solist to solist_head
64static soinfo* solist;
65static soinfo* sonext;
66static soinfo* somain; // main process, always the one after libdl_info
67static soinfo* vdso; // vdso if present104soinfo* solist_get_somain() {
105  return somain;
106}

通过注释好像标识main process ,不过上面有一个remove somain 是不是表示后面要移除的。不过这个不是我们研究的重点

find_libraries 核心装在步骤

/bionic/linker/linker_main.cpp

1504// add_as_children - add first-level loaded libraries (i.e. library_names[], but
1505// not their transitive dependencies) as children of the start_with library.
1506// This is false when find_libraries is called for dlopen(), when newly loaded
1507// libraries must form a disjoint tree.
1508bool find_libraries(android_namespace_t* ns,
1509                    soinfo* start_with,
1510                    const char* const library_names[],
1511                    size_t library_names_count,
1512                    soinfo* soinfos[],
1513                    std::vector<soinfo*>* ld_preloads,
1514                    size_t ld_preloads_count,
1515                    int rtld_flags,
1516                    const android_dlextinfo* extinfo,
1517                    bool add_as_children,
1518                    bool search_linked_namespaces,
1519                    std::vector<android_namespace_t*>* namespaces) {
1520  // Step 0: prepare.
1521  std::unordered_map<const soinfo*, ElfReader> readers_map;
1522  LoadTaskList load_tasks;
1523
1524  for (size_t i = 0; i < library_names_count; ++i) {
1525    const char* name = library_names[i];
1526    load_tasks.push_back(LoadTask::create(name, start_with, ns, &readers_map));
1527  }
1528
1529  // If soinfos array is null allocate one on stack.
1530  // The array is needed in case of failure; for example
1531  // when library_names[] = {libone.so, libtwo.so} and libone.so
1532  // is loaded correctly but libtwo.so failed for some reason.
1533  // In this case libone.so should be unloaded on return.
1534  // See also implementation of failure_guard below.
1535
1536  if (soinfos == nullptr) {
1537    size_t soinfos_size = sizeof(soinfo*)*library_names_count;
1538    soinfos = reinterpret_cast<soinfo**>(alloca(soinfos_size));
1539    memset(soinfos, 0, soinfos_size);
1540  }
1541
1542  // list of libraries to link - see step 2.
1543  size_t soinfos_count = 0;
1544
1545  auto scope_guard = android::base::make_scope_guard([&]() {
1546    for (LoadTask* t : load_tasks) {
1547      LoadTask::deleter(t);
1548    }
1549  });
1550
1551  ZipArchiveCache zip_archive_cache;
1552
1553  // Step 1: expand the list of load_tasks to include
1554  // all DT_NEEDED libraries (do not load them just yet)
1555  for (size_t i = 0; i<load_tasks.size(); ++i) {
1556    LoadTask* task = load_tasks[i];
1557    soinfo* needed_by = task->get_needed_by();
1558
1559    bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
1560    task->set_extinfo(is_dt_needed ? nullptr : extinfo);
1561    task->set_dt_needed(is_dt_needed);
1562
1563    // Note: start from the namespace that is stored in the LoadTask. This namespace
1564    // is different from the current namespace when the LoadTask is for a transitive
1565    // dependency and the lib that created the LoadTask is not found in the
1566    // current namespace but in one of the linked namespace.
1567    if (!find_library_internal(const_cast<android_namespace_t*>(task->get_start_from()),
1568                               task,
1569                               &zip_archive_cache,
1570                               &load_tasks,
1571                               rtld_flags,
1572                               search_linked_namespaces || is_dt_needed)) {
1573      return false;
1574    }
1575
1576    soinfo* si = task->get_soinfo();
1577
1578    if (is_dt_needed) {
1579      needed_by->add_child(si);
1580    }
1581
1582    // When ld_preloads is not null, the first
1583    // ld_preloads_count libs are in fact ld_preloads.
1584    if (ld_preloads != nullptr && soinfos_count < ld_preloads_count) {
1585      ld_preloads->push_back(si);
1586    }
1587
1588    if (soinfos_count < library_names_count) {
1589      soinfos[soinfos_count++] = si;
1590    }
1591  }
1592
1593  // Step 2: Load libraries in random order (see b/24047022)
1594  LoadTaskList load_list;
1595  for (auto&& task : load_tasks) {
1596    soinfo* si = task->get_soinfo();
1597    auto pred = [&](const LoadTask* t) {
1598      return t->get_soinfo() == si;
1599    };
1600
1601    if (!si->is_linked() &&
1602        std::find_if(load_list.begin(), load_list.end(), pred) == load_list.end() ) {
1603      load_list.push_back(task);
1604    }
1605  }
1606  shuffle(&load_list);
1607
1608  for (auto&& task : load_list) {
1609    if (!task->load()) {
1610      return false;
1611    }
1612  }
1613
1614  // Step 3: pre-link all DT_NEEDED libraries in breadth first order.
1615  for (auto&& task : load_tasks) {
1616    soinfo* si = task->get_soinfo();
1617    if (!si->is_linked() && !si->prelink_image()) {
1618      return false;
1619    }
1620  }
1621
1622  // Step 4: Construct the global group. Note: DF_1_GLOBAL bit of a library is
1623  // determined at step 3.
1624
1625  // Step 4-1: DF_1_GLOBAL bit is force set for LD_PRELOADed libs because they
1626  // must be added to the global group
1627  if (ld_preloads != nullptr) {
1628    for (auto&& si : *ld_preloads) {
1629      si->set_dt_flags_1(si->get_dt_flags_1() | DF_1_GLOBAL);
1630    }
1631  }
1632
1633  // Step 4-2: Gather all DF_1_GLOBAL libs which were newly loaded during this
1634  // run. These will be the new member of the global group
1635  soinfo_list_t new_global_group_members;
1636  for (auto&& task : load_tasks) {
1637    soinfo* si = task->get_soinfo();
1638    if (!si->is_linked() && (si->get_dt_flags_1() & DF_1_GLOBAL) != 0) {
1639      new_global_group_members.push_back(si);
1640    }
1641  }
1642
1643  // Step 4-3: Add the new global group members to all the linked namespaces
1644  if (namespaces != nullptr) {
1645    for (auto linked_ns : *namespaces) {
1646      for (auto si : new_global_group_members) {
1647        if (si->get_primary_namespace() != linked_ns) {
1648          linked_ns->add_soinfo(si);
1649          si->add_secondary_namespace(linked_ns);
1650        }
1651      }
1652    }
1653  }
1654
1655  // Step 5: Collect roots of local_groups.
1656  // Whenever needed_by->si link crosses a namespace boundary it forms its own local_group.
1657  // Here we collect new roots to link them separately later on. Note that we need to avoid
1658  // collecting duplicates. Also the order is important. They need to be linked in the same
1659  // BFS order we link individual libraries.
1660  std::vector<soinfo*> local_group_roots;
1661  if (start_with != nullptr && add_as_children) {
1662    local_group_roots.push_back(start_with);
1663  } else {
1664    CHECK(soinfos_count == 1);
1665    local_group_roots.push_back(soinfos[0]);
1666  }
1667
1668  for (auto&& task : load_tasks) {
1669    soinfo* si = task->get_soinfo();
1670    soinfo* needed_by = task->get_needed_by();
1671    bool is_dt_needed = needed_by != nullptr && (needed_by != start_with || add_as_children);
1672    android_namespace_t* needed_by_ns =
1673        is_dt_needed ? needed_by->get_primary_namespace() : ns;
1674
1675    if (!si->is_linked() && si->get_primary_namespace() != needed_by_ns) {
1676      auto it = std::find(local_group_roots.begin(), local_group_roots.end(), si);
1677      LD_LOG(kLogDlopen,
1678             "Crossing namespace boundary (si=%s@%p, si_ns=%s@%p, needed_by=%s@%p, ns=%s@%p, needed_by_ns=%s@%p) adding to local_group_roots: %s",
1679             si->get_realpath(),
1680             si,
1681             si->get_primary_namespace()->get_name(),
1682             si->get_primary_namespace(),
1683             needed_by == nullptr ? "(nullptr)" : needed_by->get_realpath(),
1684             needed_by,
1685             ns->get_name(),
1686             ns,
1687             needed_by_ns->get_name(),
1688             needed_by_ns,
1689             it == local_group_roots.end() ? "yes" : "no");
1690
1691      if (it == local_group_roots.end()) {
1692        local_group_roots.push_back(si);
1693      }
1694    }
1695  }
1696
1697  // Step 6: Link all local groups
1698  for (auto root : local_group_roots) {
1699    soinfo_list_t local_group;
1700    android_namespace_t* local_group_ns = root->get_primary_namespace();
1701
1702    walk_dependencies_tree(root,
1703      [&] (soinfo* si) {
1704        if (local_group_ns->is_accessible(si)) {
1705          local_group.push_back(si);
1706          return kWalkContinue;
1707        } else {
1708          return kWalkSkip;
1709        }
1710      });
1711
1712    soinfo_list_t global_group = local_group_ns->get_global_group();
1713    bool linked = local_group.visit([&](soinfo* si) {
1714      // Even though local group may contain accessible soinfos from other namesapces
1715      // we should avoid linking them (because if they are not linked -> they
1716      // are in the local_group_roots and will be linked later).
1717      if (!si->is_linked() && si->get_primary_namespace() == local_group_ns) {
1718        if (!si->link_image(global_group, local_group, extinfo) ||
1719            !get_cfi_shadow()->AfterLoad(si, solist_get_head())) {
1720          return false;
1721        }
1722      }
1723
1724      return true;
1725    });
1726
1727    if (!linked) {
1728      return false;
1729    }
1730  }
1731
1732  // Step 7: Mark all load_tasks as linked and increment refcounts
1733  // for references between load_groups (at this point it does not matter if
1734  // referenced load_groups were loaded by previous dlopen or as part of this
1735  // one on step 6)
1736  if (start_with != nullptr && add_as_children) {
1737    start_with->set_linked();
1738  }
1739
1740  for (auto&& task : load_tasks) {
1741    soinfo* si = task->get_soinfo();
1742    si->set_linked();
1743  }
1744
1745  for (auto&& task : load_tasks) {
1746    soinfo* si = task->get_soinfo();
1747    soinfo* needed_by = task->get_needed_by();
1748    if (needed_by != nullptr &&
1749        needed_by != start_with &&
1750        needed_by->get_local_group_root() != si->get_local_group_root()) {
1751      si->increment_ref_count();
1752    }
1753  }
1754
1755
1756  return true;
1757}

看到这我第一时间感觉这块代码是不是大改过。应该是随着android迭代而增加的。本来不想粘怎么多代码的。但是看它写了这个函数的具体的操作的步骤,我就简单写一下把

  1. 全部代码都是围绕着LoadTask列表操作。第一步就是把所有依赖的so都找出来初始化load_tasks 列表。这个列表是 std::vector<LoadTask*>,猜测所有载入操作实际就是在LoadTask类中进行的。
  2. 调用LoadTask的load 方法载入so
  3. 后面就是处理载入的so,然后进行linking。至于什么namespace,local group和global group是啥,我也不明白,就先不写了
  4. 最后做一些首尾的清理工作。这一套走完。我们的soinfos就初始化玩了。

最后我们看一下find_library_internal,其实也没啥可看的,都是比较底层的工作,一层层调用之后。最后就是读so的磁盘文件。之后他们负责初始化传进来的LoadTask的类。初始化好了之后,以后LoadTask调用load方法就就完成载入了。

/bionic/linker/linker.cpp

1442static bool find_library_internal(android_namespace_t* ns,
1443                                  LoadTask* task,
1444                                  ZipArchiveCache* zip_archive_cache,
1445                                  LoadTaskList* load_tasks,
1446                                  int rtld_flags,
1447                                  bool search_linked_namespaces) {
1448  soinfo* candidate;
1449
1450  if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
1451    task->set_soinfo(candidate);
1452    return true;
1453  }
1454
1455  // Library might still be loaded, the accurate detection
1456  // of this fact is done by load_library.
1457  TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
1458      task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
1459
1460  if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
1461    return true;
1462  }
1463
1464  if (search_linked_namespaces) {
1465    // if a library was not found - look into linked namespaces
1466    // preserve current dlerror in the case it fails.
1467    DlErrorRestorer dlerror_restorer;
1468    for (auto& linked_namespace : ns->linked_namespaces()) {
1469      if (find_library_in_linked_namespace(linked_namespace,
1470                                           task)) {
1471        if (task->get_soinfo() == nullptr) {
1472          // try to load the library - once namespace boundary is crossed
1473          // we need to load a library within separate load_group
1474          // to avoid using symbols from foreign namespace while.
1475          //
1476          // However, actual linking is deferred until when the global group
1477          // is fully identified and is applied to all namespaces.
1478          // Otherwise, the libs in the linked namespace won't get symbols from
1479          // the global group.
1480          if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
1481            return true;
1482          }
1483        } else {
1484          // lib is already loaded
1485          return true;
1486        }
1487      }
1488    }
1489  }
1490
1491  return false;
1492}
14931322static bool load_library(android_namespace_t* ns,
1323                         LoadTask* task,
1324                         ZipArchiveCache* zip_archive_cache,
1325                         LoadTaskList* load_tasks,
1326                         int rtld_flags,
1327                         bool search_linked_namespaces) {
1328  const char* name = task->get_name();
1329  soinfo* needed_by = task->get_needed_by();
1330  const android_dlextinfo* extinfo = task->get_extinfo();
1331
1332  off64_t file_offset;
1333  std::string realpath;
1334  if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
1335    file_offset = 0;
1336    if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
1337      file_offset = extinfo->library_fd_offset;
1338    }
1339
1340    if (!realpath_fd(extinfo->library_fd, &realpath)) {
1341      PRINT("warning: unable to get realpath for the library \"%s\" by extinfo->library_fd. "
1342            "Will use given name.", name);
1343      realpath = name;
1344    }
1345
1346    task->set_fd(extinfo->library_fd, false);
1347    task->set_file_offset(file_offset);
1348    return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
1349  }
1350
1351  // Open the file.
1352  int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
1353  if (fd == -1) {
1354    DL_ERR("library \"%s\" not found", name);
1355    return false;
1356  }
1357
1358  task->set_fd(fd, true);
1359  task->set_file_offset(file_offset);
1360
1361  return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
1362}
1363
1364static bool find_loaded_library_by_soname(android_namespace_t* ns,
1365                                          const char* name,
1366                                          soinfo** candidate) {
1367  return !ns->soinfo_list().visit([&](soinfo* si) {
1368    const char* soname = si->get_soname();
1369    if (soname != nullptr && (strcmp(name, soname) == 0)) {
1370      *candidate = si;
1371      return false;
1372    }
1373
1374    return true;
1375  });
1376}
1377
1378// Returns true if library was found and false otherwise
1379static bool find_loaded_library_by_soname(android_namespace_t* ns,
1380                                         const char* name,
1381                                         bool search_linked_namespaces,
1382                                         soinfo** candidate) {
1383  *candidate = nullptr;
1384
1385  // Ignore filename with path.
1386  if (strchr(name, '/') != nullptr) {
1387    return false;
1388  }
1389
1390  bool found = find_loaded_library_by_soname(ns, name, candidate);
1391
1392  if (!found && search_linked_namespaces) {
1393    // if a library was not found - look into linked namespaces
1394    for (auto& link : ns->linked_namespaces()) {
1395      if (!link.is_accessible(name)) {
1396        continue;
1397      }
1398
1399      android_namespace_t* linked_ns = link.linked_namespace();
1400
1401      if (find_loaded_library_by_soname(linked_ns, name, candidate)) {
1402        return true;
1403      }
1404    }
1405  }
1406
1407  return found;
1408}
14091188static bool load_library(android_namespace_t* ns,
1189                         LoadTask* task,
1190                         LoadTaskList* load_tasks,
1191                         int rtld_flags,
1192                         const std::string& realpath,
1193                         bool search_linked_namespaces) {
1194  off64_t file_offset = task->get_file_offset();
1195  const char* name = task->get_name();
1196  const android_dlextinfo* extinfo = task->get_extinfo();
1197
1198  if ((file_offset % PAGE_SIZE) != 0) {
1199    DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset);
1200    return false;
1201  }
1202  if (file_offset < 0) {
1203    DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset);
1204    return false;
1205  }
1206
1207  struct stat file_stat;
1208  if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) {
1209    DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno));
1210    return false;
1211  }
1212  if (file_offset >= file_stat.st_size) {
1213    DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64,
1214        name, file_offset, file_stat.st_size);
1215    return false;
1216  }
1217
1218  // Check for symlink and other situations where
1219  // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
1220  if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
1221    soinfo* si = nullptr;
1222    if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
1223      TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
1224            "will return existing soinfo", name, si->get_realpath());
1225      task->set_soinfo(si);
1226      return true;
1227    }
1228  }
1229
1230  if ((rtld_flags & RTLD_NOLOAD) != 0) {
1231    DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name);
1232    return false;
1233  }
1234
1235  struct statfs fs_stat;
1236  if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) {
1237    DL_ERR("unable to fstatfs file for the library \"%s\": %s", name, strerror(errno));
1238    return false;
1239  }
1240
1241  // do not check accessibility using realpath if fd is located on tmpfs
1242  // this enables use of memfd_create() for apps
1243  if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) {
1244    // TODO(dimitry): workaround for http://b/26394120 - the grey-list
1245
1246    // TODO(dimitry) before O release: add a namespace attribute to have this enabled
1247    // only for classloader-namespaces
1248    const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
1249    if (is_greylisted(ns, name, needed_by)) {
1250      // print warning only if needed by non-system library
1251      if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) {
1252        const soinfo* needed_or_dlopened_by = task->get_needed_by();
1253        const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" :
1254                                                      needed_or_dlopened_by->get_realpath();
1255        DL_WARN_documented_change(__ANDROID_API_N__,
1256                                  "private-api-enforced-for-api-level-24",
1257                                  "library \"%s\" (\"%s\") needed or dlopened by \"%s\" "
1258                                  "is not accessible by namespace \"%s\"",
1259                                  name, realpath.c_str(), sopath, ns->get_name());
1260        add_dlwarning(sopath, "unauthorized access to",  name);
1261      }
1262    } else {
1263      // do not load libraries if they are not accessible for the specified namespace.
1264      const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ?
1265                                          "(unknown)" :
1266                                          task->get_needed_by()->get_realpath();
1267
1268      DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"",
1269             name, needed_or_dlopened_by, ns->get_name());
1270
1271      // do not print this if a library is in the list of shared libraries for linked namespaces
1272      if (!maybe_accessible_via_namespace_links(ns, name)) {
1273        PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the"
1274              " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\","
1275              " permitted_paths=\"%s\"]",
1276              name, realpath.c_str(),
1277              needed_or_dlopened_by,
1278              ns->get_name(),
1279              android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
1280              android::base::Join(ns->get_default_library_paths(), ':').c_str(),
1281              android::base::Join(ns->get_permitted_paths(), ':').c_str());
1282      }
1283      return false;
1284    }
1285  }
1286
1287  soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
1288  if (si == nullptr) {
1289    return false;
1290  }
1291
1292  task->set_soinfo(si);
1293
1294  // Read the ELF header and some of the segments.
1295  if (!task->read(realpath.c_str(), file_stat.st_size)) {
1296    soinfo_free(si);
1297    task->set_soinfo(nullptr);
1298    return false;
1299  }
1300
1301  // find and set DT_RUNPATH and dt_soname
1302  // Note that these field values are temporary and are
1303  // going to be overwritten on soinfo::prelink_image
1304  // with values from PT_LOAD segments.
1305  const ElfReader& elf_reader = task->get_elf_reader();
1306  for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) {
1307    if (d->d_tag == DT_RUNPATH) {
1308      si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val));
1309    }
1310    if (d->d_tag == DT_SONAME) {
1311      si->set_soname(elf_reader.get_string(d->d_un.d_val));
1312    }
1313  }
1314
1315  for_each_dt_needed(task->get_elf_reader(), [&](const char* name) {
1316    load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map()));
1317  });
1318
1319  return true;
1320}

相关文章:

android so载入过程

源自android 9 看源代码的网页 /bionic/libdl/libdl_static.c 好像没用。都是空的 /bionic/libdl/libdl.cpp 主角 22// These functions are exported by the loader 23// TODO(dimitry): replace these with reference to libc.so101// Proxy calls to bionic loader 102_…...

FlowerShop花店管理系统wpf+sqlserver

FlowerShop花店管理系统wpfsqlserver说明文档 运行前附加数据库.mdf&#xff08;或sql生成数据库&#xff09; 主要技术&#xff1a; 基于C#wpf架构和sql server数据库 功能模块&#xff1a; 顾客登录后可以查询花卉详情然后购买 店主登录管理后台 顾客管理 删除顾客多行删…...

如何在群晖NAS部署WPS容器并实现无公网IP远程访问本地office软件

文章目录 1. 拉取WPS Office镜像2. 运行WPS Office镜像容器3. 本地访问WPS Office4. 群晖安装Cpolar5. 配置WPS Office远程地址6. 远程访问WPS Office小结 7. 固定公网地址 wps-office是一个在Linux服务器上部署WPS Office的镜像。它基于WPS Office的Linux版本&#xff0c;通过…...

【C语言程序设计】C语言求圆周率π(三种方法)

题目一&#xff1a; 利用公式①计求π的近似值&#xff0c;要求累加到最后一项小于10^(-6)为止。 程序代码&#xff1a; #include <stdio.h> #include <stdlib.h> #include <math.h> int main(){float s1;float pi0;float i1.0;float n1.0;while(fabs(i)&…...

常见的特殊端口号及其用途

21端口&#xff1a;FTP&#xff08;文件传输协议&#xff09;服务端口。FTP允许用户进行文件传输&#xff0c;如上传和下载文件。22端口&#xff1a;SSH&#xff08;安全外壳协议&#xff09;服务端口。SSH用于远程登录到服务器&#xff0c;并提供加密的数据传输。23端口&#…...

Linux(ubuntu) 安装kotlin

Kotlin 是一种基于 Java 语言的静态类型编程语言&#xff0c;它可以运行于 JVM 上 1. 安装 Java Development Kit (JDK) Kotlin 运行于 JVM 上&#xff0c;所以首先需要安装 Java Development Kit&#xff08;JDK&#xff09; Ubuntu 或 Debian 系统 sudo apt update sudo a…...

微信小程序提交成功设置提示

在微信小程序中&#xff0c;当用户成功提交表单或完成某项操作后&#xff0c;通常我们会设置一个提示来告知用户操作已完成。这种提示通常可以通过几种方式来实现&#xff0c;例如使用 wx.showToast 方法显示一个短暂的提示消息&#xff0c;或者跳转到一个新的页面并显示成功信…...

Pycharm与Anaconda安装

网址&#xff1a; Pycharm&#xff1a;https://www.jetbrains.com/pycharm/ Anaconda&#xff1a;https://www.anaconda.com/download/ 官网下载速度太慢可以选择到清华源下载&#xff1a;https://repo.anaconda.com/archive/ 一&#xff1a;Anaconda安装 安装&#xff1a; …...

阿里云数据盘挂载目录

1、先登录服务器创建新目录aaa 2、云盘都快照备份下。后续操作完核实无误了&#xff0c;您根据您需求删除快照就行&#xff0c; 然后登录服务器内执行&#xff1a; fdisk -l lsblk blkid ll /aaa 3、执行&#xff1a;&#xff08;以下命令是进行数据盘做ext4文件系统并挂载到…...

【Python】探索PyPinyin 库:Python 中的中文拼音转换工具

花未全开月未圆&#xff0c; 半山微醉尽余欢。 何须多虑盈亏事&#xff0c; 终是小满胜万全。 —— 《对抗路—吕布》 PyPinyin 是一个功能强大的 Python 库&#xff0c;用于将中文文本转换为拼音。它提供了丰富的功能&#xff0c;能够满足各种中文文本处理的需求。在本文中&am…...

Linux运维总结:Centos7.6之OpenSSH7.4升级版本至9.3

一、环境信息 操作系统&#xff1a;Centos7.6.1810 OpenSSH_7.4p1, OpenSSL 1.0.2k-fips 注意&#xff1a;升级后由于加密算法的区别&#xff0c;低版本的SSH工具可能无法连接&#xff0c;建议改用Xshell7或SecureCRT9.0以上版本。 二、注意事项 1、 检查防火墙或selinux是否…...

SD-WAN能解决企业网络的哪些问题?

SD-WAN技术的崛起为企业网络带来了全新的解决方案。在数字化转型、云计算、远程办公和5G等领域&#xff0c;SD-WAN技术展现出强劲的市场趋势。那么&#xff0c;SD-WAN究竟能够解决企业网络中的哪些难题呢&#xff1f; 提升网络带宽利用率 传统网络在连接分支机构时&#xff0c;…...

Python实战:Python集合的常见操作

Python集合&#xff08;set&#xff09;是一种无序且元素唯一的容器&#xff0c;它是Python中一种基本的数据结构。本文将详细介绍Python集合的常见操作&#xff0c;包括创建集合、添加和删除元素、集合运算、集合推导式等。 1. 创建集合 Python集合可以通过多种方式创建&…...

Linux: cloud: network: tap tx 丢包一例,vCPU的运行受到主机CPU的占用影响

https://access.redhat.com/documentation/en-us/red_hat_openstack_platform/10/html/ovs-dpdk_end_to_end_troubleshooting_guide/high_packet_loss_in_the_tx_queue_of_the_instance_s_tap_interface 这个里面有一个丢包的例子是说&#xff0c;如果tx-queue的大小不够大&am…...

揭秘数据之美:利用 Bokeh 轻松构建实时、动态的数据可视化项目

1、引言 想让你的数据跃然 “屏” 上&#xff1f;厌倦了静态图表的平淡无奇&#xff1f;那么&#xff0c;今天就让我们一起探索 Python 世界中的瑰宝 ——Bokeh 库。这款强大的可视化工具以其流畅的交互性和实时更新能力&#xff0c;让你的数据呈现如电影般生动立体&#xff0…...

性能测试场景分析并设计?超细案例讲解

前言 性能测试场景&#xff0c;其实和功能测试没什么区别&#xff0c;只是侧重点不同。 我们在功能测试中经常用到的等价类边界值等分析和设计测试case的方法&#xff0c;目的是为了尽可能的覆盖业务场景&#xff0c;避免遗漏导致的功能逻辑缺失或者未达到预期。 而在性能测试…...

python面向对象练习一

假设我们正在开发一个学生管理系统&#xff0c;我们需要创建一个Student类来表示学生对象。 每个学生都有学号、姓名和年龄属性。我们还希望能够打印学生的信息&#xff0c;并在删除学生对象时输出一条提示消息。 要求使用__str__()管理学生信息的打印 要求使用__del__()管理删…...

【Linux-tar/gzip/zip】

Linux-tar/gzip/zip ■ tar■ gzip■ zip■ unzip解压缩 ■ tar 基本语法&#xff1a; tar [选项] 压缩后的压缩包 要压缩的文件 选项说明描述-cf :对文件或文件夹进行打包-v :显示压缩的进度- z :使用gzip压缩工具把打包后的文件进行压缩为.gz-j :使用bzip2压缩工具把打包后…...

第一代高通S7和S7 Pro音频平台:超旗舰性能,全面革新音频体验

以下文章来源于高通中国 如今&#xff0c;音频内容与形式日渐丰富&#xff0c;可满足人们放松心情、提升自我、获取资讯等需求。得益于手机、手表、耳机、车载音箱等智能设备的广泛应用&#xff0c;音频内容可以更快速触达用户。从《音频产品使用现状调研报告2023》中发现&…...

el-menu + el-badge 菜单加红点标识el-badge

el-menu el-badge 菜单加红点标识el-badge 一、el-menu组件menu/index.vuemenu/submenu.vue 二、获取/更新菜单红点标识 main.js引入全局组件/mixins全局混入 el-menu封装 一、el-menu组件 menu/index.vue 重点&#xff1a;定义 ref"menu"&#xff0c;切换路由时…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

AspectJ 在 Android 中的完整使用指南

一、环境配置&#xff08;Gradle 7.0 适配&#xff09; 1. 项目级 build.gradle // 注意&#xff1a;沪江插件已停更&#xff0c;推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

jmeter聚合报告中参数详解

sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample&#xff08;样本数&#xff09; 表示测试中发送的请求数量&#xff0c;即测试执行了多少次请求。 单位&#xff0c;以个或者次数表示。 示例&#xff1a;…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

什么是VR全景技术

VR全景技术&#xff0c;全称为虚拟现实全景技术&#xff0c;是通过计算机图像模拟生成三维空间中的虚拟世界&#xff0c;使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验&#xff0c;结合图文、3D、音视频等多媒体元素…...