blob: e6f00aa0e7d8b40a9ce89616475b323a5c5a5b62 [file] [log] [blame]
<html devsite><head>
<title>VNDK 编译系统支持</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>
在 Android 8.1 及更高版本中,编译系统具有内置的 VNDK 支持。如果启用了 VNDK 支持,编译系统就会检查各模块之间的依赖关系,为供应商模块编译特定于供应商的变体,并自动将这些模块安装到指定目录中。
</p>
<h2 id="vndk-build-support-example">VNDK 编译支持示例</h2>
<p>
在此示例中,<code>Android.bp</code> 模块定义定义了一个名为 <code>libexample</code> 的库。<code>vendor_available</code> 属性表示框架模块和供应商模块均可能依赖于 <code>libexample</code>
</p>
<p>
<img src="../images/treble_vndk_androidbp.png" alt="具有 vendor_available:true 和 vndk.enabled:true 的 libexample"/>
</p>
<figcaption>
<strong>图 1.</strong> 已启用 VNDK 支持
</figcaption>
<p>
框架可执行文件 <code>/system/bin/foo</code> 和供应商可执行文件 <code>/vendor/bin/bar</code> 均依赖于 <code>libexample</code>,并且在其 <code>shared_libs</code> 属性中具有 <code>libexample</code>
</p>
<p>
如果框架模块和供应商模块均使用 <code>libexample</code>,则编译 <code>libexample</code> 的两个变体。核心变体(以 <code>libexample</code> 命名)由框架模块使用,供应商变体(以 <code>libexample.vendor</code> 命名)由供应商模块使用。这两个变体将安装到不同的目录中。
</p>
<ul>
<li>核心变体将安装到 <code>/system/lib[64]/libexample.so</code> 中。</li>
<li>供应商变体将安装到 <code>/system/lib[64]/vndk/libexample.so</code> 中,因为 <code>vndk.enabled</code><code>true</code></li>
</ul>
<p>
如需了解详情,请参阅<a href="#module-definition">模块定义</a>
</p>
<h2 id="configuring-build-support">配置编译支持</h2>
<p>
要为产品设备启用完整编译系统支持,请将 <code>BOARD_VNDK_VERSION</code> 添加到 <code>BoardConfig.mk</code>
</p>
<pre class="prettyprint">BOARD_VNDK_VERSION := current</pre>
<p>
此设置会产生<strong>全局</strong>效应:如果在 <code>BoardConfig.mk</code> 中定义,系统会检查所有模块。由于没有将违规模块列入黑名单或白名单的机制,因此在添加 <code>BOARD_VNDK_VERSION</code> 之前应清除所有不必要的依赖项。您可以通过在环境变量中设置 <code>BOARD_VNDK_VERSION</code> 来测试和编译模块:
</p>
<pre class="prettyprint">$ BOARD_VNDK_VERSION=current m module_name.vendor</pre>
<p>如果启用 <code>BOARD_VNDK_VERSION</code>,系统会移除多个默认的全局标头搜索路径。<em></em>其中包括:
</p>
<ul>
<li><code>frameworks/av/include</code></li>
<li><code>frameworks/native/include</code></li>
<li><code>frameworks/native/opengl/include</code></li>
<li><code>hardware/libhardware/include</code></li>
<li><code>hardware/libhardware_legacy/include</code></li>
<li><code>hardware/ril/include</code></li>
<li><code>libnativehelper/include</code></li>
<li><code>libnativehelper/include_deprecated</code></li>
<li><code>system/core/include</code></li>
<li><code>system/media/audio/include</code></li>
</ul>
<p>
如果某个模块依赖于上述目录中的标头,则您必须明确指定与 <code>header_libs</code><code>static_libs</code> 和/或 <code>shared_libs</code> 的依赖关系。
</p>
<h2 id="module-definition">模块定义</h2>
<p>
要使用 <code>BOARD_VNDK_VERSION</code> 编译 Android,您必须在 <code>Android.mk</code><code>Android.bp</code> 中修改模块定义。此部分介绍了不同种类的模块定义,一些与 VNDK 相关的模块属性,以及在编译系统中实现的依赖性检查。
</p>
<h3 id="vendor-modules">供应商模块</h3>
<p>
供应商模块是特定于供应商的可执行文件或共享库(必须将这些模块安装到供应商分区中)。在 <code>Android.bp</code> 文件中,供应商模块必须将供应商或专有属性设置为 <code>true</code>。在 <code>Android.mk</code> 文件中,供应商模块必须将 <code>LOCAL_VENDOR_MODULE</code><code>LOCAL_PROPRIETARY_MODULE</code> 设置为 <code>true</code>
</p>
<p>
如果定义了 <code>BOARD_VNDK_VERSION</code>,则编译系统不允许在供应商模块和框架模块之间建立依赖关系,并且编译系统会在以下情况下发出错误:
</p>
<ul>
<li>不具有 <code>vendor:true</code> 的模块依赖于具有 <code>vendor:true</code> 的模块,或</li>
<li>具有 <code>vendor:true</code> 的模块依赖于既不具有 <code>vendor:true</code> 也不具有 <code>vendor_available:true</code> 的非 <code>llndk_library</code> 模块。</li>
</ul>
<p>
依赖性检查适用于 <code>Android.bp</code> 中的 <code>header_libs</code><code>static_libs</code><code>shared_libs</code> 以及 <code>Android.mk</code> 中的 <code>LOCAL_HEADER_LIBRARIES</code><code>LOCAL_STATIC_LIBRARIES</code><code>LOCAL_SHARED_LIBRARIES</code>
</p>
<h3 id="ll-ndk">LL-NDK</h3>
<p>
LL-NDK 共享库是具有稳定 ABI 的共享库。框架模块和供应商模块均具有相同的最新实现。对于每个 LL-NDK 共享库,<code>Android.bp</code> 都包含一个 <code>llndk_library</code> 模块定义:
</p>
<pre class="prettyprint">
llndk_library {
name: "libvndksupport",
symbol_file: "libvndksupport.map.txt",
}
</pre>
<p>
该模块定义指定了模块名称和符号文件,后者描述了对供应商模块可见的符号。例如:
</p>
<pre class="prettyprint">
LIBVNDKSUPPORT {
global:
android_load_sphal_library; # vndk
android_unload_sphal_library; # vndk
local:
*;
};
</pre>
<p>
编译系统会根据符号文件为供应商模块生成存根共享库。如果启用了 <code>BOARD_VNDK_VERSION</code>,供应商模块将与这些存根共享库建立关联。只有在满足以下条件时,存根共享库中才会包含符号:
</p>
<ul>
<li>它未在以 <code>_PRIVATE</code><code>_PLATFORM</code> 结尾的部分中定义,</li>
<li>它不含 <code>#platform-only</code> 标记,并且</li>
<li>不含 <code>#introduce*</code> 标记或者该标记与目标匹配。</li>
</ul>
<aside class="note">
<strong>注意</strong>:供应商不得定义自己的 LL-NDK 共享库,因为供应商模块无法在<a href="/setup/build/gsi">通用系统映像 (GSI)</a> 中找到它们。
</aside>
<h3 id="vndk">VNDK</h3>
<p>
<code>Android.bp</code> 文件中,<code>cc_library</code><code>cc_library_static</code><code>cc_library_shared</code><code>cc_library_headers</code> 模块定义支持三个与 VNDK 相关的属性:<code>vendor_available</code><code>vndk.enabled</code><code>vndk.support_system_process</code>
</p>
<p>
如果 <code>vendor_available</code><code>vndk.enabled</code><code>true</code>,则可以编译两种变体(核心变体和供应商变体)。<em></em><em></em>核心变体应被视为框架模块,而供应商变体应被视为供应商模块。如果某些框架模块依赖于此模块,则会编译核心变体。如果某些供应商模块依赖于此模块,则会编译供应商变体。编译系统会强制执行以下依赖性检查:
</p>
<ul>
<li>核心变体始终供框架专用,无法供供应商模块访问。</li>
<li>供应商变体始终无法供框架模块访问。</li>
<li>供应商变体的所有依赖项(在 <code>header_libs</code><code>static_libs</code> 和/或 <code>shared_libs</code> 中指定)必须是 <code>llndk_library</code> 或具有 <code>vendor_available</code><code>vndk.enabled</code> 的模块。</li>
<li>如果 <code>vendor_available</code><code>true</code>,则供应商变体可供所有供应商模块访问。</li>
<li>如果 <code>vendor_available</code><code>false</code>,则供应商变体仅可供其他 VNDK 或 VNDK-SP 模块访问(即,具有 <code>vendor:true</code> 的模块无法与 <code>vendor_available:false</code> 模块相关联)。</li>
</ul>
<p>
系统将通过以下规则确定 <code>cc_library</code><code>cc_library_shared</code> 的默认安装路径:
</p>
<ul>
<li>将核心变体安装到 <code>/system/lib[64]</code> 中。</li>
<li>供应商变体安装路径可能会有所不同:
<ul>
<li>如果 <code>vndk.enabled</code><code>false</code>,则将供应商变体将安装到 <code>/vendor/lib[64]</code> 中。</li>
<li>如果 <code>vndk.enabled</code><code>true</code>,则 <code>vndk.support_system_process</code> 可以是 <code>true</code><code>false</code>。如果:
<ul>
<li><code>false</code>,则供应商变体将安装到 <code>/system/lib[64]/vndk-${VER}</code> 中。</li>
<li><code>true</code>,则供应商变体将安装到 <code>/system/lib[64]/vndk-sp-${VER}</code> 中。</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>
下表总结了编译系统如何处理供应商变体:
</p>
<table>
<tbody><tr>
<th>vendor_available</th>
<th style="text-align: center">vndk<br />已启用</th>
<th style="text-align: center">vndk<br />support_same_process</th>
<th>供应商变体说明</th>
</tr>
<tr>
<td rowspan="4"><code>true</code></td>
<td rowspan="2"><code>false</code></td>
<td><code>false</code></td>
<td>供应商变体为 VND-ONLY。共享库将安装到 <code>/vendor/lib[64]</code> 中。<em></em></td>
</tr>
<tr>
<td><code>true</code></td>
<td>无效(编译错误)<em></em></td>
</tr>
<tr>
<td rowspan="2"><code>true</code></td>
<td><code>false</code></td>
<td>供应商变体为 VNDK。共享库将安装到 <code>/system/lib[64]/vndk-${VER}</code> 中。<em></em></td>
</tr>
<tr>
<td><code>true</code></td>
<td>供应商变体为 VNDK-SP。共享库将安装到 <code>/system/lib[64]/vndk-sp-${VER}</code> 中。<em></em></td>
</tr>
<tr>
<td rowspan="4"><p><code>false</code></p></td>
<td rowspan="2"><p><code>false</code></p></td>
<td><p><code>false</code></p></td>
<td><p>没有供应商变体。此模块为 FWK-ONLY。<em></em></p></td>
</tr>
<tr>
<td><code>true</code></td>
<td>无效(编译错误)<em></em></td>
</tr>
<tr>
<td rowspan="2"><code>true</code></td>
<td><code>false</code></td>
<td>供应商变体为 VNDK-Private。<em></em>共享库将安装到 <code>/system/lib[64]/vndk-${VER}</code> 中。供应商模块不得直接使用这些变体。</td>
</tr>
<tr>
<td><code>true</code></td>
<td>供应商变体为 VNDK-SP-Private。<em></em>共享库将安装到 <code>/system/lib[64]/vndk-sp-${VER}</code> 中。供应商模块不得直接使用这些变体。</td>
</tr>
</tbody></table>
<aside class="note">
<strong>注意</strong>:供应商可以为其模块设置 <code>vendor_available</code>,但不得设置 <code>vndk.enabled</code><code>vndk.support_system_process</code>,因为供应商模块无法在<a href="/setup/build/gsi">通用系统映像 (GSI)</a> 中找到它们。
</aside>
<h3 id="vndk-extensions">VNDK 扩展</h3>
<p>
VNDK 扩展是具有额外 API 的 VNDK 共享库,将安装到 <code>/vendor/lib[64]/vndk[-sp]</code> 中(不含版本后缀),并在系统运行时会替换原始的 VNDK 共享库。
</p>
<h4 id="defining-vndk-extensions">定义 VNDK 扩展</h4>
<p>
在 Android 9 及更高版本中,<code>Android.bp</code> 本身支持 VNDK 扩展。要编译 VNDK 扩展,请定义另一个具有 <code>vendor:true</code><code>extends</code> 属性的模块:
</p>
<pre class="prettyprint">
cc_library {
name: "libvndk",
vendor_available: true,
vndk: {
enabled: true,
},
}
cc_library {
name: "libvndk_ext",
vendor: true,
vndk: {
enabled: true,
extends: "libvndk",
},
}
</pre>
<p>
具有 <code>vendor:true</code><code>vndk.enabled:true</code><code>extends</code> 属性的模块可定义 VNDK 扩展:</p>
<ul>
<li><code>extends</code> 属性必须指定基础 VNDK 共享库名称(或 VNDK-SP 共享库名称)。</li>
<li>VNDK 扩展(或 VNDK-SP 扩展)以扩展时所基于的基础模块名称命名。例如,<code>libvndk_ext</code> 的输出二进制文件是 <code>libvndk.so</code>,而非 <code>libvndk_ext.so</code></li>
<li>VNDK 扩展将安装到 <code>/vendor/lib[64]/vndk</code> 中。</li>
<li>VNDK-SP 扩展将安装到 <code>/vendor/lib[64]/vndk-sp</code> 中。</li>
<li>基础共享库必须同时具有 <code>vndk.enabled:true</code><code>vendor_available:true</code></li>
</ul>
<p>
VNDK-SP 扩展必须从 VNDK-SP 共享库进行扩展(<code>vndk.support_system_process</code> 必须相等):
</p>
<pre class="prettyprint">
cc_library {
name: "libvndk_sp",
vendor_available: true,
vndk: {
enabled: true,
support_system_process: true,
},
}
cc_library {
name: "libvndk_sp_ext",
vendor: true,
vndk: {
enabled: true,
extends: "libvndk_sp",
support_system_process: true,
},
}
</pre>
<p>
VNDK 扩展(或 VNDK-SP 扩展)可以依赖于其他供应商共享库:
</p>
<pre class="prettyprint">
cc_library {
name: "libvndk",
vendor_available: true,
vndk: {
enabled: true,
},
}
cc_library {
name: "libvndk_ext",
vendor: true,
vndk: {
enabled: true,
extends: "libvndk",
},
shared_libs: [
"libvendor",
],
}
cc_library {
name: "libvendor",
vendor: true,
}
</pre>
<aside class="note">
<strong>注意</strong>:与 SP-HAL-Dep 类似,VNDK-SP 扩展及其依赖项(包括供应商库)在 sepolicy 中必须标记为 <code>same_process_hal_file</code>
</aside>
<h4 id="using-vndk-extensions">使用 VNDK 扩展</h4>
<p>
如果供应商模块依赖于由 VNDK 扩展定义的其他 API,则该模块必须在其 <code>shared_libs</code> 属性中指定 VNDK 扩展的名称:
</p>
<pre class="prettyprint">
// A vendor shared library example
cc_library {
name: "libvendor",
vendor: true,
shared_libs: [
"libvndk_ext",
],
}
// A vendor executable example
cc_binary {
name: "vendor-example",
vendor: true,
shared_libs: [
"libvndk_ext",
],
}
</pre>
<p>
如果供应商模块依赖于 VNDK 扩展,则这些 VNDK 扩展将自动安装到 <code>/vendor/lib[64]/vndk[-sp]</code> 中。如果某个模块不再依赖于 VNDK 扩展,请向 <code>CleanSpec.mk</code> 添加一个清理步骤,以移除共享库。例如:
</p>
<pre class="prettyprint">
$(call add-clean-step, rm -rf $(TARGET_OUT_VENDOR)/lib/libvndk.so)
</pre>
<h3 id="conditional-compilation">条件编译</h3>
<p>
本节介绍了如何处理以下三个 VNDK 共享库之间的细微差别(例如,为其中一个变体添加或移除某项功能):<em></em>
</p>
<ul>
<li>核心变体(例如 <code>/system/lib[64]/libexample.so</code></li>
<li>供应商变体(例如 <code>/system/lib[64]/vndk[-sp]-${VER}/libexample.so</code></li>
<li>VNDK 扩展(例如 <code>/vendor/lib[64]/vndk[-sp]/libexample.so</code>
</li>
</ul>
<h4 id="conditional-cflags">条件编译器标记</h4>
<p>
默认情况下,Android 编译系统会为供应商变体(包括 VNDK 扩展)定义 <code>__ANDROID_VNDK__</code>。您可以使用 C 预处理器防护程序来保护相应代码:
</p>
<pre class="prettyprint">
void all() { }
#if !defined(__ANDROID_VNDK__)
void framework_only() { }
#endif
#if defined(__ANDROID_VNDK__)
void vndk_only() { }
#endif
</pre>
<p>
除了 <code>__ANDROID_VNDK__</code>,还可以在 <code>Android.bp</code> 中指定不同的 <code>cflags</code><code>cppflags</code>。在 <code>target.vendor</code> 中指定的 <code>cflags</code><code>cppflags</code> 是专门针对供应商变体的。例如,以下代码示例是针对 <code>libexample</code><code>libexample_ext</code><code>Android.bp</code> 模块定义:
</p>
<pre class="prettyprint">
cc_library {
name: "libexample",
srcs: ["example.c"],
vendor_available: true,
vndk: {
enabled: true,
},
target: {
vendor: {
cflags: ["-DLIBEXAMPLE_ENABLE_VNDK=1"],
},
},
}
cc_library {
name: "libexample_ext",
srcs: ["example.c"],
vendor: true,
vndk: {
enabled: true,
extends: "libexample",
},
cflags: [
"-DLIBEXAMPLE_ENABLE_VNDK=1",
"-DLIBEXAMPLE_ENABLE_VNDK_EXT=1",
],
}
</pre>
<p>
<code>example.c</code> 的代码清单:
</p>
<pre class="prettyprint">
void all() { }
#if !defined(LIBEXAMPLE_ENABLE_VNDK)
void framework_only() { }
#endif
#if defined(LIBEXAMPLE_ENABLE_VNDK)
void vndk() { }
#endif
#if defined(LIBEXAMPLE_ENABLE_VNDK_EXT)
void vndk_ext() { }
#endif
</pre>
<p>
针对每个变体导出的符号:
</p>
<table>
<tbody><tr>
<th>安装路径</th>
<th>导出的符号</th>
</tr>
<tr>
<td><code>/system/lib[64]/libexample.so</code></td>
<td><code>all</code><code>framework_only</code></td>
</tr>
<tr>
<td><code>/system/lib[64]/vndk-${VER}/libexample.so</code></td>
<td><code>all</code><code>vndk</code></td>
</tr>
<tr>
<td><code>/vendor/lib[64]/vndk/libexample.so</code></td>
<td><code>all</code><code>vndk</code><code>vndk_ext</code></td>
</tr>
</tbody></table>
<p>
VNDK ABI 合规性检查工具会将 VNDK 和 VNDK 扩展的 ABI 同 <code>prebuilts/abi-dumps/vndk</code> 下的 ABI 转储进行比较:
</p>
<ul>
<li>通过原始 VNDK 共享库导出的符号必须与 ABI 转储中定义的符号相同(而不是后者的超集)。</li>
<li>通过 VNDK 扩展导出的符号必须是 ABI 转储中定义的符号的超集。</li>
</ul>
<h4 id="excluding">排除源文件或共享库</h4>
<p>
要从供应商变体中排除源文件,请将相应文件添加到 <code>exclude_srcs</code> 属性中。同样,要确保共享库未与供应商变体相关联,请将这些库添加到 <code>exclude_shared_libs</code> 属性中。例如:
</p>
<pre class="prettyprint">
cc_library {
name: "libcond_exclude_example",
srcs: ["fwk.c", "both.c"],
shared_libs: ["libfwk_only", "libboth"],
target: {
vendor: {
exclude_srcs: ["fwk.c"],
exclude_shared_libs: ["libfwk_only"],
},
},
}
</pre>
<p>
在本示例中,<code>libcond_exclude_example</code> 的核心变体包含 <code>fwk.c</code><code>both.c</code> 中的代码,并且依赖于共享库 <code>libfwk_only</code><code>libboth</code><code>libcond_exclude_example</code> 的供应商变体仅包含 <code>both.c</code> 中的代码,因为 <code>fwk.c</code> 已被 <code>exclude_srcs</code> 属性排除。同样,<code>libcond_exclude_example</code> 仅依赖于共享库 <code>libboth</code>,因为 <code>libfwk_only</code> 已被 <code>exclude_shared_libs</code> 属性排除。
</p>
<h3 id="product-packages">产品包</h3>
<p>
在 Android 编译系统中,变量 <code>PRODUCT_PACKAGES</code> 指定应安装到设备中的可执行文件、共享库或软件包。指定模块的传递依赖项也会隐式安装到设备中。
</p>
<p>
如果启用了 <code>BOARD_VNDK_VERSION</code>,具有 <code>vendor_available</code><code>vndk.enabled</code> 的模块会得到特殊处理。如果框架模块依赖于具有 <code>vendor_available</code><code>vndk.enabled</code> 的模块,则核心变体将纳入传递安装集中。同样,如果供应商模块依赖于具有 <code>vendor_available</code><code>vndk.enabled</code> 的模块,则供应商变体将纳入传递安装集中。
</p>
<p>
当相关依赖项对编译系统不可见时(例如,可以在运行时使用 <code>dlopen()</code> 打开的共享库),您应该在 <code>PRODUCT_PACKAGES</code> 中指定模块名称来明确安装这些模块。
</p>
<p>
如果某个模块具有 <code>vendor_available</code><code>vndk.enabled</code>,则模块名称代表该模块的核心变体。要在 <code>PRODUCT_PACKAGES</code> 中明确指定供应商变体,请将 <code>.vendor</code> 后缀附加到模块名称上。例如:
</p>
<pre class="prettyprint">
cc_library {
name: "libexample",
srcs: ["example.c"],
vendor_available: true,
}
</pre>
<p>
在本示例中,<code>libexample</code> 代表 <code>/system/lib[64]/libexample.so</code><code>libexample.vendor</code> 代表 <code>/vendor/lib[64]/libexample.so</code>。要安装 <code>/vendor/lib[64]/libexample.so</code>,请将 <code>libexample.vendor</code> 添加到 <code>PRODUCT_PACKAGES</code>
</p>
<pre class="prettyprint">PRODUCT_PACKAGES += libexample.vendor</pre>
</body></html>