| <html devsite><head> |
| <title>HIDL 框架向后兼容性验证</title> |
| <meta name="project_path" value="/_project.yaml"/> |
| <meta name="book_path" value="/_book.yaml"/> |
| </head> |
| <body> |
| |
| <!-- |
| Copyright 2018 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><a href="/devices/architecture/#hidl">HIDL HAL</a> 可保证 Android 核心系统(也称为 system.img 或框架)向后兼容。虽然<a href="/compatibility/vts">供应商测试套件 (VTS)</a> 测试可确保 HAL 按预期运行(例如,针对所有 1.2 实现运行 1.1 HAL 测试),但仍需要进行框架测试,以确保提供受支持的 HAL(1.0、1.1 或 1.2)时该框架适用于该 HAL。</p> |
| |
| <p>要详细了解 HAL 接口定义语言 (HIDL),请参阅 <a href="/devices/architecture/hidl">HIDL</a>、<a href="/devices/architecture/hidl/versioning">HIDL 版本控制</a>和 <a href="/devices/architecture/vintf/fcm#hal-version-deprecation">HIDL HAL 弃用</a>。</p> |
| |
| <h2 id="about-HAL-upgrades">关于 HAL 升级</h2> |
| |
| <p>HAL 升级分为两类:主要和次要。<em></em><em></em>大多数系统仅包含一个 HAL 实现,但支持多个实现。例如:</p> |
| |
| <pre>android.hardware.teleport@1.0 # initial interface |
| android.hardware.teleport@1.1 # minor version upgrade |
| android.hardware.teleport@1.2 # another minor version upgrade |
| ... |
| android.hardware.teleport@2.0 # major version upgrade |
| ...</pre> |
| |
| <p>系统分区通常包含一个框架守护进程(如 <code>teleportd</code>),用于管理与特定 HAL 实现组进行的通信。作为一种替代方法,系统可能会包含一个用于实现便捷客户端行为的系统库(如 <code>android.hardware.configstore-utils</code>)。在上面的示例中,无论设备上安装了哪个版本的 HAL,<code>teleportd</code> 都必须能够正常运行。</p> |
| |
| <h2 id="google-maintained-versions">Google 维护的版本</h2> |
| |
| <p>如果存在主要版本升级(1.0、2.0、3.0 等),则至少必须有一台 Google 维护的设备来维护各主要版本的实现,直到该版本弃用为止。如果 Google 维护的所有设备均未搭载特定主要版本,则 Google 会继续维护该主要版本的旧实现。</p> |
| |
| <p>这种维护会增加一点额外的开销,因为创建新实现(如 2.0)时,旧实现(如 1.2)将保留且默认处于不使用的状态。</p> |
| |
| <h2 id="testing-minor-version-upgrades">测试次要版本升级</h2> |
| |
| <p>如要测试框架中次要版本的向后兼容性,则需要一种自动生成次要版本实现的方法。鉴于 Google 维护的版本存在一定限制,<code>hidl-gen</code> 只会(且只能)生成采用 1.(x+n) 实现并提供 1.x 实现的适配器;它无法根据 2.0 实现生成 1.0 实现(以主要版本的定义为准)。</p> |
| |
| <p>例如,要针对 1.2 实现运行 1.1 测试,则必须能够模拟具有 1.1 实现的情况。1.2 接口可自动用作 1.1 实现,但行为上存在一些细微差别(例如,框架会手动检查所属的具体版本或对自身调用 <code>castFrom</code>)。</p> |
| <p>基本做法如下所示:</p> |
| |
| <ol> |
| <li>在 Android 移动设备上安装 x.(y+n) 接口。</li> |
| |
| <li>安装并启用目标为 x.y 的适配器。</li> |
| |
| <li>测试设备,验证它能否按预期运行旧版次要版本。</li> |
| </ol> |
| |
| <p>这些适配器完全隐藏了如下事实:实现实际上由 1.2 接口提供支持,并且仅提供 1.1 接口(适配器采用 1.2 接口并让其看起来像 1.1 接口)。</p> |
| |
| <h3 id="example-workflow">工作流程示例</h3> |
| |
| <p>在此示例中,Android 设备运行 <code>android.hardware.foo@1.1::IFoo/default</code>。要确保客户端在 <code>android.hardware.foo@1.0::IFoo/default</code> 上正常运行,请执行以下操作:</p> |
| |
| <ol> |
| <li>在终端中,运行以下命令: |
| |
| <pre>$ PACKAGE=android.hidl.allocator@1.0-adapter |
| $ INTERFACE=IAllocator |
| $ INSTANCE=ashmem |
| $ THREAD_COUNT=1 # can see current thread use on `lshal -i -e` |
| $ m -j $PACKAGE |
| $ /data/nativetest64/$PACKAGE/$PACKAGE $INTERFACE $INSTANCE $THREAD_COUNT |
| Trying to adapt down android.hidl.allocator@1.0-adapter/default |
| Press any key to disassociate adapter.</pre> |
| </li> |
| |
| <li>使用 <code>adb shell stop</code>(或 <code>start</code>)重启客户端,或者仅终止相应进程。</li> |
| |
| <li>测试完成后,取消关联适配器。</li> |
| |
| <li>通过重启设备或重启客户端来恢复系统状态。</li> |
| </ol> |
| |
| <h3 id="additional-targets">其他目标</h3> |
| |
| <p>对于编译系统中使用 <code>hidl_interface</code> 指定的每个接口,<code>hidl-gen</code> 会自动为其适配器添加额外的编译目标。对于软件包 <code>a.b.c@x.y</code>,还需添加额外的 C++ 目标 <code>a.b.c@x.y-adapter</code>。</p> |
| |
| <aside class="note"><strong>注意</strong>:无需提供任何 Java 适配器,因为 C++ 适配器始终可用于封装 Java 服务。</aside> |
| |
| <p><code>a.b.c@x.y</code> 的适配器将一些实现 <code>a.b.c@x.(y+n)::ISomething/instance-name</code> 用作输入,并且必须注册 <code>a.b.c@x.y::ISomething/instance-name</code>,还必须取消注册 <code>y+n</code> 实现。</p> |
| |
| <p>假设有如下示例接口:</p> |
| |
| <pre>// IFoo.hal |
| package a.b.c@1.0; |
| interface IFoo { |
| doFoo(int32_t a) generates (int64_t b); |
| doSubInterface() generates (IFoo a); |
| };</pre> |
| |
| <p>由 <code>a.b.c@1.0-adapter</code> 提供的代码与以下示例类似:</p> |
| |
| <pre>// autogenerated code |
| // in namespace a::b::c::V1_0::IFoo |
| struct MockFoo { |
| // takes some subclass of V1_0. May be V1_1, V1_2, etc... |
| MockFoo(V1_0::IFoo impl) mImpl(impl) {} |
| |
| Return<int64_t> doFoo(int32_t a) { |
| return this->mImpl->doFoo(a); |
| } |
| |
| Return<V1_0::ICallback> doSubInterface() { |
| // getMockForBinder returns MockCallback instance |
| // that corresponds to a particular binder object |
| // It can't return a new object every time or |
| // clients using interfacesSame will have |
| // divergent behavior when using the mock. |
| auto _hidl_out = this->mImpl->doSubInterface(); |
| return getMockForBinder(_hidl_out); |
| } |
| };</pre> |
| |
| <p>数据值会精确地转发到自动生成的模拟类以及从中转出,子接口除外(它们会返回)。这些接口必须封装在相应的最新回调对象中。</p> |
| |
| </body></html> |