blob: 0314bf3ad9620317222ea00bd3cc72a22c2ff249 [file] [log] [blame]
<html devsite><head>
<title>创建 HAL 接口</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>您必须使用 HIDL 来描述用于对框架进行条件式编译的所有编译标记。相关编译标记必须分组并包含在单个 <code>.hal</code> 文件中。使用 HIDL 指定配置项具有以下优势:</p>
<ul>
<li>可实施版本控制(为了添加新配置项,供应商/OEM 必须明确扩展 HAL)</li>
<li>记录详尽</li>
<li>可使用 SELinux 实现访问控制</li>
<li>可通过<a href="/devices/tech/test_infra/tradefed/fundamentals/vts">供应商测试套件</a>对配置项进行全面检查(范围检查、各项内容之间的相互依赖性检查等)</li>
<li>在 C++ 和 Java 中自动生成 API</li>
</ul>
<h2 id="identify-flags">确定框架使用的编译标记</h2>
<p>首先,请确定用于对框架进行条件式编译的编译标记,然后舍弃过时的配置以缩小编译标记集的范围。例如,下列编译标记集已确定用于 <code>surfaceflinger</code></p>
<ul>
<li><code>TARGET_USES_HWC2</code>(即将弃用)</li>
<li><code>TARGET_BOARD_PLATFORM</code></li>
<li><code>TARGET_DISABLE_TRIPLE_BUFFERING</code></li>
<li><code>TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS</code></li>
<li><code>NUM_FRAMEBUFFER_SURFACE_BUFFERS</code></li>
<li><code>TARGET_RUNNING_WITHOUT_SYNC_FRAMEWORK</code></li>
<li><code>VSYNC_EVENT_PHASE_OFFSET_NS</code></li>
<li><code>SF_VSYNC_EVENT_PHASE_OFFSET_NS</code>(即将弃用)</li>
<li><code>PRESENT_TIME_OFFSET_FROM_VSYNC_NS</code></li>
<li><code>MAX_VIRTUAL_DISPLAY_DIMENSION</code></li>
</ul>
<h2 id="create-interface">创建 HAL 接口</h2>
<p>子系统的编译配置是通过 HAL 接口访问的,而用于提供配置值的接口会在 HAL 软件包 <code>android.hardware.configstore</code>(目前为 1.0 版)中进行分组。例如,要为 <code>surfaceflinger</code> 创建 HAL 接口文件,请在 <strong><code>hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal</code></strong> 中运行以下命令:
</p>
<pre class="devsite-click-to-copy">
package android.hardware.configstore@1.0;
interface ISurfaceFlingerConfigs {
// TO-BE-FILLED-BELOW
};
</pre>
<p>创建 <code>.hal</code> 文件后,请运行 <code>hardware/interfaces/update-makefiles.sh</code> 以将新的 <code>.hal</code> 文件添加到 <code>Android.bp</code><code>Android.mk</code> 文件中。</p>
<h2 id="add-functions">为编译标记添加函数</h2>
<p>对于每个编译标记,请向相应接口各添加一个新函数。例如,在 <strong><code>hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal</code></strong> 中运行以下命令:
</p>
<pre class="devsite-click-to-copy">
interface ISurfaceFlingerConfigs {
disableTripleBuffering() generates(OptionalBool ret);
forceHwcForVirtualDisplays() generates(OptionalBool ret);
enum NumBuffers: uint8_t {
USE_DEFAULT = 0,
TWO = 2,
THREE = 3,
};
numFramebufferSurfaceBuffers() generates(NumBuffers ret);
runWithoutSyncFramework() generates(OptionalBool ret);
vsyncEventPhaseOffsetNs generates (OptionalUInt64 ret);
presentTimeOffsetFromSyncNs generates (OptionalUInt64 ret);
maxVirtualDisplayDimension() generates(OptionalInt32 ret);
};
</pre>
<p>添加函数时,请注意以下事项:</p>
<ul>
<li><strong>采用简洁的名称</strong>。请避免将 makefile 变量名称转换为函数名称,并切记 <code>TARGET_</code><code>BOARD_</code> 前缀不再是必需的。</li>
<li><strong>添加注释</strong>。帮助开发者了解配置项的用途,配置项如何改变框架行为、有效值等。</li>
</ul>
<p>函数返回类型可以是 <code>Optional[Bool|String|Int32|UInt32|Int64|UInt64]</code>。类型会在同一目录中的 <code>types.hal</code> 中进行定义,并使用字段(可表明原始值是否是由 HAL 指定)来封装原始值;如果原始值不是由 HAL 指定,则使用默认值。</p>
<pre class="devsite-click-to-copy">
struct OptionalString {
bool specified;
string value;
};
</pre>
<p>在适当的情况下,请定义最能代表配置项类型的枚举,并将该枚举用作返回类型。在上述示例中,<code>NumBuffers</code> 枚举会被定义为限制有效值的数量。在定义这类自定义数据类型时,请添加字段或枚举值(例如 <code>USE_DEFAULT</code>)来表示该值是否由 HAL 指定。</p>
<p>在 HIDL 中,单个编译标记并不一定要变成单个函数。模块所有者也可以将密切相关的编译标记汇总为一个结构体,并通过某个函数返回该结构体(这样做可以减少函数调用的次数)。</p>
<p>例如,用于在 <strong><code>hardware/interfaces/configstore/1.0/ISurfaceFlingerConfigs.hal</code></strong> 中将两个编译标记汇总到单个结构体的选项如下:</p>
<pre class="devsite-click-to-copy">
interface ISurfaceFlingerConfigs {
// other functions here
struct SyncConfigs {
OptionalInt64 vsyncEventPhaseoffsetNs;
OptionalInt64 presentTimeoffsetFromSyncNs;
};
getSyncConfigs() generates (SyncConfigs ret);
// other functions here
};
</pre>
<h2 id="alternatives">单个 HAL 函数的替代函数</h2>
<p>作为针对所有编译标记使用单个 HAL 函数的替代函数,HAL 接口还提供了 <code>getBoolean(string
key)</code><code>getInteger(string key)</code> 等简单函数。实际的 <code>key=value</code> 对会存储在单独的文件中,而 HAL 服务会通过读取/解析这些文件来提供值。</p>
<p>虽然这种方法很容易定义,但它不具备 HIDL 提供的优势(强制实施版本控制、便于记录、实现访问控制),因此不推荐使用。</p>
<p class="note"><strong>注意</strong>:在使用简单函数时,几乎不可能实现访问控制,因为 HAL 自身无法识别客户端。</p>
<h2 id="single-multiple">单个接口与多个接口</h2>
<p>面向配置项设计的 HAL 接口提供了以下两种选择:</p>
<ol>
<li>单个接口;涵盖所有配置项</li>
<li>多个接口;每个接口分别涵盖一组相关配置项</li>
</ol>
<p>单个接口更易于使用,但随着更多的配置项添加到单个文件中,单个接口可能会越来越难以维护。此外,由于访问控制不够精细,获得接口访问权限的进程可能会读取所有配置项(无法授予对部分配置项的访问权限)。此外,如果未授予访问权限,则无法读取任何配置项。</p>
<p>由于存在这些问题,Android 会针对一组相关配置项将多个接口与单个 HAL 接口搭配使用。例如,对 <code>surfaceflinger</code> 相关配置项使用 <code>ISurfaceflingerConfigs</code>,对蓝牙相关配置项使用 <code>IBluetoothConfigs</code> 等等。</p>
</body></html>