| <html devsite><head> |
| <title>链接器命名空间</title> |
| <meta name="project_path" value="/_project.yaml"/> |
| <meta name="book_path" value="/_book.yaml"/> |
| </head> |
| <body> |
| <!-- |
| Copyright 2017 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| <p>动态链接器解决了 Treble VNDK 设计中的两个难题:</p> |
| |
| <ul> |
| <li>将 SP-HAL 共享库及其依赖项(包括 VNDK-SP 库)加载到框架进程中。这种情况下应该有一些防止出现符号冲突的机制。</li> |
| |
| <li><code>dlopen()</code> 和 <code>android_dlopen_ext()</code> 可能会引入一些在编译时不可见的运行时依赖项,这些依赖项使用静态分析很难检测到。</li> |
| </ul> |
| |
| <p>这两个难题可以通过链接器命名空间机制来解决。<em></em>链接器命名空间机制由动态链接器提供,可以隔离不同链接器命名空间中的共享库,以确保具有相同库名称和不同符号的库不会发生冲突。</p> |
| |
| <p>另一方面,链接器命名空间机制可提供相应的灵活性,从而将由一个链接器命名空间导出的某些共享库用于另一个链接器命名空间。这些导出的共享库可能会成为对其他程序公开的应用编程接口,同时在其链接器命名空间中隐藏实现细节。</p> |
| |
| <p>例如,<code>/system/lib[64]/libcutils.so</code> 和 <code>/system/lib[64]/vndk-sp-${VER}/libcutils.so</code> 是两个共享库。这两个库可能有不同的符号。它们会加载到不同的链接器命名空间中,以便框架模块可以依赖于 <code>/system/lib[64]/libcutils.so</code>,而 SP-HAL 共享库则可以依赖于 <code>/system/lib[64]/vndk-sp-${VER}/libcutils.so</code>。</p> |
| |
| <p>另一方面,<code>/system/lib[64]/libc.so</code> 是由一个链接器命名空间导出而后又被导入到许多链接器命名空间中的公共库。<code>/system/lib[64]/libc.so</code> 的依赖项(例如 <code>libnetd_client.so</code>)将被加载到 <code>/system/lib[64]/libc.so</code> 所在的命名空间中。其他命名空间将无法访问这些依赖项。这种机制会在提供公共接口的同时封装实现细节。</p> |
| |
| <h2 id="how-does-it-work">工作原理</h2> |
| |
| <p>动态链接器负责加载 <code>DT_NEEDED</code> 条目中指定的共享库,或由 <code>dlopen()</code> 或 <code>android_dlopen_ext()</code> 的参数指定的共享库。在这两种情况下,动态链接器都会找出调用程序所在的链接器命名空间,并尝试将相关依赖项加载到同一个链接器命名空间中。如果动态链接器无法将共享库加载到指定的链接器命名空间中,它会向关联的链接器命名空间索取导出的共享库。<em></em></p> |
| |
| <h2 id="configuration-file-format">配置文件格式</h2> |
| |
| <p>配置文件格式取决于 INI 文件格式。典型的配置文件如下所示:</p> |
| |
| <pre class="prettyprint"> |
| dir.system = /system/bin |
| dir.system = /system/xbin |
| dir.vendor = /vendor/bin |
| |
| [system] |
| additional.namespaces = sphal,vndk |
| |
| namespace.default.isolated = true |
| namespace.default.search.paths = /system/${LIB} |
| namespace.default.permitted.paths = /system/${LIB}/hw |
| namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB} |
| namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw |
| |
| namespace.sphal.isolated = true |
| namespace.sphal.visible = true |
| namespace.sphal.search.paths = /odm/${LIB}:/vendor/${LIB} |
| namespace.sphal.permitted.paths = /odm/${LIB}:/vendor/${LIB} |
| namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}:/odm/${LIB} |
| namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}:/vendor/${LIB} |
| namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}:/odm/${LIB} |
| namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}:/vendor/${LIB} |
| namespace.sphal.links = default,vndk |
| namespace.sphal.link.default.shared_libs = libc.so:libm.so |
| namespace.sphal.link.vndk.shared_libs = libbase.so:libcutils.so |
| |
| namespace.vndk.isolated = true |
| namespace.vndk.search.paths = /system/${LIB}/vndk-sp-29 |
| namespace.vndk.permitted.paths = /system/${LIB}/vndk-sp-29 |
| namespace.vndk.links = default |
| namespace.vndk.link.default.shared_libs = libc.so:libm.so |
| |
| [vendor] |
| namespace.default.isolated = false |
| namespace.default.search.paths = /vendor/${LIB}:/system/${LIB} |
| </pre> |
| |
| <p>配置文件包含以下内容:</p> |
| |
| <ul> |
| <li>多个“目录-区段”映射属性(位于动态链接器的开头),用于选择有效的区段。</li> |
| |
| <li>多个链接器命名空间配置区段:<ul> |
| <li>每个区段都包含多个命名空间(圆形顶点)以及各命名空间之间的多个回退链接(图形弧)。</li> |
| |
| <li>每个命名空间都具有自己的隔离、搜索路径、允许的路径以及可见性设置。</li> |
| </ul> |
| </li> |
| </ul> |
| |
| <p>下表详细介绍了各属性的含义。</p> |
| |
| <h3 id="directory-section-mapping-property">“目录-区段”映射属性</h3> |
| |
| <table> |
| <tbody><tr> |
| <th>属性</th> |
| <th>说明</th> |
| <th>示例</th> |
| </tr> |
| |
| <tr> |
| <td><p><code>dir.<var>name</var></code></p></td> |
| |
| <td> |
| <p>指向 <code>[<var>name</var>]</code> 区段所应用到的目录的路径。</p> |
| |
| <p>每个属性都会将目录下的可执行文件映射到链接器命名空间配置区段。可能会有 2 个(或多个)属性具有相同的 <code><var>name</var></code>,却指向不同的目录。</p> |
| </td> |
| |
| <td> |
| <p> |
| <code>dir.system = /system/bin</code><br /> |
| <code>dir.system = /system/xbin</code><br /> |
| <code>dir.vendor = /vendor/bin</code><br /> |
| </p> |
| |
| <p>这表示在 <code>[system]</code> 区段中指定的配置适用于从 <code>/system/bin</code> 或 <code>/system/xbin</code> 加载的可执行文件。</p> |
| |
| <p>在 <code>[vendor]</code> 区段中指定的配置适用于从 <code>/vendor/bin</code> 加载的可执行文件。</p> |
| </td> |
| </tr> |
| </tbody></table> |
| |
| <h3 id="relation-properties">关系属性</h3> |
| |
| <table> |
| <tbody><tr> |
| <th>属性</th> |
| <th>说明</th> |
| <th>示例</th> |
| </tr> |
| |
| <tr> |
| <td><code>additional.<wbr></wbr>namespaces</code></td> |
| |
| <td> |
| <p>相应区段的其他命名空间的逗号分隔列表(<code>default</code> 命名空间除外)。</p> |
| </td> |
| |
| <td> |
| <p><code>additional.<wbr></wbr>namespaces = sphal,<wbr></wbr>vndk</code></p> |
| |
| <p>这表示 <code>[system]</code> 配置中有 3 个命名空间(<code>default</code>、<code>sphal</code> 和 <code>vndk</code>)。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>links</code></td> |
| |
| <td> |
| <p>回退命名空间的逗号分隔列表。</p> |
| |
| <p>如果在当前命名空间中找不到共享库,则动态链接器会尝试从回退命名空间加载共享库。在列表开头指定的命名空间优先级较高。</p> |
| |
| <aside class="note">注意:回退命名空间没有传递特性。例如,命名空间 A 链接到命名空间 B,命名空间 B 链接到命名空间 C。如果动态链接器在命名空间 A 中找不到相应的库,则它仅会搜索命名空间 B,而不会搜索命名空间 C。<em></em><em></em><em></em><em></em><em></em><em></em><em></em></aside> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>sphal.<wbr></wbr>links = default,<wbr></wbr>vndk</code></p> |
| |
| <p>如果某个共享库或可执行文件请求另一个共享库,而后者无法加载到 <code>sphal</code> 命名空间,则动态链接器会尝试从 <code>default</code> 命名空间加载此共享库。</p> |
| |
| <p>然后,如果此共享库也无法从 <code>default</code> 命名空间加载,则动态链接器会尝试从 <code>vndk</code> 命名空间加载此共享库。</p> |
| |
| <p>最后,如果所有尝试都失败,则动态链接器会返回一个错误。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>link.<wbr></wbr><var>other</var>.<wbr></wbr>shared_libs</code></td> |
| |
| <td> |
| <p>用冒号分隔的共享库列表(如果在 <code>name</code> 命名空间中找不到这些共享库,则可以在 <code>other</code> 命名空间中搜索)。</p> |
| |
| <p>此属性无法与 <code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>link.<wbr></wbr><var>other</var>.<wbr></wbr>allow_all_shared_libs</code> 一起使用。</p> |
| |
| <aside class="note"><p>注意:此属性与 <a href="/devices/tech/config/namespaces_libraries">public.libraries.txt</a> 文件在底层实现上是相同的。这两种机制都通过使用库名称过滤器指定链接的方式来控制导入的共享库。</p> |
| |
| <p>不同之处在于,<code>ld.config.txt</code> 由动态链接器进行加载,并且所有命名空间都是在程序启动时创建的。相反,<code>libnativeloader</code> 会在 Zygote 进程针对某个应用进行分岔和专门化操作时创建链接器命名空间。应用原生库的命名空间具有一个仅允许使用在 <code>public.libraries.txt</code> 中指定的库名称的链接。</p></aside> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>sphal.<wbr></wbr>link.<wbr></wbr>default.<wbr></wbr>shared_libs = libc.so:<wbr></wbr>libm.so</code></p> |
| |
| <p>这表示回退链接仅接受 <code>libc.so</code> 或 <code>libm.so</code> 作为请求的库名称。如果请求的库名称不是 <code>libc.so</code> 或 <code>libm.so</code>,则动态链接器会忽略从 <code>sphal</code> 到 <code>default</code> 命名空间的回退链接。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>link.<wbr></wbr><var>other</var>.<wbr></wbr>allow_all_shared_libs</code></td> |
| |
| <td> |
| <p>一个布尔值,用于指示在 <code><var>name</var></code> 命名空间中找不到共享库时,是否所有共享库都可以在 <code><var>other</var></code> 命名空间中搜索。</p> |
| |
| <p>此属性无法与 <code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>link.<wbr></wbr><var>other</var>.<wbr></wbr>shared_libs</code> 一起使用。</p> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>vndk.<wbr></wbr>link.<wbr></wbr>sphal.<wbr></wbr>allow_all_shared_libs = true</code></p> |
| |
| <p>这表示所有库名称都可以遍历从 <code>vndk</code> 到 <code>sphal</code> 命名空间的回退链接。</p> |
| </td> |
| </tr> |
| </tbody></table> |
| |
| <h3 id="namespace-properties">命名空间属性</h3> |
| |
| <table> |
| <tbody><tr> |
| <th>属性</th> |
| <th>说明</th> |
| <th>示例</th> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>isolated</code></td> |
| |
| <td> |
| <p>一个布尔值,用于指示动态链接器是否应该检查共享库在什么位置。</p> |
| |
| <p>如果 <code>isolated</code> 为 <code>true</code>,则只有某个 <code>search.paths</code> 目录(不包含子目录)中或 <code>permitted.paths</code>(包含子目录)下的共享库才能加载。<em></em><em></em></p> |
| |
| <p>如果 <code>isolated</code> 为 <code>false</code>,则动态链接器不会检查共享库的路径。</p> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>sphal.<wbr></wbr>isolated = true</code></p> |
| |
| <p>这表示只有 <code>search.paths</code> 中或 <code>permitted.paths</code> 下的共享库才能加载到 <code>sphal</code> 命名空间。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>search.paths</code></td> |
| |
| <td> |
| <p>以冒号分隔的目录列表,用于搜索共享库。</p> |
| |
| <p>如果函数调用 <code>dlopen()</code> 或 <code>DT_NEEDED</code> 条目时未指定完整路径,则在 <code>search.paths</code> 中指定的目录将附加到请求的库名称前面。在列表开头指定的目录优先级较高。</p> |
| |
| <p>如果 <code>isolated</code> 为 <code>true</code>,则任一 <code>search.paths</code> 目录(不包含子目录)中的共享库都可以加载,无论 <code>permitted.paths</code> 属性如何设置。<em></em></p> |
| |
| <p>例如,如果 <code>search.paths</code> 为 <code>/system/${LIB}</code>,并且 <code>permitted.paths</code> 为空,则 <code>/system/${LIB}/libc.so</code> 可以加载,但 <code>/system/${LIB}/vndk/libutils.so</code> 无法加载。</p> |
| |
| <aside class="note">注意:<code>${LIB}</code> 是内置占位符。对于 32 位进程,此占位符将替换为 <code>lib</code>;对于 64 位进程,此占位符将替换为 <code>lib64</code>。</aside> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>default.<wbr></wbr>search.paths = /system/${LIB}</code></p> |
| |
| <p>这表示动态链接器会在 <code>/system/${LIB}</code> 中搜索共享库。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>asan.search.paths</code></td> |
| |
| <td> |
| <p>以冒号分隔的目录列表,用于在启用 <a href="/devices/tech/debug/asan">Address Sanitizer</a> 后搜索共享库。</p> |
| |
| <p>在启用 <a href="/devices/tech/debug/asan">Address Sanitizer</a> 后,系统会忽略 <code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>search.paths</code>。</p> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>default.<wbr></wbr>asan.search.paths = /data/asan/system/${LIB}:<wbr></wbr>/system/${LIB}</code></p> |
| |
| <p>这表示在启用 <a href="/devices/tech/debug/asan">Address Sanitizer</a> 后,动态链接器会先搜索 <code>/data/asan/system/${LIB}</code>,然后再搜索 <code>/system/${LIB}</code>。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>permitted.paths</code></td> |
| |
| <td> |
| <p>以冒号分隔的目录列表(包含子目录),当 <code>isolated</code> 为 <code>true</code> 时,动态链接器可在其中加载共享库(除了 <code>search.paths</code> 以外)。</p> |
| |
| <p><code>permitted.paths</code> 的子目录下的共享库也可以加载。例如,如果 <code>permitted.paths</code> 为 <code>/system/${LIB}</code>,则 <code>/system/${LIB}/libc.so</code> 和 <code>/system/${LIB}/vndk/libutils.so</code> 均可加载。</p> |
| |
| <p>如果 <code>isolated</code> 为 <code>false</code>,则系统会忽略 <code>permitted.paths</code> 并发出相应警告。</p> |
| |
| <aside class="note">注意:在动态链接器搜索共享库时,<code>permitted.paths</code> 不会附加到请求的库名称前面。其主要目的是让程序员能够通过指定共享库的完整路径将共享库加载到隔离的命名空间。</aside> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>default.<wbr></wbr>permitted.paths = /system/${LIB}/hw</code></p> |
| |
| <p>这表示 <code>/system/${LIB}/hw</code> 下的共享库可以加载到隔离的 <code>default</code> 命名空间。</p> |
| |
| <p>例如,如果没有 <code>permitted.paths</code>,则 <code>libaudiohal.so</code> 无法将 <code>/system/${LIB}/hw/audio.a2dp.default.so</code> 加载到 <code>default</code> 命名空间。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>asan.permitted.paths</code></td> |
| |
| <td> |
| <p>以冒号分隔的目录列表,在启用 <a href="/devices/tech/debug/asan">Address Sanitizer</a> 后,动态链接器可在其中加载共享库。</p> |
| |
| <p>在启用 <a href="/devices/tech/debug/asan">Address Sanitizer</a> 后,系统会忽略 <code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>permitted.paths</code>。</p> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>default.<wbr></wbr>asan.permitted.paths = /data/asan/system/${LIB}/hw:<wbr></wbr>/system/${LIB}/hw</code></p> |
| |
| <p>这表示在启用 <a href="/devices/tech/debug/asan">Address Sanitizer</a> 后,<code>/data/asan/system/${LIB}/hw</code> 或 <code>/system/${LIB}/hw</code> 下的共享库可以加载到隔离的 <code>default</code> 命名空间。</p> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>namespace.<wbr></wbr><var>name</var>.<wbr></wbr>visible</code></td> |
| |
| <td> |
| <p>一个布尔值,用于指示程序(不包括 <code>libc</code>)是否可以包含带有 <code>android_get_exported_namespace()</code> 的链接器命名空间句柄,以及通过将此句柄传递到 <code>android_dlopen_ext()</code> 打开链接器命名空间中的共享库。</p> |
| |
| <p>如果 <code>visible</code> 为 <code>true</code>,则 <code>android_get_exported_namespace()</code> 在命名空间存在时始终返回此句柄。</p> |
| |
| <p>如果 <code>visible</code> 为 <code>false</code>(默认值),则无论命名空间是否存在,<code>android_get_exported_namespace()</code> 始终返回 <code>NULL</code>。仅当符合以下条件时,共享库才能加载到此命名空间:(1) 具有指向此命名空间的回退链接的其他链接器命名空间请求这些共享库,或者 (2) 此命名空间中的其他共享库或可执行文件请求这些共享库。</p> |
| </td> |
| |
| <td> |
| <p><code>namespace.<wbr></wbr>sphal.<wbr></wbr>visible = true</code></p> |
| |
| <p>这表示 <code>android_get_exported_namespace("sphal")</code> 可以返回有效的链接器命名空间句柄。</p> |
| </td> |
| </tr> |
| </tbody></table> |
| |
| <h2 id="linker-namespace-isolation">链接器命名空间隔离</h2> |
| |
| <p><code>${android-src}/system/core/rootdir/etc</code> 中有 3 个配置文件。系统会根据 <code>BoardConfig.mk</code> 中 <code>PRODUCT_TREBLE_LINKER_NAMESPACES</code>、<code>BOARD_VNDK_VERSION</code> 和 <code>BOARD_VNDK_RUNTIME_DISABLE</code> 的值选择不同的配置:</p> |
| |
| <table> |
| <tbody><tr> |
| <th><code>PRODUCT_TREBLE_</code><br /><code>LINKER_NAMESPACES</code></th> |
| <th><code>BOARD_VNDK_</code><br /><code>VERSION</code></th> |
| <th><code>BOARD_VNDK_</code><br /><code>RUNTIME_DISABLE</code></th> |
| <th>选择的配置</th> |
| <th>VTS 要求</th> |
| </tr> |
| |
| <tr> |
| <td rowspan="3"><code>true</code></td> |
| <td rowspan="2"><code>current</code></td> |
| <td><em>empty</em></td> |
| <td><code>ld.config.txt</code></td> |
| <td>搭载 Android P 的设备的必要配置。</td> |
| </tr> |
| |
| <tr> |
| <td><code>true</code></td> |
| <td rowspan="2"><code>ld.config.vndk_lite.txt</code></td> |
| <td rowspan="2">搭载 Android 8.x 的设备的必要配置。</td> |
| </tr> |
| |
| <tr> |
| <td><em>empty</em></td> |
| <td><em>any</em></td> |
| </tr> |
| |
| <tr> |
| <td><code>false</code></td> |
| <td><em>any</em></td> |
| <td><em>any</em></td> |
| <td><code>ld.config.legacy.txt</code></td> |
| <td>适用于不支持 Treble 的设备</td> |
| </tr> |
| </tbody></table> |
| |
| <p><code>${android-src}/system/core/rootdir/etc/ld.config.vndk_lite.txt</code> 会隔离 SP-HAL 和 VNDK-SP 共享库。在 Android 8.0 及更高版本中,当 <code>PRODUCT_TREBLE_LINKER_NAMESPACES</code> 为 <code>true</code> 时,该配置必须是动态链接器的配置文件。</p> |
| |
| <p><code>${android-src}/system/core/rootdir/etc/ld.config.txt</code> 也会隔离 SP-HAL 和 VNDK-SP 共享库。此外,<code>ld.config.txt</code> 还会提供全面的动态链接器隔离。它可确保系统分区中的模块不依赖于供应商分区中的共享库,反之亦然。</p> |
| |
| <p>在 Android 8.1 中,<code>ld.config.txt</code> 是默认配置文件,强烈建议您启用全面的动态链接器隔离。但是,如果在 Android 8.1 中需要清理的依赖项太多,您可以将 <code>BOARD_VNDK_RUNTIME_DISABLE</code> 添加到 <code>BoardConfig.mk</code> 中:</p> |
| |
| <pre class="prettyprint"> |
| BOARD_VNDK_RUNTIME_DISABLE := true |
| </pre> |
| |
| <p>如果 <code>BOARD_VNDK_RUNTIME_DISABLE</code> 为 <code>true</code>,则会安装 <code>${android-src}/system/core/rootdir/etc/ld.config.vndk_lite.txt</code>。</p> |
| |
| <h3 id="ld.config.txt">ld.config.txt</h3> |
| |
| <p><code>ld.config.txt</code> 会隔离系统分区和供应商分区之间的共享库依赖项。下文概述了该配置文件与上一小节中提到的 <code>ld.config.txt</code> 相比有哪些不同:</p> |
| |
| <ul> |
| <li> |
| <p>框架进程</p> |
| |
| <ul> |
| <li>创建了四个命名空间(<code>default</code>、<code>vndk</code>、<code>sphal</code> 和 <code>rs</code>)。</li> |
| |
| <li>系统会隔离所有命名空间。</li> |
| |
| <li>将系统共享库加载到 <code>default</code> 命名空间中。</li> |
| |
| <li>将 SP-HAL 加载到 <code>sphal</code> 命名空间中。</li> |
| |
| <li>将 VNDK-SP 共享库加载到 <code>vndk</code> 命名空间中。</li> |
| </ul> |
| </li> |
| |
| <li> |
| <p>供应商进程</p> |
| |
| <ul> |
| <li>创建了三个命名空间(<code>default</code>、<code>vndk</code> 和 <code>system</code>)。</li> |
| |
| <li>系统会隔离 <code>default</code> 命名空间。</li> |
| |
| <li>将供应商共享库加载到 <code>default</code> 命名空间中。</li> |
| |
| <li>将 VNDK 和 VNDK-SP 共享库加载到 <code>vndk</code> 命名空间中。</li> |
| |
| <li>将 LL-NDK 及其依赖项加载到 <code>system</code> 命名空间中。</li> |
| </ul> |
| </li> |
| </ul> |
| |
| <p>链接器命名空间之间的关系如下图所示:</p> |
| |
| <img src="../images/treble_vndk_linker_namespace3.png" alt="ld.config.txt 中描绘的链接器命名空间图表"/> |
| <figcaption> |
| <strong>图 1.</strong> 链接器命名空间隔离 (<code>ld.config.txt</code>) |
| </figcaption> |
| |
| <p>在上图中,LL-NDK 和 VNDK-SP 代表以下共享库:<em></em><em></em></p> |
| |
| <ul> |
| <li> |
| <em>LL-NDK</em> |
| |
| <ul> |
| <li><code>libEGL.so</code></li> |
| <li><code>libGLESv1_CM.so</code></li> |
| <li><code>libGLESv2.so</code></li> |
| <li><code>libGLESv3.so</code></li> |
| <li><code>libandroid_net.so</code></li> |
| <li><code>libc.so</code></li> |
| <li><code>libdl.so</code></li> |
| <li><code>liblog.so</code></li> |
| <li><code>libm.so</code></li> |
| <li><code>libnativewindow.so</code></li> |
| <li><code>libneuralnetworks.so</code></li> |
| <li><code>libsync.so</code></li> |
| <li><code>libvndksupport.so</code></li> |
| <li><code>libvulkan.so</code></li> |
| </ul> |
| </li> |
| |
| <li> |
| <em>VNDK-SP</em> |
| |
| <ul> |
| <li><code>[email protected]</code></li> |
| <li><code>[email protected]</code></li> |
| <li><code>[email protected]</code></li> |
| <li><code>[email protected]</code></li> |
| <li><code>libRSCpuRef.so</code></li> |
| <li><code>libRSDriver.so</code></li> |
| <li><code>libRS_internal.so</code></li> |
| <li><code>libbase.so</code></li> |
| <li><code>libbcinfo.so</code></li> |
| <li><code>libc++.so</code></li> |
| <li><code>libcutils.so</code></li> |
| <li><code>libhardware.so</code></li> |
| <li><code>libhidlbase.so</code></li> |
| <li><code>libhidlmemory.so</code></li> |
| <li><code>libhidltransport.so</code></li> |
| <li><code>libhwbinder.so</code></li> |
| <li><code>libion.so</code></li> |
| <li><code>libutils.so</code></li> |
| <li><code>libz.so</code></li> |
| </ul> |
| </li> |
| </ul> |
| |
| <p>下表列出了框架进程的命名空间配置(摘自 <code>ld.config.txt</code> 中的 <code>[system]</code> 部分):</p> |
| |
| <table> |
| <tbody><tr> |
| <th>命名空间</th> |
| <th>属性</th> |
| <th>值</th> |
| </tr> |
| |
| <tr> |
| <td rowspan="3"><code>default</code></td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/system/${LIB}</code><br /> |
| <code>/product/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/system/${LIB}/drm</code><br /> |
| <code>/system/${LIB}/extractors</code><br /> |
| <code>/system/${LIB}/hw</code><br /> |
| <code>/product/${LIB}</code><br /> |
| <code>/system/framework</code><br /> |
| <code>/system/app</code><br /> |
| <code>/system/priv-app</code><br /> |
| <code>/vendor/app</code><br /> |
| <code>/vendor/priv-app</code><br /> |
| <code>/oem/app</code><br /> |
| <code>/odm/priv-app</code><br /> |
| <code>/oem/app</code><br /> |
| <code>/product/framework</code><br /> |
| <code>/product/app</code><br /> |
| <code>/product/priv-app</code><br /> |
| <code>/data</code><br /> |
| <code>/mnt/expand</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td rowspan="8"><code>sphal</code></td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>visible</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>default,vndk,rs</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.default.shared_libs</code></td> |
| <td><em>LL-NDK</em></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.vndk.shared_libs</code></td> |
| <td><em>VNDK-SP</em></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.rs.shared_libs</code></td> |
| <td><code>libRS_internal.so</code></td> |
| </tr> |
| |
| <tr> |
| <td rowspan="7"><code>vndk</code>(适用于 VNDK-SP)</td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}/vndk-sp</code><br /> |
| <code>/vendor/${LIB}/vndk-sp</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/odm/${LIB}/hw</code><br /> |
| <code>/odm/${LIB}/egl</code><br /> |
| <code>/vendor/${LIB}/hw</code><br /> |
| <code>/vendor/${LIB}/egl</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}/hw</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>visible</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>default</code>、<code>sphal</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.default.shared_libs</code></td> |
| <td><em>LL-NDK</em></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.default.allow_all_shared_libs</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td rowspan="7"><code>rs</code>(适用于 Renderscript)</td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}/vndk-sp</code><br /> |
| <code>/vendor/${LIB}/vndk-sp</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}</code><br /> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code><br /> |
| <code>/data</code>(适用于已编译的 RS 内核) |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>visible</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>default,vndk</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.default.shared_libs</code></td> |
| <td> |
| <em>LL-NDK</em><br /> |
| <code>libmediandk.so</code><br /> |
| <code>libft2.so</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>link.vndk.shared_libs</code></td> |
| <td><em>VNDK-SP</em></td> |
| </tr> |
| </tbody></table> |
| |
| <p>下表列出了供应商进程的命名空间配置(摘自 <code>ld.config.txt</code> 中的 <code>[vendor]</code> 部分):</p> |
| |
| <table> |
| <tbody><tr> |
| <th>命名空间</th> |
| <th>属性</th> |
| <th>值</th> |
| </tr> |
| |
| <tr> |
| <td rowspan="7"><code>default</code></td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/odm</code><br /> |
| <code>/vendor</code><br /> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>visible</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>system</code>、<code>vndk</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.system.shared_libs</code></td> |
| <td><em>LL-NDK</em></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.vndk.shared_libs</code></td> |
| <td><em>VNDK</em>、<em>VNDK-SP</em>(供应商可用)</td> |
| </tr> |
| |
| <tr> |
| <td rowspan="5"><code>vndk</code></td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}/vndk</code><br /> |
| <code>/odm/${LIB}/vndk-sp</code><br /> |
| <code>/vendor/${LIB}/vndk</code><br /> |
| <code>/vendor/${LIB}/vndk-sp</code><br /> |
| <code>/system/${LIB}/vndk-${VER}</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>system</code>、<code>default</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.system.shared_libs</code></td> |
| <td><em>LL-NDK</em></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.default.allow_all_shared_libs</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td rowspan="2"><code>system</code></td> |
| <td><code>search.paths</code></td> |
| <td><code>/system/${LIB}</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>false</code></td> |
| </tr> |
| </tbody></table> |
| |
| <p>更多详情请见 <code>${android-src}/system/core/rootdir/etc/ld.config.txt</code>。</p> |
| |
| <h3 id="ld.config.vndk_lite.txt">ld.config.vndk_lite.txt</h3> |
| |
| <p>从 Android 8.0 开始,动态链接器将配置为隔离 SP-HAL 和 VNDK-SP 共享库,以使其符号不会与其他框架共享库发生冲突。链接器命名空间之间的关系如下所示:</p> |
| |
| <img src="../images/treble_vndk_linker_namespace1.png" alt="ld.config.vndk_lite.txt 中描绘的链接器命名空间图表"/> |
| <figcaption> |
| <strong>图 2.</strong> 链接器命名空间隔离 (<code>ld.config.vndk_lite.txt</code>) |
| </figcaption> |
| |
| <p><em></em><em></em>LL-NDK 和 VNDK-SP 代表以下共享库: |
| </p> |
| |
| <ul> |
| <li> |
| <em>LL-NDK</em> |
| |
| <ul> |
| <li><code>libEGL.so</code></li> |
| <li><code>libGLESv1_CM.so</code></li> |
| <li><code>libGLESv2.so</code></li> |
| <li><code>libc.so</code></li> |
| <li><code>libdl.so</code></li> |
| <li><code>liblog.so</code></li> |
| <li><code>libm.so</code></li> |
| <li><code>libnativewindow.so</code></li> |
| <li><code>libstdc++.so</code>(不在 <code>ld.config.txt</code> 中)</li> |
| <li><code>libsync.so</code></li> |
| <li><code>libvndksupport.so</code></li> |
| <li><code>libz.so</code>(已移到 <code>ld.config.txt</code> 中的 VNDK-SP)<em></em></li> |
| </ul> |
| </li> |
| |
| <li> |
| <em>VNDK-SP</em> |
| |
| <ul> |
| <li><code>[email protected]</code></li> |
| <li><code>[email protected]</code></li> |
| <li><code>[email protected]</code></li> |
| <li><code>[email protected]</code></li> |
| <li><code>libbase.so</code></li> |
| <li><code>libc++.so</code></li> |
| <li><code>libcutils.so</code></li> |
| <li><code>libhardware.so</code></li> |
| <li><code>libhidlbase.so</code></li> |
| <li><code>libhidlmemory.so</code></li> |
| <li><code>libhidltransport.so</code></li> |
| <li><code>libhwbinder.so</code></li> |
| <li><code>libion.so</code></li> |
| <li><code>libutils.so</code></li> |
| </ul> |
| </li> |
| </ul> |
| |
| <p>下表列出了框架进程的命名空间配置(摘自 <code>ld.config.vndk_lite.txt</code> 中的 <code>[system]</code> 部分):</p> |
| |
| <table> |
| <tbody><tr> |
| <th>命名空间</th> |
| <th>属性</th> |
| <th>值</th> |
| </tr> |
| |
| <tr> |
| <td rowspan="2"><code>default</code></td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/system/${LIB}</code><br /> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code><br /> |
| <code>/product/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>false</code></td> |
| </tr> |
| |
| <tr> |
| <td rowspan="8"><code>sphal</code></td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>visible</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>default,vndk,rs</code></td> |
| </tr> |
| <tr> |
| <td><code>link.default.shared_libs</code></td> |
| <td><em>LL-NDK</em></td> |
| </tr> |
| <tr> |
| <td><code>link.vndk.shared_libs</code></td> |
| <td><em>VNDK-SP</em></td> |
| </tr> |
| <tr> |
| <td><code>link.rs.shared_libs</code></td> |
| <td><code>libRS_internal.so</code></td> |
| </tr> |
| |
| <tr> |
| <td rowspan="6"><code>vndk</code>(适用于 VNDK-SP)</td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}/vndk-sp</code><br /> |
| <code>/vendor/${LIB}/vndk-sp</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/odm/${LIB}/hw</code><br /> |
| <code>/odm/${LIB}/egl</code><br /> |
| <code>/vendor/${LIB}/hw</code><br /> |
| <code>/vendor/${LIB}/egl</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}/hw</code><br /> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>visible</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>default</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.default.shared_libs</code></td> |
| <td><em>LL-NDK</em></td> |
| </tr> |
| |
| <tr> |
| <td rowspan="7"><code>rs</code>(适用于 Renderscript)</td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}/vndk-sp</code><br /> |
| <code>/vendor/${LIB}/vndk-sp</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}</code><br /> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>permitted.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/vendor/${LIB}</code><br /> |
| <code>/data</code>(适用于已编译的 RS 内核) |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>visible</code></td> |
| <td><code>true</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>links</code></td> |
| <td><code>default,vndk</code></td> |
| </tr> |
| |
| <tr> |
| <td><code>link.default.shared_libs</code></td> |
| <td> |
| <em>LL-NDK</em><br /> |
| <code>libmediandk.so</code><br /> |
| <code>libft2.so</code> |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>link.vndk.shared_libs</code></td> |
| <td><em>VNDK-SP</em></td> |
| </tr> |
| </tbody></table> |
| |
| <p>下表列出了供应商进程的命名空间配置(摘自 <code>ld.config.vndk_lite.txt</code> 中的 <code>[vendor]</code> 部分):</p> |
| |
| <table> |
| <tbody><tr> |
| <th>命名空间</th> |
| <th>属性</th> |
| <th>值</th> |
| </tr> |
| |
| <tr> |
| <td rowspan="2"><code>default</code></td> |
| <td><code>search.paths</code></td> |
| <td> |
| <code>/odm/${LIB}</code><br /> |
| <code>/odm/${LIB}/vndk</code><br /> |
| <code>/odm/${LIB}/vndk-sp</code><br /> |
| <code>/vendor/${LIB}</code><br /> |
| <code>/vendor/${LIB}/vndk</code><br /> |
| <code>/vendor/${LIB}/vndk-sp</code><br /> |
| <code>/system/${LIB}/vndk-${VER}</code><br /> |
| <code>/system/${LIB}/vndk-sp-${VER}</code><br /> |
| <code>/system/${LIB}</code>(已弃用)<br /> |
| <code>/product/${LIB}</code>(已弃用) |
| </td> |
| </tr> |
| |
| <tr> |
| <td><code>isolated</code></td> |
| <td><code>false</code></td> |
| </tr> |
| </tbody></table> |
| |
| <p>更多详情请见 <code>${android-src}/system/core/rootdir/etc/ld.config.vndk_lite.txt</code>。</p> |
| |
| <h2 id="document-history">文档历史记录</h2> |
| |
| <h3 id="changes-p">Android P 变更</h3> |
| |
| <ul> |
| <li><p>在 Android P 中,<code>vndk</code> 链接器命名空间已添加到供应商进程,而且 VNDK 共享库已与默认链接器命名空间隔离开。</p></li> |
| |
| <li><p>将 <code>PRODUCT_FULL_TREBLE</code> 替换为更具体的 <code>PRODUCT_TREBLE_LINKER_NAMESPACES</code>。</p></li> |
| |
| <li> |
| <p>Android P 更改了以下动态链接器配置文件的名称:</p> |
| |
| <table> |
| <tbody><tr> |
| <th>Android 8.x</th> |
| <th>Android P</th> |
| <th>说明</th> |
| </tr> |
| |
| <tr> |
| <td>ld.config.txt.in</td> |
| <td>ld.config.txt</td> |
| <td>对于具有运行时链接器命名空间隔离的设备</td> |
| </tr> |
| |
| <tr> |
| <td>ld.config.txt</td> |
| <td>ld.config.vndk_lite.txt</td> |
| <td>对于具有 VNDK-SP 链接器命名空间隔离的设备</td> |
| </tr> |
| |
| <tr> |
| <td>ld.config.legacy.txt</td> |
| <td>ld.config.legacy.txt</td> |
| <td>对于搭载 Android 7.x 及更早版本的旧版设备</td> |
| </tr> |
| </tbody></table> |
| </li> |
| |
| <li><p>移除 <code>[email protected]</code>。</p></li> |
| |
| <li><p>添加了 <code>product</code> 和 <code>odm</code> 分区。</p></li> |
| </ul> |
| |
| </body></html> |