blob: 560c9f46b398179a1d5bf0834ad5bdc39b012402 [file] [log] [blame]
<html devsite><head>
<title>使用 Binder IPC</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 O 中对 Binder 驱动程序进行的更改、提供了有关使用 Binder IPC 的详细信息,并列出了必需的 SELinux 政策。</p>
<h2 id="binder-changes">对 Binder 驱动程序进行的更改</h2>
<p>从 Android O 开始,Android 框架和 HAL 现在使用 Binder 互相通信。由于这种通信方式极大地增加了 Binder 流量,因此 Android O 包含了几项改进,旨在确保 Binder IPC 的速度。集成最新版 Binder 驱动程序的 SoC 供应商和原始设备制造商 (OEM) 应该查看这些改进的列表、用于 3.18、4.4 和 4.9 版内核的相关 SHA,以及所需的用户空间更改。</p>
<h3 id="contexts">多个 Binder 域(上下文)</h3>
<em>在通用 3.10、3.18、4.4、4.9 版内核和上游中</em>
<p>
为了明确地拆分框架(与设备无关)和供应商(与具体设备相关)代码之间的 Binder 流量,Android O 引入了“Binder 上下文”这一概念。<em></em>每个 Binder 上下文都有自己的设备节点和上下文(服务)管理器。您只能通过上下文管理器所属的设备节点对其进行访问,并且在通过特定上下文传递 Binder 节点时,只能由另一个进程从相同的上下文访问上下文管理器,从而确保这些域完全互相隔离。如需使用方法的详细信息,请参阅 <a href="#vndbinder">vndbinder</a><a href="#vndservicemanager">vndservicemanager</a>
</p>
<h3 id="scatter">分散-集中</h3>
<em>在通用 3.10、3.18、4.4、4.9 版内核和上游中</em>
<p>在之前的 Android 版本中,Binder 调用中的每条数据都会被复制 3 次:
</p>
<ul>
<li>一次是在调用进程中将数据序列化为 <code><a href="https://developer.android.com/reference/android/os/Parcel.html">Parcel</a></code></li>
<li>一次是在内核驱动程序中将 <code>Parcel</code> 复制到目标进程</li>
<li>一次是在目标进程中对 <code>Parcel</code> 进行反序列化</li>
</ul>
<p>
Android O 使用<a href="https://en.wikipedia.org/wiki/Vectored_I/O">分散-集中优化</a>机制将复制次数从 3 次减少到了 1 次。数据保留其原始结构和内存布局,且 Binder 驱动程序会立即将数据复制到目标进程中,而不是先在 <code>Parcel</code> 中对数据进行序列化。在目标进程中,这些数据的结构和内存布局保持不变,并且,在无需再次复制的情况下即可读取这些数据。
</p>
<h3 id="locking">精细锁定</h3>
<em>在通用 3.18、4.4、4.9 版内核和上游中</em>
<p>在之前的 Android 版本中,Binder 驱动程序使用全局锁来防范对重要数据结构的并发访问。虽然采用全局锁时出现争用的可能性极低,但主要的问题是,如果低优先级线程获得该锁,然后实现了抢占,则会导致同样需要获得该锁的优先级较高的线程出现严重的延迟。这会导致平台卡顿。
</p>
<p>原先尝试解决此问题的方法是在保留全局锁的同时禁止抢占。但是,这更像是一种临时应对手段而非真正的解决方案,最终被上游拒绝并舍弃。后来尝试的解决方法侧重于提升锁定的精细程度,自 2017 年 1 月以来,Pixel 设备上一直采用的是更加精细的锁定。虽然这些更改大部分已公开,但未来版本中还会有一些重大的改进。
</p>
<p>在确定了精细锁定实现中的一些小问题后,我们使用不同的锁定架构设计了一种改进的解决方案,并在 3.18、4.4, 和 4.9 版通用分支中提交了相关更改。我们会继续在大量不同的设备上测试这种实现方式;由于目前看来这个方案不存在什么问题,因此建议搭载 Android O 的设备都使用这种实现方式。</p>
<p class="note"><strong>注意</strong>:我们强烈建议针对精细锁定安排充足的测试时间。
</p>
<h3 id="rt-priority">实时优先级继承</h3>
<em>在通用 3.18、4.4、4.9 版内核中(即将针对上游推出)</em>
<p>Binder 驱动程序一直支持 nice 优先级继承。随着 Android 中以实时优先级运行的进程日益增加,现在出现以下这种情形也属正常:如果实时线程进行 Binder 调用,则处理该调用的进程中的线程同样会以实时优先级运行。为了支持这些使用情景,Android O 现在在 Binder 驱动程序中实现了实时优先级继承。
</p>
<p>
除了事务级优先级继承之外,“节点优先级继承”允许节点(Binder 服务对象)指定对该节点执行调用操作所需的最低优先级。<em></em>之前版本的 Android 已经通过 nice 值支持节点优先级继承,但 Android O 增加了对实时调度政策节点继承的支持。
</p>
<p class="note"><strong>注意</strong>:Android 性能团队发现,实时优先级继承会对框架 Binder 域 (<code>/dev/binder</code>) 造成不必要的负面影响,因此已对该域<strong>停用</strong>实时优先级继承。
</p>
<h3 id="userspace">用户空间更改</h3>
<p>
Android O 纳入了在通用内核中使用现有 Binder 驱动程序所需的所有用户空间更改,但有一个例外:针对 <code>/dev/binder</code> 停用实时优先级继承的原始实现使用的是 <a href="https://android.googlesource.com/kernel/msm/+/868f6ee048c6ff51dbd92353dd5c68bea4419c78" class="external">ioctl</a>。由于后续开发将优先级继承的控制方法改为了更加精细的方法(根据 Binder 模式,而非上下文),因此,ioctl 不存于 Android 通用分支中,而是<a href="https://android-review.googlesource.com/#/c/421861/" class="external">提交到了我们的通用内核中</a>
</p>
<p>
此项更改的影响是,所有节点均默认停用实时优先级继承。<em></em>Android 性能团队发现,为 <code>hwbinder</code> 域中的所有节点启用实时优先级继承会有一定好处。要达到同样的效果,请在用户空间中择优实施<a href="https://android-review.googlesource.com/#/c/440359/" class="external">此更改</a>
</p>
<h3 id="shas">通用内核的 SHA</h3>
<p>要获取对 Binder 驱动程序所做的必要更改,请同步到下列 SHA(或更高版本):
</p>
<ul>
<li>通用 3.18 版<br />
cc8b90c121de ANDROID: Binder:请勿在还原时检查优先级权限。</li>
<li>通用 4.4 版<br />
76b376eac7a2 ANDROID: Binder:请勿在还原时检查优先级权限。</li>
<li>通用 4.9 版<br />
ecd972d4f9b5 ANDROID: Binder:请勿在还原时检查优先级权限。</li>
</ul>
<h2 id="ipc">使用 Binder IPC</h2>
<p>一直以来,供应商进程都使用 Binder 进程间通信 (IPC) 技术进行通信。在 Android O 中,<code>/dev/binder</code> 设备节点成为了框架进程的专属节点,这意味着供应商进程将无法再访问该节点。供应商进程可以访问 <code>/dev/hwbinder</code>,但必须将其 AIDL 接口转为使用 HIDL。对于想要继续在供应商进程之间使用 AIDL 接口的供应商,Android 会按以下方式支持 Binder IPC。</p>
<h3 id="vndbinder">vndbinder</h3>
<p>Android O 支持供应商服务使用新的 Binder 域,这可通过使用 <code>/dev/vndbinder</code>(而非 <code>/dev/binder</code>)进行访问。添加 <code>/dev/vndbinder</code> 后,Android 现在拥有以下 3 个 IPC 域:</p>
<table>
<tbody><tr>
<th>IPC 域</th>
<th>说明</th>
</tr>
<tr>
<td><code>/dev/binder</code></td>
<td>框架/应用进程之间的 IPC,使用 AIDL 接口</td>
</tr>
<tr>
<td><code>/dev/hwbinder</code></td>
<td>框架/供应商进程之间的 IPC,使用 HIDL 接口
<br />供应商进程之间的 IPC,使用 HIDL 接口</td>
</tr>
<tr>
<td><code>/dev/vndbinder</code></td>
<td>供应商/供应商进程之间的 IPC,使用 AIDL 接口</td>
</tr>
</tbody></table>
<p>为了显示 <code>/dev/vndbinder</code>,请确保内核配置项 <code>CONFIG_ANDROID_BINDER_DEVICES</code> 设为 <code>"binder,hwbinder,vndbinder"</code>(这是 Android 通用内核树的默认设置)。</p>
<p>通常,供应商进程不直接打开 Binder 驱动程序,而是链接到打开 Binder 驱动程序的 <code>libbinder</code> 用户空间库。为 <code>::android::ProcessState()</code> 添加方法可为 <code>libbinder</code> 选择 Binder 驱动程序。供应商进程应该在调用 <code>ProcessState,</code><code>IPCThreadState</code> 或发出任何普通 Binder 调用<strong>之前</strong>调用此方法。要使用该方法,请在供应商进程(客户端和服务器)的 <code>main()</code> 后放置以下调用:</p>
<pre class="prettyprint">ProcessState::initWithDriver("/dev/vndbinder");</pre>
<h3 id="vndservicemanager">vndservicemanager</h3>
<p>以前,Binder 服务通过 <code>servicemanager</code> 注册,其他进程可从中检索这些服务。在 Android O 中,<code>servicemanager</code> 现在专用于框架和应用进程,供应商进程无法再对其进行访问。</p>
<p>不过,供应商服务现在可以使用 <code>vndservicemanager</code>,这是一个使用 <code>/dev/vndbinder</code>(作为构建基础的源代码与框架 <code>servicemanager</code> 相同)而非 <code>/dev/binder</code><code>servicemanager</code> 的新实例。供应商进程无需更改即可与 <code>vndservicemanager</code> 通信;当供应商进程打开 /<code>dev/vndbinder</code> 时,服务查询会自动转至 <code>vndservicemanager</code></p>
<p><code>vndservicemanager</code> 二进制文件包含在 Android 的默认设备 Makefile 中。</p>
<h2 id="selinux">SELinux 政策</h2>
<p>想要使用 Binder 功能来相互通信的供应商进程需要满足以下要求:</p>
<ol>
<li>能够访问 <code>/dev/vndbinder</code></li>
<li>将 Binder <code>{transfer, call}</code> 接入 <code>vndservicemanager</code></li>
<li>针对想要通过供应商 Binder 接口调用供应商域 B 的任何供应商域 A 执行 <code>binder_call(A, B)</code> 操作。</li>
<li>有权在 <code>vndservicemanager</code> 中对服务执行 <code>{add, find}</code> 操作。</li>
</ol>
<p>要满足要求 1 和 2,请使用 <code>vndbinder_use()</code> 宏:</p>
<pre class="prettyprint">vndbinder_use(some_vendor_process_domain);</pre>
<p>要满足要求 3,需要通过 Binder 通信的供应商进程 A 和 B 的 <code>binder_call(A, B)</code> 可以保持不变,且不需要重命名。</p>
<p>要满足要求 4,您必须按照处理服务名称、服务标签和规则的方式进行更改。</p>
<p>有关 SELinux 的详细信息,请参阅 <a href="/security/selinux/">Android 中的安全增强型 Linux</a>。有关 Android 8.0 中 SELinux 的详细信息,请参阅 <a href="/security/selinux/images/SELinux_Treble.pdf">SELinux for Android 8.0</a></p>
<h3 id="names">服务名称</h3>
<p>以前,供应商进程在 <code>service_contexts</code> 文件中注册服务名称并添加用于访问该文件的相应规则。来自 <code>device/google/marlin/sepolicy</code><code>service_contexts</code> 文件示例:</p>
<pre class="devsite-click-to-copy">
AtCmdFwd u:object_r:atfwd_service:s0
cneservice u:object_r:cne_service:s0
qti.ims.connectionmanagerservice u:object_r:imscm_service:s0
rcs u:object_r:radio_service:s0
uce u:object_r:uce_service:s0
vendor.qcom.PeripheralManager u:object_r:per_mgr_service:s0
</pre>
<p>而在 Android O 中,<code>vndservicemanager</code> 会加载 <code>vndservice_contexts</code> 文件。迁移到 <code>vndservicemanager</code>(且已经在旧的 <code>service_contexts</code> 文件中)的供应商服务应该添加到新的 <code>vndservice_contexts</code> 文件中。</p>
<h3 id="labels">服务标签</h3>
<p>以前,服务标签(例如 <code>u:object_r:atfwd_service:s0</code>)在 <code>service.te</code> 文件中定义。例如:</p>
<pre class="prettyprint">type atfwd_service, service_manager_type;</pre>
<p>在 Android O 中,您必须将类型更改为 <code>vndservice_manager_type</code> 并将规则移动到 <code>vndservice.te</code> 文件中。例如:</p>
<pre class="prettyprint">type atfwd_service, vndservice_manager_type;</pre>
<h3 id="rules">Servicemanager 规则</h3>
<p>以前,规则会授予域访问权限,以向 <code>servicemanager</code> 添加服务或在其中查找服务。例如:</p>
<pre class="prettyprint">
allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;
</pre>
<p>在 Android O 中,这样的规则可继续存在并使用相同的类。例如:</p>
<pre class="prettyprint">
allow atfwd atfwd_service:service_manager find;
allow some_vendor_app atfwd_service:service_manager add;
</pre>
</body></html>