Docs: Changes to source.android.com
- 181204744 Devsite localized content from translation request b4bd44... by Android Partner Docs <[email protected]>
- 181204738 Devsite localized content from translation request 6e2e74... by Android Partner Docs <[email protected]>
- 181204731 Devsite localized content from translation request c6da36... by Android Partner Docs <[email protected]>
- 181184337 Adding nav for vndk build system support file (includes v... by Heidi von Markham <[email protected]>
- 181184012 Add details on enabling vndk for a partner codebase. by Heidi von Markham <[email protected]>
- 181181304 Drop path prefix "platform/" in human readable reference ... by Android Partner Docs <[email protected]>
- 180959465 Update public documentation around versions of OpenJDK bu... by Android Partner Docs <[email protected]>
- 180959038 Update home page with Jan 2018 bulletins by Danielle Roberts <[email protected]>
- 180944987 Update january 2018 bulletin with AOSP links by Danielle Roberts <[email protected]>
- 180939327 Devsite localized content from translation request 9d7ae6... by Android Partner Docs <[email protected]>
- 180939213 Devsite localized content from translation request 761984... by Android Partner Docs <[email protected]>
- 180939203 Devsite localized content from translation request 37ad64... by Android Partner Docs <[email protected]>
- 180813220 Devsite localized content from translation request 45f650... by Android Partner Docs <[email protected]>
- 180813011 Devsite localized content from translation request 7a3ee2... by Android Partner Docs <[email protected]>
- 180813003 Devsite localized content from translation request 52d1dd... by Android Partner Docs <[email protected]>
- 180721815 Update Jan 2018 bulletin with announcement about CVE-2017... by Danielle Roberts <[email protected]>
- 180718550 Update to January 2018 bulletin for coordinated disclosure by Danielle Roberts <[email protected]>
- 180689483 Devsite localized content from translation request 015eda... by Android Partner Docs <[email protected]>
- 180689471 Devsite localized content from translation request 86e026... by Android Partner Docs <[email protected]>
- 180688614 Added note about requirement to restart the audioserver by Android Partner Docs <[email protected]>
- 180681938 Add tags for January Security Release. by Android Partner Docs <[email protected]>
- 180580440 Publish Dec 2017 Pixel bulletins by Danielle Roberts <[email protected]>
- 180574446 Clarify OTA updates instructions in FBE docs by Danielle Roberts <[email protected]>
- 180566242 Update researcher acknowledgement for CVE-2017-13221 by Danielle Roberts <[email protected]>
- 180562297 January 2018 Pixel and Android Security bulletins by Danielle Roberts <[email protected]>
- 180562227 Devsite localized content from translation request a4ca37... by Android Partner Docs <[email protected]>
- 180562222 Devsite localized content from translation request f65459... by Android Partner Docs <[email protected]>
- 180561535 Devsite localized content from translation request 881cd3... by Android Partner Docs <[email protected]>
- 180561527 Devsite localized content from translation request 51b684... by Android Partner Docs <[email protected]>
- 180561524 Devsite localized content from translation request 226f2c... by Android Partner Docs <[email protected]>
- 180560907 Devsite localized content from translation request 9b462a... by Android Partner Docs <[email protected]>
- 180560904 Devsite localized content from translation request 1e3945... by Android Partner Docs <[email protected]>
- 180560895 Devsite localized content from translation request 60fa89... by Android Partner Docs <[email protected]>
- 180560177 Devsite localized content from translation request 9f6556... by Android Partner Docs <[email protected]>
- 180560173 Devsite localized content from translation request 37eb85... by Android Partner Docs <[email protected]>
- 180560169 Devsite localized content from translation request abf551... by Android Partner Docs <[email protected]>
- 180214623 Devsite localized content from translation request 69a1b1... by Android Partner Docs <[email protected]>
- 180214622 Devsite localized content from translation request abe464... by Android Partner Docs <[email protected]>
- 180214009 Devsite localized content from translation request 1c13f2... by Android Partner Docs <[email protected]>
- 180214006 Devsite localized content from translation request 9237e3... by Android Partner Docs <[email protected]>
- 180214003 Devsite localized content from translation request 1116f7... by Android Partner Docs <[email protected]>
- 179974666 Devsite localized content from translation request afb4de... by Android Partner Docs <[email protected]>
- 179932481 Devsite localized content from translation request 499773... by Android Partner Docs <[email protected]>
- 179932464 Devsite localized content from translation request 6bcb66... by Android Partner Docs <[email protected]>
- 179932462 Devsite localized content from translation request 6c13a3... by Android Partner Docs <[email protected]>
- 179931339 Correct out of place punctuation by Danielle Roberts <[email protected]>
- 179874281 Add libFuzzer docs to SAC. by Danielle Roberts <[email protected]>
- 179859323 Exclude compatibility/source from localization by Danielle Roberts <[email protected]>
- 179836094 Devsite localized content from translation request 3dae55... by Android Partner Docs <[email protected]>
- 179835757 Devsite localized content from translation request 76210b... by Android Partner Docs <[email protected]>
- 179835692 Devsite localized content from translation request eab645... by Android Partner Docs <[email protected]>
- 179835686 Devsite localized content from translation request 23e94d... by Android Partner Docs <[email protected]>
- 179778362 Devsite localized content from translation request 6406f2... by Android Partner Docs <[email protected]>
- 179688064 Devsite localized content from translation request 713535... by Android Partner Docs <[email protected]>
- 179622714 Add information about where to find OTA logs for both A/B... by Christina Nguyen <[email protected]>
- 179617573 Incorporate CDD source assets in google3 to allow buildin... by Clay Murphy <[email protected]>
PiperOrigin-RevId: 181204744
Change-Id: If0130be7bf5d5544f5b0ddda0977243b884b9943
diff --git a/zh-cn/devices/tech/admin/enterprise-telephony.html b/zh-cn/devices/tech/admin/enterprise-telephony.html
index 4945f03..a7e4ef6 100644
--- a/zh-cn/devices/tech/admin/enterprise-telephony.html
+++ b/zh-cn/devices/tech/admin/enterprise-telephony.html
@@ -38,7 +38,7 @@
</p>
<p>
-示例:
+例如:
</p><ul>
<li><strong>为工作联系人添加标记</strong>:请参阅 <code>packages/apps/ContactsCommon</code> f3eb5a207bfe0ff3b4ed2350ae5865ed8bc59798<em></em>
</li><li><strong>跨资料搜索</strong>:请参阅 <code>packages/apps/ContactsCommon</code> cd0b29ddbf3648e48f048196c62245d545bc6122<em></em></li>
@@ -52,14 +52,13 @@
<h3 id="cross-profile-contact-search">跨资料联系人搜索</h3>
<p>
-跨资料联系人搜索应该使用 Enterprise Contacts API(<code>ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI</code> 等)实现。该 API 可在 Android EMM 开发者网站上的 <a href="http://developer.android.com/preview/features/afw.html#contacts">EMM 开发者概览</a>中找到。
+跨资料联系人搜索应使用 Enterprise Contacts API(<code>ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI</code> 等)来实现。该 API 可在 Android EMM 开发者网站上的 <a href="http://developer.android.com/preview/features/afw.html#contacts">EMM 开发者概览</a>中找到。
</p>
<h3 id="work-profile-contact-badging">工作资料联系人标记</h3>
<p>
-工作资料联系人标记可通过检查 <code>ContactsContract.Directory.isEntepriseDirectoryId()</code>(如果可用)或 <code><a href="http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html#isEnterpriseContactId(long)">isEnterpriseContactId</a></code> 实现。
-.
+工作资料联系人标记可通过检查 <code>ContactsContract.Directory.isEntepriseDirectoryId()</code>(如果可用)或 <code><a href="http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html#isEnterpriseContactId(long)">isEnterpriseContactId</a></code> 来实现。
</p>
<h3 id="managed-profile-aware-connectionservice">可感知受管理资料的连接服务</h3>
diff --git a/zh-cn/devices/tech/admin/implement.html b/zh-cn/devices/tech/admin/implement.html
index c04559b..8278ab0 100644
--- a/zh-cn/devices/tech/admin/implement.html
+++ b/zh-cn/devices/tech/admin/implement.html
@@ -67,7 +67,7 @@
<h3 id="uses-feature">Uses-feature</h3>
<p>设备必须定义以下 <code>uses-feature</code>:</p>
-<pre>
+<pre class="devsite-click-to-copy">
android.software.managed_users
android.software.device_admin
</pre>
@@ -77,15 +77,19 @@
<h3 id="required_apps">仅限基本应用</h3>
<p>默认情况下,在配置托管设备时,只能启用资料正确运行所必需的应用。原始设备制造商 (OEM) 必须通过修改以下文件确保托管资料或设备具有所有必需的应用:</p>
-<pre>vendor_required_apps_managed_profile.xml
+<pre class="devsite-click-to-copy">
+vendor_required_apps_managed_profile.xml
vendor_required_apps_managed_device.xml
</pre>
<p>Nexus 设备的示例:</p>
-<p><code>packages/apps/ManagedProvisioning/res/values/vendor_required_apps_managed_device.xml</code></p>
+<pre class="devsite-click-to-copy">
+packages/apps/ManagedProvisioning/res/values/vendor_required_apps_managed_device.xml
+</pre>
-<pre><resources>
+<pre class="devsite-click-to-copy">
+<resources>
<!-- A list of apps to be retained on the managed device -->
<string-array name="vendor_required_apps_managed_device">
<item>com.android.vending</item> <!--Google Play -->
@@ -98,11 +102,11 @@
</resources>
</pre>
-<p><code>
+<pre class="devsite-click-to-copy">
packages/apps/ManagedProvisioning/res/values/vendor_required_apps_managed_profile.xml
-</code></p>
+</pre>
-<pre>
+<pre class="devsite-click-to-copy">
<resources>
<!-- A list of apps to be retained in the managed profile. This includes any Google experience apps required. -->
<string-array name="vendor_required_apps_managed_profile">
@@ -121,8 +125,12 @@
<p>NFC 设备必须在“开箱即用”的过程(即安装向导)中启用 NFC,并配置为接受托管配置 Intent:</p>
-<p><code>packages/apps/Nfc/res/values/provisioning.xml</code></p>
-<pre><bool name="enable_nfc_provisioning">true</bool>
+<pre class="devsite-click-to-copy">
+packages/apps/Nfc/res/values/provisioning.xml
+</pre>
+
+<pre class="devsite-click-to-copy">
+<bool name="enable_nfc_provisioning">true</bool>
<item>application/com.android.managedprovisioning</item>
</pre>
@@ -130,9 +138,10 @@
<p>支持“开箱即用”过程(即安装向导)的设备应实现设备所有者配置功能。当“开箱即用”过程开始时,应检查其他进程(如设备所有者配置)是否已经完成用户设置,如果已完成,则应触发返回主屏幕的 Intent 完成设置。配置应用会捕获此 Intent,然后将控制权交给新设置的设备所有者。</p>
-<p>要满足设置要求,请将以下代码添加到设备设置的主要活动中:</p>
+<p>要满足设置要求,请将以下代码添加到设备设置的主 Activity 中:</p>
-<pre>@Override
+<pre class="devsite-click-to-copy">
+@Override
protected void onStart() {
super.onStart();
diff --git a/zh-cn/devices/tech/admin/provision.html b/zh-cn/devices/tech/admin/provision.html
index a77e73d..8d1680d 100644
--- a/zh-cn/devices/tech/admin/provision.html
+++ b/zh-cn/devices/tech/admin/provision.html
@@ -30,7 +30,7 @@
<p>托管配置是一个框架式界面流程,用于确保用户充分了解设置设备所有者或受管理资料的含义。它旨在充当受管理资料的设置向导。</p>
-<p class="note"><strong>注意</strong>:只能为未配置的设备设置设备所有者。如果 <code>Settings.Secure.USER_SETUP_COMPLETE</code> 已设置,则设备被视为已配置,不能再设置设备所有者。</p>
+<p class="note"><strong>注意</strong>:只能为未配置的设备设置设备所有者。如果已设置 <code>Settings.Secure.USER_SETUP_COMPLETE</code>,则设备被视为已配置,不能再设置设备所有者。</p>
<p>如果启用设备的默认加密功能,则设备的管理配置流程会相当简单和快速。受管理配置组件会:</p>
@@ -55,15 +55,16 @@
<p>资料所有者配置假定设备的用户(而不是公司 IT 部门)监督设备管理。要启用资料所有者配置,您必须发送包含相应附加内容的 intent。例如,使用 TestDPC 应用(<a href="https://play.google.com/store/apps/details?id=com.afwsamples.testdpc&hl=zh-cn">从 Google Play 下载</a>或<a href="https://github.com/googlesamples/android-testdpc/">从 GitHub 构建</a>)。在设备上安装 TestDPC,从启动器启动该应用,然后按照应用说明进行操作。启动器抽屉式导航栏中出现带有标记的图标时,则表示配置完成。</p>
-<p>移动设备管理 (MDM) 应用通过发送包含操作的 intent 来触发受管理资料的创建:<a href="https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/admin/DevicePolicyManager.java">DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE</a>。以下是触发受管理资料创建并将 DeviceAdminSample 设为资料所有者的示例 intent:</p>
+<p>移动设备管理 (MDM) 应用通过发送包含以下操作的 intent 来触发受管理资料的创建:<a href="https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/admin/DevicePolicyManager.java">DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE</a>。以下是触发受管理资料创建并将 DeviceAdminSample 设为资料所有者的示例 intent:</p>
-<pre>adb shell am start -a android.app.action.PROVISION_MANAGED_PROFILE \
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb shell am start -a android.app.action.PROVISION_MANAGED_PROFILE \
-c android.intent.category.DEFAULT \
-e wifiSsid $(printf '%q' \"WifiSSID\") \
-e deviceAdminPackage "com.google.android.deviceadminsample" \
-e android.app.extra.deviceAdminPackageName $(printf '%q'
.DeviceAdminSample\$DeviceAdminSampleReceiver) \
- -e android.app.extra.DEFAULT_MANAGED_PROFILE_NAME "My Organisation"
+ -e android.app.extra.DEFAULT_MANAGED_PROFILE_NAME "My Organisation"</code>
</pre>
<h2 id="device_owner_provisioning_via_nfc">设备所有者配置</h2>
@@ -74,7 +75,7 @@
<p>典型的 NFC 包包括以下内容:</p>
-<pre>
+<pre class="devsite-click-to-copy">
EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LOCATION
EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
@@ -84,8 +85,10 @@
<p>设备必须将 NFC 配置为接受来自设置体验的托管配置 Mimetype:</p>
-<pre>/packages/apps/Nfc/res/values/provisioning.xml
-
+<pre class="devsite-click-to-copy">
+/packages/apps/Nfc/res/values/provisioning.xml
+</pre>
+<pre class="devsite-click-to-copy">
<bool name="enable_nfc_provisioning">true</bool>
<item>application/com.android.managedprovisioning</item>
</pre>
diff --git a/zh-cn/devices/tech/admin/testing-provision.html b/zh-cn/devices/tech/admin/testing-provision.html
index e7ac5b8..af8cd38 100644
--- a/zh-cn/devices/tech/admin/testing-provision.html
+++ b/zh-cn/devices/tech/admin/testing-provision.html
@@ -30,20 +30,22 @@
<h2 id="download_source">下载源代码</h2>
<p>按照<a href="/source/downloading.html">下载源代码</a>中的步骤下载 AfW 自动化测试框架源代码。AfW 自动化测试框架源代码位于 <code>./test/AfwTestHarness</code> 项目中。要下载的 AfW 自动化测试框架版本取决于分支名称(每个 Android 平台都有其单独的 AfW 自动化测试框架版本)。Android 7.0 的分支名称为 <code>afw-test-harness-nougat-dev</code>。要初始化该分支的 Repo 并下载源代码,请使用:</p>
-<pre>
-$ mkdir WORKING_DIRECTORY
-$ cd WORKING_DIRECTORY
-$ git config --global user.name "Your Name"
-$ git config --global user.email "[email protected]"
-$ repo init -u https://android.googlesource.com/platform/manifest -b afw-test-harness-nougat-dev
-$ repo sync -j24
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">mkdir WORKING_DIRECTORY</code>
+<code class="devsite-terminal">cd WORKING_DIRECTORY</code>
+<code class="devsite-terminal">git config --global user.name "Your Name"</code>
+<code class="devsite-terminal">git config --global user.email "[email protected]"</code>
+<code class="devsite-terminal">repo init -u https://android.googlesource.com/platform/manifest -b afw-test-harness-nougat-dev</code>
+<code class="devsite-terminal">repo sync -j24</code>
</pre>
<p>要查看不同版本的源代码,请用相应标签指定分支。可用的分支包括:</p>
<table>
<tbody><tr>
-<th>分支名称</th><th>支持的 Android 平台</th></tr>
+<th>分支名称</th>
+<th>支持的 Android 平台</th>
+</tr>
<tr>
<td>afw-test-harness-nougat-dev</td>
<td>Android 7.0</td>
@@ -67,9 +69,9 @@
<h3 id="view_studio">在 Android Studio 中查看</h3>
<p>要在 Android Studio 中查看和修改 AfW 源代码,请执行以下操作:</p>
<ol>
-<li>运行以下命令:<pre>
-$ make idegen
-$ development/tools/idegen/idegen.sh
+<li>运行以下命令:<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">make idegen</code>
+<code class="devsite-terminal">development/tools/idegen/idegen.sh</code>
</pre>
</li>
<li>在 Android Studio 中打开 <code>android.ipr</code>。</li>
@@ -80,12 +82,13 @@
<h2 id="config_harness">配置 AfW 自动化测试框架</h2>
<p>通过配置 <code>test/AfwTestHarness/afw-test.props</code>,您可以自定义自动化测试框架。要成功运行自动化测试框架,请按照以下步骤操作:</p>
<ol>
-<li>使用以下属性在 <code>afw-test.props</code> 中配置 WLAN 网络:<pre>wifi_ssid
+<li>使用以下属性在 <code>afw-test.props</code> 中配置 WLAN 网络:<pre class="devsite-click-to-copy">
+wifi_ssid
wifi_password (optional)
wifi_security_type (optional, available options are: NONE, WEP or WPA)
</pre>
</li>
-<li>从与 Test DPC(充当设备策略控制器)绑定的一个域中获取至少一个帐号。使用以下属性在 <code>afw-test.props</code> 中指定详细信息:<pre>
+<li>从与 Test DPC(充当设备策略控制器)绑定的一个域中获取至少一个帐号。使用以下属性在 <code>afw-test.props</code> 中指定详细信息:<pre class="devsite-click-to-copy">
work_account_username
work_account_password
</pre>
@@ -95,23 +98,29 @@
<h2 id="build_harness">编译 AfW 自动化测试框架</h2>
<p>使用以下命令初始化编译配置:</p>
-<pre>
-$ source build/envsetup.sh
-$ lunch
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">source build/envsetup.sh</code>
+<code class="devsite-terminal">lunch</code>
</pre>
<p>选择设备类型,然后按 <strong>Enter</strong> 键。</p>
<p>使用以下命令编译自动化测试框架:</p>
-<pre>$ make afw-test-harness -j32</pre>
+<pre class="devsite-terminal devsite-click-to-copy">
+make afw-test-harness -j32
+</pre>
<p>该操作将创建一个目录 (<code>out/host/linux-x86/afw-th/android-cts</code>),该目录包含运行自动化测试框架所需的全部二进制文件、配置文件和工具。该目录还会被压缩在一个文件 (<code>out/host/linux-x86/afw-th/android-afw-test-harness.zip</code>) 中以供分发。</p>
<h2 id="run_harness">运行 AfW 自动化测试框架</h2>
<p>请按照以下步骤运行 AfW 自动化测试框架:</p>
<ol>
-<li>使用以下命令,在您的编译环境中启动测试运行程序:<pre>$ afw-test-tradefed</pre>
+<li>使用以下命令,在您的编译环境中启动测试运行程序:<pre class="devsite-terminal devsite-click-to-copy">
+afw-test-tradefed
+</pre>
该操作将启动 <code>cts-tf</code> 控制台,并从 <code>out/host/linux-x86/afw-th/android-cts</code> 中加载测试计划、测试用例和 <code>afw-test.props</code>。</li>
-<li>使用以下命令,从 <code>android-afw-test-harness.zip</code> 的解压缩文件夹中启动测试运行程序:<pre>$ cts-tf > ./android‐cts/tools/afw-test‐tradefed</pre>
+<li>使用以下命令,从 <code>android-afw-test-harness.zip</code> 的解压缩文件夹中启动测试运行程序:<pre class="devsite-click-to-copy">
+cts-tf> ./android‐cts/tools/afw-test‐tradefed
+</pre>
该操作将从 <code>android-cts</code> 目录中加载测试计划、测试用例和 <code>afw-test.props</code>。
请确保 <code>./android‐cts/repository/testcases/afw-test.props</code> 拥有工作帐号和 WLAN 配置。</li>
@@ -120,10 +129,13 @@
<li><code><strong>afw-user-build</strong></code>。该计划在 user 版本中运行,但要求对测试设备进行正确设置,其中包括完成初始设置以及启用 USB 调试。</li>
</ul>
-<br />要运行测试计划 <code>afw-userdebug-build</code>,请使用:<pre>$ cts-tf > run cts --plan afw-userdebug-build</pre>要查看所有测试计划,请使用命令 <code>list plans</code>。要查看计划定义,请参阅 <code>out/host/linux-x86/afw-th/android-cts/repository/plans</code>。
+<br />要运行测试计划 <code>afw-userdebug-build</code>,请使用:<pre class="devsite-click-to-copy">
+cts-tf> run cts --plan afw-userdebug-build
+</pre>要查看所有测试计划,请使用命令 <code>list plans</code>。要查看计划定义,请参阅 <code>out/host/linux-x86/afw-th/android-cts/repository/plans</code>。
<br />
</li>
-<li>运行测试包。要运行单个测试包,请使用:<pre>$ cts-tf > run cts --package com.android.afwtest.NfcProvisioning
+<li>运行测试包。要运行单个测试包,请使用:<pre class="devsite-click-to-copy">
+cts-tf> run cts --package com.android.afwtest.NfcProvisioning
</pre>要查看所有测试包,请使用命令 <code>list packages</code>。要查看更多选项,请使用命令 <code>run cts --help</code>。</li>
</ol>
@@ -132,12 +144,19 @@
<ul>
<li>使用 <code>-l INFO</code> 或 <code>-l
-DEBUG</code> 标记显示更多信息。示例:<pre>$ cts-tf > run cts ‐‐plan afw-userdebug-build -l DEBUG</pre></li>
-
-<li>在具有 <code>-s</code> 标记的设备上运行自动化测试框架。示例:<pre>$ cts-tf > run cts ‐‐plan afw-userdebug-build -l DEBUG -s device_sn</pre>
+DEBUG</code> 标记显示更多信息。示例:<pre class="devsite-click-to-copy">
+cts-tf> run cts ‐‐plan afw-userdebug-build -l DEBUG
+</pre>
</li>
-<li>在具有 <code>--all-devices</code> 标记的所有连接设备上运行自动化测试框架。示例:<pre>$ cts-tf > run cts ‐‐plan afw-userdebug-build -l DEBUG --all-devices</pre>
+<li>在具有 <code>-s</code> 标记的设备上运行自动化测试框架。示例:<pre class="devsite-click-to-copy">
+cts-tf> run cts ‐‐plan afw-userdebug-build -l DEBUG -s device_sn
+</pre>
+</li>
+
+<li>在具有 <code>--all-devices</code> 标记的所有连接设备上运行自动化测试框架。示例:<pre class="devsite-click-to-copy">
+cts-tf> run cts ‐‐plan afw-userdebug-build -l DEBUG --all-devices
+</pre>
</li>
<li>使用 <code>list invocations</code> 或 <code>l i</code> 查看当前正在运行的执行程序。</li>
@@ -158,7 +177,8 @@
</li>
</ul>
</li>
-<li>测试包通过以下方式将 AfW 的配置流程自动化:访问界面页面,并将导航日志记录在每个页面的设备 logcat 文件中。示例:<code>afwtest.AutomationDriver:
+<li>测试包通过以下方式将 AfW 的配置流程自动化:访问界面页面,并将导航日志记录在每个页面的设备 logcat 文件中。
+示例:<code>afwtest.AutomationDriver:
Navigating:com.android.afwtest.uiautomator.pages.gms.AddAccountPage</code>
<br />用于测试包 <code>com.android.afwtest.NfcProvisioning</code> 的界面页面包括:<ul>
<li>
@@ -168,15 +188,20 @@
<li><code>com.android.afwtest.uiautomator.pages.LandingPage</code></li>
</ul>
</li>
-<li>如果测试在配置过程中失败,logcat 将包含类似于以下内容的错误消息:<pre>TestRunner: java.lang.RuntimeException: Failed to load page: com.android.afwtest.uiautomator.pages.packageinstaller.DeviceAccessPage
+<li>如果测试在配置过程中失败,logcat 将包含类似于以下内容的错误消息:<pre class="devsite-click-to-copy">
+TestRunner: java.lang.RuntimeException: Failed to load page: com.android.afwtest.uiautomator.pages.packageinstaller.DeviceAccessPage
</pre>这类错误通常是由之前的界面网页或加载失败的网页中的错误所导致,因此,请尝试在 logcat 中找到出现该错误之前的其他错误消息,然后按照配置流程手动重现该错误。</li>
<li>如果测试包运行失败:<ul>
-<li>系统会使用以下语法将屏幕截图保存到 <code>out/host/linux-x86/afw-th/android-cts/repository/logs/<em>start-time</em></code>:<code>screenshot-test_<em>test_class_full_name</em>_<em>test_case_name</em>-<em>random_number</em>.png</code>。该信息也会记录在主机日志中。</li>
-<li>错误报告会以 <code>bug-<em>test_class_full_name</em>_<em>test_case_name</em>-<em>random_number</em>.zip</code> 的形式保存到 <code>out/host/linux-x86/afw-th/android-cts/repository/logs/<em>start-time</em></code>。
+<li>系统会使用以下语法将屏幕截图保存到 <code>out/host/linux-x86/afw-th/android-cts/repository/logs/<em>start-time</em></code>:
+<code>screenshot-test_<em>test_class_full_name</em>_<em>test_case_name</em>-<em>random_number</em>.png</code>。
+该信息也会记录在主机日志中。</li>
+<li>错误报告会以下列形式保存到 <code>out/host/linux-x86/afw-th/android-cts/repository/logs/<em>start-time</em></code>:
+<code>bug-<em>test_class_full_name</em>_<em>test_case_name</em>-<em>random_number</em>.zip</code>。
</li>
</ul>
</li>
-<li>执行完所有测试包后,系统会进行屏幕截图,并以 <code>screenshot-<em>random_number</em>.png</code> 的形式将其保存到 <code>out/host/linux-x86/afw-th/android-cts/repository/logs/<em>start-time</em></code>。该信息也会记录在主机日志中。</li>
+<li>所有测试包均执行完毕后,屏幕截图会以 <code>screenshot-<em>random_number</em>.png</code> 的形式保存到 <code>out/host/linux-x86/afw-th/android-cts/repository/logs/<em>start-time</em></code>。
+该信息也会记录在主机日志中。</li>
</ul>
<h2 id="faq">常见问题解答</h2>
@@ -189,17 +214,18 @@
<p><strong>我是否可以在使用 userdebug 版本刷机的设备上运行测试计划 <code>afw-user-build</code>?</strong></p>
<p><em>可以,但我们建议您在 user 版本中运行该测试计划。</em></p>
-<p><strong>有时候我的测试会因为界面加载时间过长而失败。该怎么解决这个问题?</strong></p><em>在 <code>./android-cts/repository/testcases/afw-test.props</code> 中配置 <code>timeout_size</code> 设置。有效设置为:S、M、L、XL 和 XXL。</em><p></p>
+<p><strong>有时候我的测试会因为界面加载时间过长而失败。该怎么解决这个问题?</strong></p>
+<p><em>在 <code>./android-cts/repository/testcases/afw-test.props</code> 中配置 <code>timeout_size</code> 设置。有效设置为:S、M、L、XL 和 XXL。</em></p>
<p><strong>测试包 <code>com.android.afwtest.NfcProvisioning</code>(或 <code>SuwDoProvisioning</code>)无法在我的设备上成功运行,因为安装的初始设置(即设置向导)会在配置完成后显示自定义界面(例如“条款及条件”)。如何才能跳过该自定义界面?</strong></p>
<p><em>在配置过程结束后,系统应显示最小化界面。如果界面所包含的按钮包含有意义的文本或内容描述,且文本或内容描述含有以下任何字词,则自动化测试框架将自动跳过此类界面:“跳过”、“结束”、“完成”、“接受”、“同意”、“下一步”、“继续”、“前进”。或者,您可以在 <code>afw-test.props</code> 中定义一个按钮,以便将自动化测试框架配置为跳过您的界面。示例:</em></p>
-<pre>
+<pre class="devsite-click-to-copy">
oem_widgets=your_btn
your_btn.text=your_customized_text
your_btn.package=your_package
your_btn.action=click
</pre>
-<em></em><p><em>要定义多个微件,请使用逗号分隔。</em></p>
+<p><em>要定义多个微件,请使用逗号分隔。</em></p>
<p><strong>测试包 <code>com.android.afwtest.NfcProvisioning</code>(或 <code>SuwDoProvisioning</code>)运行失败,最后的界面屏幕显示“验证您的帐号”。为什么会发生这种情况?怎样才能恢复测试设备?
</strong></p>
diff --git a/zh-cn/devices/tech/admin/testing-setup.html b/zh-cn/devices/tech/admin/testing-setup.html
index 8565854..150b0a9 100644
--- a/zh-cn/devices/tech/admin/testing-setup.html
+++ b/zh-cn/devices/tech/admin/testing-setup.html
@@ -23,46 +23,44 @@
<p>为确保为受管理个人资料提供最基本的支持,原始设备制造商 (OEM) 设备必须包含以下基本元素:</p>
<ul>
- <li>个人资料所有者(如<a href="https://developer.android.com/training/enterprise/app-compatibility.html">确保与受管理个人资料的兼容性</a>中所述)</li>
- <li>设备所有者</li>
- </ul>
+<li>个人资料所有者(如<a href="https://developer.android.com/training/enterprise/app-compatibility.html" class="external">确保与受管理个人资料的兼容性</a>中所述)</li>
+<li>设备所有者</li>
+</ul>
-<p>要查看完整的要求列表,请参阅<a href="/devices/tech/admin/implement.html">实现设备管理</a>。</p>
-
-<p>要测试设备管理功能,设备所有者可以使用 TestDPC 应用(如下所述),也可以考虑直接与其他企业移动管理 (EMM) 提供商合作。</p>
+<p>要查看完整的要求列表,请参阅<a href="/devices/tech/admin/implement.html">实现设备管理</a>。要测试设备管理功能,设备所有者可以使用 TestDPC 应用(如下所述)。</p>
<h2 id="set_up_the_device_owner_for_testing">设置设备所有者以进行测试</h2>
<p>请按照以下说明设置设备所有者测试环境。</p>
<ol>
- <li>设置设备:<ol>
- <li style="list-style-type: lower-alpha">将目标设备恢复出厂设置。</li>
- <li style="list-style-type: lower-alpha">确保您未向设备添加任何用户帐号(例如,用于登录在线服务的用户帐号)。您可以依次转到“设置”->“帐号”进行确认。<em></em></li>
- </ol></li>
- <li>使用以下某种方法设置测试应用:<ul>
- <li><a href="https://play.google.com/store/apps/details?id=com.afwsamples.testdpc&hl=zh-cn">下载 TestDPC 应用</a>(可从 Google Play 下载)。</li>
- <li><a href="https://github.com/googlesamples/android-testdpc/">编译 TestDPC 应用</a>(可从 github.com 编译)。</li>
+<li>将目标设备恢复出厂设置。</li>
+<li>确保设备不含任何用户帐号(例如,用于登录在线服务的用户帐号)。要进行验证,请依次选择“设置”>“帐号”<em></em>。</li>
+<li>使用以下某种方法设置测试应用:<ul>
+ <li><a href="https://play.google.com/store/apps/details?id=com.afwsamples.testdpc&hl=zh-cn" class="external">下载 TestDPC 应用</a>(可从 Google Play 下载)。</li>
+ <li><a href="https://github.com/googlesamples/android-testdpc/" class="external">编译 TestDPC 应用</a>(可从 github.com 编译)。</li>
</ul>
- </li>
- <li>使用以下命令将 TestDPC 应用设置为设备所有者:<br />
- <pre>$ adb shell dpm set-device-owner "com.afwsamples.testdpc/.DeviceAdminReceiver"</pre>
- </li>
- <li>在设备上完成设备所有者设置(加密、选择 WLAN 等)</li>
+</li>
+<li>使用以下命令将 TestDPC 应用设置为设备所有者:
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell dpm set-device-owner "com.afwsamples.testdpc/.DeviceAdminReceiver"
+</pre>
+</li>
+<li>在设备上完成设备所有者设置(加密、选择 WLAN 等)。
+</li>
</ol>
<h2 id="verify_the_device_owner_was_correctly_setup">验证设备所有者设置</h2>
<p>要验证设备所有者是否已正确设置,请依次转到“设置”>“安全”>“设备管理器”,并确认 TestDPC 是否已在列表中。<em></em>验证它无法被停用(这表明它就是设备所有者)。</p>
<h2 id="automate">自动配置测试</h2>
-<p>要自动化企业配置进程的测试,请使用 Android for Work (AfW) 自动化测试框架。如需了解详情,请参阅<a href="/devices/tech/admin/testing-provision.html">测试设备配置</a>。</p>
+<p>要自动化企业配置测试过程,请使用 Android for Work (AfW) 自动化测试框架。如需了解详情,请参阅<a href="/devices/tech/admin/testing-provision.html">测试设备配置</a>。</p>
<h2 id="troubleshooting">错误报告和日志</h2>
-<p>在 Android 7.0 中,设备所有者 Device Policy Client (DPC) 可以获取受管理设备上企业进程的错误报告并查看日志。</p>
+<p>自 Android 7.0 起,设备所有者 Device Policy Client (DPC) 可以获取受管理设备上企业进程的错误报告并查看日志。</p>
-<p>要触发错误报告(即由 <code>adb
-bugreport</code> 收集的包含 dumpsys、dumpstate 和 logcat 数据的对应数据),请使用 <code>DevicePolicyController.requestBugReport</code>。收集错误报告后,系统会提示用户同意发送错误报告数据。结果将由 <code>DeviceAdminReceiver.onBugreport[Failed|Shared|SharingDeclined]</code> 接收。要详细了解错误报告内容,请参阅<a href="/source/read-bug-reports.html">读取错误报告</a>。
+<p>要触发错误报告(即由 <code>adb bugreport</code> 收集的包含 <code>dumpsys</code>、dumpstate 和 logcat 数据的对应数据),请使用 <code>DevicePolicyController.requestBugReport</code>。收集错误报告后,系统会提示用户同意发送错误报告数据。结果将由 <code>DeviceAdminReceiver.onBugreport[Failed|Shared|SharingDeclined]</code> 接收。要详细了解错误报告内容,请参阅<a href="/source/read-bug-reports.html">读取错误报告</a>。</p>
-</p><p>此外,设备所有者 DPC 还可以收集与用户在受管理设备上执行的操作相关的日志。所有报告 device_admin 的设备均必须进行企业进程日志记录,且通过新的日志安全缓冲区(仅供系统服务器读取)进行启用(也就是说,<code>adb logcat -b security</code> 无法读取该缓冲区)。ActivityManager 服务和 Keyguard 组件会将以下事件记录到安全缓冲区:</p>
+<p>此外,设备所有者 DPC 还可以收集与用户在受管理设备上执行的操作相关的日志。所有报告 device_admin 的设备均必须进行企业进程日志记录,且通过新的日志安全缓冲区(仅供系统服务器读取)进行启用(也就是说,<code>$ adb logcat -b security</code> 无法读取该缓冲区)。ActivityManager 服务和 Keyguard 组件会将以下事件记录到安全缓冲区:</p>
<ul>
<li>应用进程启动</li>
diff --git a/zh-cn/devices/tech/config/carrier.html b/zh-cn/devices/tech/config/carrier.html
index e690a84..75f0498 100644
--- a/zh-cn/devices/tech/config/carrier.html
+++ b/zh-cn/devices/tech/config/carrier.html
@@ -31,7 +31,7 @@
</li><li>VoLTE/即时通讯配置
</li></ul>
-<p class="note"><strong>注意</strong>:此应用必须使用证书进行签名,且所用证书的签名要与 SIM 卡上的签名一致。有关详情,请参阅<a href="#how_privilege_is_granted_to_a_carrier_app">如何向运营商应用授予权限</a>一节。</p>
+<p class="note"><strong>注意</strong>:此应用必须使用证书进行签名,且所用证书的签名要与 SIM 卡上的签名一致。有关详情,请参阅<a href="#how_privilege_is_granted_to_a_carrier_app">如何向运营商应用授予权限</a>部分。</p>
<p>返回值的选择完全取决于运营商应用,并且可以根据通过平台传递给应用的详细信息做出动态抉择。</p>
@@ -109,7 +109,7 @@
<h3 id="configuration_keys">配置密钥</h3>
-<p>密钥列表被定义为 <code><a href="http://developer.android.com/reference/android/telephony/CarrierConfigManager.html">android.telephony.CarrierConfigManager</a></code> 中公共 SDK 的一部分,并且不能在相同的 API 级别中更改。有关密钥的摘要,请参见下表。</p>
+<p>密钥列表被定义为 <code><a href="http://developer.android.com/reference/android/telephony/CarrierConfigManager.html">android.telephony. CarrierConfigManager</a></code> 中公共 SDK 的一部分,而且无法在相同的 API 级别中更改。有关密钥的摘要,请参见下表。</p>
<h2 id="how_to_build_your_application">如何构建应用</h2>
@@ -120,13 +120,13 @@
<h3 id="declare_a_class_that_overrides_android_service_carrier_carrierservice">声明一个替换 android.service.CarrierCarrierService 的类</h3>
<ol>
- <li>替换 <code>onLoadConfig</code> 以根据传递的 <code>service.carrier.CarrierIdentifier</code> 对象返回您希望提供的值
+ <li>替换 <code>onLoadConfig</code> 以根据传递的 <code>service.carrier.CarrierIdentifier</code> 对象返回您希望提供的值。
</li><li>添加逻辑以在运营商配置可能随时间发生改变的情况下调用 <code>notifyConfigChangedForSubId</code>(例如,当用户向其帐号添加额外服务时)
</li></ol>
<p>请参阅以下示例:</p>
-<pre>
+<pre class="prettyprint">
public class SampleCarrierConfigService extends CarrierService {
private static final String TAG = "SampleCarrierConfigService";
@@ -156,7 +156,7 @@
<p>请参阅以下示例:</p>
-<pre>
+<pre class="prettyprint">
<service android:name=".SampleCarrierConfigService"
android:label="@string/service_name"
android:permission="android.permission.BIND_CARRIER_SERVICES">
diff --git a/zh-cn/devices/tech/config/filesystem.html b/zh-cn/devices/tech/config/filesystem.html
index c47a4b0..5cf8fbf 100644
--- a/zh-cn/devices/tech/config/filesystem.html
+++ b/zh-cn/devices/tech/config/filesystem.html
@@ -20,59 +20,226 @@
limitations under the License.
-->
-<p>早期版本的 Android 使用不可扩展的系统配置文件,导致设备制造商无法通过添加具名二进制文件来指定所有权、访问模式或可执行权限的自主访问控制 (DAC)。设置这种限制的原因是为了支持 Linux 内核 3.14 及更高版本,这些版本通过 <code>CAP_SUSPEND_BLOCK</code> 功能启用唤醒锁定;要保持此唤醒锁定(从而在文件系统中设置此功能),需要合作伙伴提供的 GPS 守护进程。</p>
+<p>将文件系统对象和服务添加到编译环境中时,您通常需要分别为此类项目指定唯一 ID,称为 Android ID (AID)。目前,文件和服务等很多资源不需要一定使用 Android 定义的核心 AID;在很多情况下,您可以改为使用 OEM 定义的 AID。</p>
-<p>从 Android 6.0 开始,<code>fs_config</code> 和相关结构定义 (<code>system/core/include/private/android_filesystem_config.h</code>) 位于 <code>system/core/libcutils/fs_config.c</code> 中,可以由安装在 <code>/system/etc/fs_config_dirs</code> 和 <code>/system/etc/fs_config_files</code> 中的二进制文件进行更新或替换。为明确起见,Android 针对目录和文件采用单独的匹配和解析规则(可以使用其它全局表达式),并在两个不同的表格中处理目录和文件。<code>system/core/libcutils/fs_config.c</code> 中的结构定义不仅允许运行时读取目录和文件,而且主机在构建时也可以使用相同的文件来构建文件系统映像,比方说 <code>${OUT}/system/etc/fs_config_dirs</code> 和 <code>${OUT}/system/etc/fs_config_files</code>。</p>
+<p>在早期版本的 Android 中,对 AID 机制进行扩展时,是使用设备专属的 <code>android_filesystem_config.h</code> 文件来指定文件系统权能和/或自定义 OEM AID。但是,此机制不够直观,因为它不支持 OEM AID 使用好记的名称,而是要求您为用户和群组字段指定原始数字,这样一来,便无法将好记的名称与数字 AID 关联起来。</p>
-<h2 id="gen-files">生成替换文件</h2>
+<p>Android 8.0 及更高版本中采取了一种新的 AID 机制来扩展文件系统权能。这种新方法支持:</p>
+<ul>
+<li>配置文件可以有多个源位置(支持可扩展的编译环境配置)。</li>
+<li>在编译时对 OEM AID 值进行健全性检查。</li>
+<li>生成可视需要在源文件中使用的自定义 OEM AID 标头。</li>
+<li>将好记的名称与实际的 OEM AID 值相关联。支持为用户和群组指定非数字的字符串参数,即“foo”而不是“2901”。</li>
+</ul>
+
+<p>其他改进包括从 <code>system/core/include/private/android_filesystem_config.h</code> 中移除了 <code>android_ids[]</code> 数组。
+该数组现在作为完全自行生成的数组存在于 Bionic 中,并具有通过 <code>getpwnam()</code> 和 <code>getgrnam()</code> 提取数据的访问器。(此改进还有另一个作用,即使核心 AID 发生更改,生成的二进制文件也可保持稳定。)如需了解这种机制以及查看包含更多详情的 README 文件,请参阅 <code>build/make/tools/fs_config</code>。</p>
+
+<aside class="note"><strong>注意</strong>:虽然您仍可以使用<a href="#older">旧版 Android 中的文件系统替换方法</a>,但不能同时再使用新的 AID 机制。建议您尽可能使用新的机制。</aside>
+
+<h2 id="adding-android-ids-aids">添加 Android ID (AID)</h2>
+<p>Android 8.0 从 Android 开放源代码项目 (AOSP) 中移除了 <code>android_ids[]</code> 数组。所有适合 AID 的名称都改为在生成 Bionic <code>android_ids[]</code> 数组时从 <code>system/core/include/private/android_filesystem_config.h</code> 标头文件生成。这种机制会提取与 <code>AID_*</code> 匹配的所有 <code>define</code>,且 <strong>*</strong> 会变为小写名称。</p>
+
+<p>例如,在 <code>private/android_filesystem_config.h</code> 中:</p>
+
+<pre class="prettyprint">#define AID_SYSTEM 1000</pre>
+
+<p>会变为:</p>
+<ul>
+<li>好记的名称:system</li>
+<li>uid:1000</li>
+<li>gid:1000</li>
+</ul>
+
+<p>要添加新的 AOSP 核心 AID,只需将 <code>#define</code> 添加到 <code>android_filesystem_config.h</code> 标头文件中即可。AID 在编译环境中生成,并会提供给使用用户和群组参数的接口。这种机制会确认新的 AID 不在应用或 OEM 范围内;此外,它还会接受对此类范围的更改,并自动根据相应更改或新的 OEM 保留范围重新进行配置。</p>
+
+<h2 id="configuring-aids">配置 AID</h2>
+<p>
+要启用新的 AID 机制,请在 <code>BoardConfig.mk</code> 文件中设置 <code>TARGET_FS_CONFIG_GEN</code>。此变量含有配置文件列表,使您可以根据需要附加文件。</p>
+
+<aside class="caution"><strong>注意</strong>:请勿通过旧版 Android 中早期的 <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> 方法使用 <code>TARGET_FS_CONFIG_GEN</code>!否则,您会收到错误提示。</aside>
+
+<p>按照惯例,配置文件使用名称 <code>config.fs</code>,但在实践中,您可以使用任何名称。<code>config.fs</code> 文件采用 <a href="https://docs.python.org/2/library/configparser.html" class="external">Python ConfigParser ini 格式</a>,并包含大写部分(用于配置文件系统权能)和 AID 部分(用于配置 OEM 专属 AID)。
+</p>
+
+<h3 id="configuring-the-caps-section">配置大写部分</h3>
+<p>大写部分支持在编译环境中对文件系统对象设置<a href="http://man7.org/linux/man-pages/man7/capabilities.7.html" class="external">文件系统权能</a>(文件系统本身也必须支持此功能)。</p>
+
+<p>由于在 Android 中以 Root 身份运行稳定的服务会导致<a href="/compatibility/cts/index.html">兼容性测试套件 (CTS)</a> 失败,因此在之前有关在运行进程或服务时保留权能的要求中,您需要先设置权能,然后使用 <code>setuid</code>/<code>setgid</code> 设置适当的 AID 以运行程或服务。借助大写部分,您可以跳过这些要求,让内核为您代劳。当控制权交给 <code>main()</code> 时,您的进程就已拥有所需的权能,因此您的服务可以使用非 Root 用户和群组(这是启动特权服务的首选方式)。</p>
+
+<p>大写部分使用以下语法:</p>
+<table>
+ <tbody><tr>
+ <th>部分</th>
+ <th>值</th>
+ <th>定义</th>
+ </tr>
+ <tr>
+ <td><code>[path]</code></td>
+ <td></td>
+ <td>要配置的文件系统路径。以 / 结尾的路径被视为目录,否则,将被视为文件。
+ <br /><br />在不同文件中使用同一 <code>[path]</code> 指定多个部分的做法是错误的。在 Python 3.2 之前的版本中,同一文件中包含的某些部分可替换它之前的部分;而在 Python 3.2 中,系统设置了严格模式。</td>
+ </tr>
+ <tr>
+ <td><code>mode</code></td>
+ <td>八进制文件模式</td>
+ <td>至少为 3 位数的有效八进制文件模式。如果指定 3,则会附上前缀 0,否则系统会按原样使用模式。</td>
+ </tr>
+ <tr>
+ <td><code>user</code></td>
+ <td>AID_<user></td>
+ <td>有效 AID 的 C 样式的 <code>define</code> 或好记的名称(例如 <code>AID_RADIO</code> 和 <code>radio</code> 皆可)。要指定自定义 AID,请参阅<a href="#configuring-the-aid-section">配置 AID 部分</a>。</td>
+ </tr>
+ <tr>
+ <td><code>group</code></td>
+ <td>AID_<group></td>
+ <td>和用户一样。</td>
+ </tr>
+ <tr>
+ <td><code>caps</code></td>
+ <td>cap*</td>
+ <td><code>system/core/include/private/android_filesystem_capability.h</code> 中所声明的名称,不含前导 <code>CAP_</code>。允许大小写混用。大写也可以是原始值:<ul>
+ <li>binary (0b0101)</li>
+ <li>octal (0455)</li>
+ <li>int (42)</li>
+ <li>hex (0xFF)</li>
+ </ul>
+ 可以使用空格隔开多个大写字母。</td>
+ </tr>
+</tbody></table>
+
+<p>有关使用示例,请参阅<a href="#using-file-system-capabilities">使用文件系统权能</a>。</p>
+
+<h3 id="configuring-the-aid-section">配置 AID 部分</h3>
+<p>AID 部分包含 OEM 专属 AID,并使用以下语法:</p>
+
+<table>
+ <tbody><tr>
+ <th>部分</th>
+ <th>值</th>
+ <th>定义</th>
+ </tr>
+ <tr>
+ <td><code>[AID_<name>]</code></td>
+ <td></td>
+ <td><code><name></code> 可以包含大写字母、数字和下划线字符。小写版本作为好记的名称使用。生成的用于代码收录的标头文件使用确切的 <code>AID_<name></code>。
+ <br /><br />使用同一 <code>AID_<name></code> 指定多个部分(不区分大小写,限制条件与 <code>[path]</code> 相同)是错误的做法。</td>
+ </tr>
+ <tr>
+ <td><code>value</code></td>
+ <td><number></td>
+ <td>有效的 C 样式的数字字符串(十六进制、八进制、二进制和十进制)。
+ <br /><br />使用同一值选项指定多个部分<strong>或</strong>指定超出收录的 OEM 范围(在 <code>system/core/include/private/android_filesystem_config.h</code> 中指定)的值,属于错误的做法:<ul>
+ <li>AID_OEM_RESERVED_START(2900) - AID_OEM_RESERVED_END(2999)</li>
+ <li>AID_OEM_RESERVED_2_START(5000) - AID_OEM_RESERVED_2_END(5999)</li>
+ </ul>
+ </td>
+ </tr>
+</tbody></table>
+
+<p>有关使用示例,请参阅<a href="#defining-an-oem-specific-aid">定义 OEM 专属 AID</a> 和<a href="#using-an-oem-specific-aid">使用 OEM 专属 AID</a>。</p>
+
+<h2 id="usage-examples">用法示例</h2>
+<p>以下示例详细介绍了如何定义和使用 OEM 专属 AID,以及如何启用文件系统权能。</p>
+
+<h3 id="defining-an-oem-specific-aid">定义 OEM 专属 AID</h3>
+<p>要定义 OEM 专属 AID,请创建一个 <code>config.fs</code> 文件并设置 AID 值。例如,在 <code>device/x/y/config.fs</code> 中设置以下内容:</p>
+
+<pre class="prettyprint">
+[AID_FOO]
+value: 2900
+</pre>
+
+<p>创建好文件后,设置 <code>TARGET_FS_CONFIG_GEN</code> 变量并在 <code>BoardConfig.mk</code> 指向它。例如,在 <code>device/x/y/BoardConfig.mk</code> 中设置以下内容:</p>
+
+<pre class="prettyprint">TARGET_FS_CONFIG_GEN += device/x/y/config.fs</pre>
+
+<p>总的来说,现在系统已经可以在新编译环境中使用您的自定义 AID 了。
+</p>
+
+<h3 id="using-an-oem-specific-aid">使用 OEM 专属 AID</h3>
+<p>要通过 C 或 C++ 代码访问 AID 的 <code>#define</code> 值,请使用自动生成的标头文件,方法是:将其添加到模块的 <code>Android.mk</code> 中并纳入空的仿库。例如,在 <code>Android.mk</code> 中添加以下内容:</p>
+
+<pre class="prettyprint"> LOCAL_STATIC_LIBRARIES := liboemaids</pre>
+<p>在您的 C 代码中,<code>#include "generated_oem_aid.h"</code> 并开始使用所声明的标识符。例如,在 <code>my_file.c</code> 中添加以下内容:</p>
+
+<pre class="prettyprint">
+#include "generated_oem_aid.h"
+
+…
+
+If (ipc->uid == AID_FOO) {
+ // Do something
+...
+</pre>
+
+<p>在 Android 8.0 中,您必须配合 <code>oem_####</code> 使用 <code>getpwnam</code> 和类似函数,在通过 <code>getpwnam</code>(如 init 脚本)处理查询时也是如此。例如,在 <code>some/init.rc</code> 中使用以下内容:</p>
+
+<pre class="prettyprint">
+service foo /vendor/bin/foo_service
+ user: oem_2900
+ group: oem_2900
+</pre>
+
+<h3 id="using-file-system-capabilities">使用文件系统权能</h3>
+<p>要启用文件系统权能,请在 <code>config.fs</code> 文件中创建一个大写部分。例如,在 <code>device/x/y/config.fs</code> 中添加以下部分:</p>
+
+<pre class="prettyprint">
+[system/bin/foo_service]
+mode: 0555
+user: AID_FOO
+group: AID_SYSTEM
+caps: SYS_ADMIN | SYS_NICE
+</pre>
+
+<aside class="note"><strong>注意</strong>:此处也可以使用好记的名称 <code>foo</code> 和 <code>system</code>。</aside>
+
+<p>创建好文件后,设置 <code>TARGET_FS_CONFIG_GEN</code> 并在 <code>BoardConfig.mk</code> 中指向它。例如,在 <code>device/x/y/BoardConfig.mk</code> 中设置以下内容:</p>
+
+<pre class="prettyprint">TARGET_FS_CONFIG_GEN += device/x/y/config.fs</pre>
+
+<p>当执行服务 <code>foo</code> 时,它会先使用权能 <code>CAP_SYS_ADMIN</code> 和 <code>CAP_SYS_NICE</code>,而不使用 <code>setuid</code> 和 <code>setgid</code> 调用。此外,<code>foo</code> 服务的 SELinux 策略也不再需要 <code>setuid</code> 和 <code>setgid</code>,因此,可以从 <code>foo</code> 的 SELinux 策略中移除这些权能。</p>
+
+<h2 id="older">配置替换(Android 6.x 到 7.x 版本)</h2>
+
+<p>Android 6.0 将 <code>fs_config</code> 和关联的结构定义 (<code>system/core/include/private/android_filesystem_config.h</code>) 转移到了 <code>system/core/libcutils/fs_config.c</code>。在此处,可使用安装在 <code>/system/etc/fs_config_dirs</code> 和 <code>/system/etc/fs_config_files</code> 中的二进制文件来更新或替换它们。针对目录和文件分别采用单独的匹配和解析规则(可能会使用其他全局表达式),这样一来,Android 就能够在两个不同的表中处理目录和文件。<code>system/core/libcutils/fs_config.c</code> 中的结构定义不仅可让系统在运行时读取目录和文件,而且主机在编译时也可以使用相同的文件来构建文件系统映像,比方说 <code>${OUT}/system/etc/fs_config_dirs</code> 和 <code>${OUT}/system/etc/fs_config_files</code>。</p>
+
+<p>虽然扩展文件系统时采用的替换方法已被 Android 8.0 中推出的模块化配置系统所取代,但如果需要,您仍可以使用原来的方法。以下部分将详细介绍如何生成和纳入替换文件以及如何配置文件系统。</p>
+
+<h3 id="older-generate">生成替换文件</h3>
<p>您可以使用 <code>build/tools/fs_config</code> 中的 <code>fs_config_generate</code> 工具生成相应的二进制文件 <code>/system/etc/fs_config_dirs</code> 和 <code>/system/etc/fs_config_files</code>。该工具使用 <code>libcutils</code> 库函数 (<code>fs_config_generate()</code>) 管理放入缓冲区内的 DAC 需求,并为头文件定义规则来规定 DAC 规则的用法。</p>
-<p>要使用此工具,请在 <code>device/<em>vendor</em>/<em>device</em>/android_filesystem_config.h</code> 中创建头文件作为替换。该文件必须使用 <code>system/core/include/private/android_filesystem_config.h</code> 中定义的 <code>structure fs_path_config</code> 格式,并对目录和文件符号进行以下结构初始化:</p>
+<p>要使用该工具,请在 <code>device/<em>vendor</em>/<em>device</em>/android_filesystem_config.h</code> 中创建头文件以用作替换文件。该文件必须使用 <code>system/core/include/private/android_filesystem_config.h</code> 中定义的 <code>structure fs_path_config</code> 格式,并对目录和文件符号进行以下结构初始化:</p>
<ul>
<li>对于目录,请使用 <code>android<strong>_device</strong>_dirs[]</code>。</li>
<li>对于文件,请使用 <code>android<strong>_device</strong>_files[]</code>。</li>
</ul>
-<p>在不使用 <code>android_device_dirs[]</code> 和 <code>android_device_files[]</code> 时,您可以定义 <code>NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS</code> 和 <code>NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES</code>(请参见下面的<a href="#example">示例</a>)。</p>
+<p>在不使用 <code>android_device_dirs[]</code> 和 <code>android_device_files[]</code> 时,您可以定义 <code>NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_DIRS</code> 和 <code>NO_ANDROID_FILESYSTEM_CONFIG_DEVICE_FILES</code>(请参阅下面的<a href="#older-example">示例</a>)。您还可以使用板级配置中的 <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> 指定强制基本名称为 <code>android_filesystem_config.h</code> 的替换文件。</p>
-<p>您还可以使用单板配置中的 <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> 指定强制基本名称为 <code>android_filesystem_config.h</code> 的替换文件。
+<h3 id="older-include">包含替换文件</h3>
+<p>要包含文件,请确保 <code>PRODUCT_PACKAGES</code> 包含 <code>fs_config_dirs</code> 和/或 <code>fs_config_files</code>,以便它可以分别将其安装到 <code>/system/etc/fs_config_dirs</code> 和 <code>/system/etc/fs_config_files</code> 中。编译系统会在 <code>BoardConfig.mk</code> 所在的 <code>$(TARGET_DEVICE_DIR)</code> 中搜索自定义 <code>android_filesystem_config.h</code>。如果此文件位于其他位置,请设置板级配置变量 <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> 来指向该位置。</p>
-</p><h2 id="include-files">包含的文件</h2>
-
-<p><code>PRODUCT_PACKAGES</code> 必须包含 <code>fs_config_dirs</code> 和/或 <code>fs_config_files</code>,才能分别将它们安装到 <code>/system/etc/fs_config_dirs</code> 和 <code>/system/etc/fs_config_files</code>。</p>
-
-<p>构建系统会在 <code>BoardConfig.mk</code> 所在的 <code>$(TARGET_DEVICE_DIR)</code> 中搜索自定义 <code>android_filesystem_config.h</code>。如果此文件位于其他位置,请设置单板配置变量 <code>TARGET_ANDROID_FILESYSTEM_CONFIG_H</code> 来指向该位置。</p>
-
-<h2 id="configuring">配置</h2>
-<p>要在 Android 6.0 及更高版本中配置文件系统,请按以下步骤操作:</p>
+<h3 id="older-configure">配置文件系统</h3>
+<p>要在 Android 6.0 及更高版本中配置文件系统,请执行以下操作:</p>
<ol>
<li>创建 <code>$(TARGET_DEVICE_DIR)/android_filesystem_config.h</code> 文件。</li>
-<li>将 <code>fs_config_dirs</code> 和/或 <code>fs_config_files</code> 添加到单板配置文件(例如 <code>$(TARGET_DEVICE_DIR)/device.mk</code>)中的 <code>PRODUCT_PACKAGES </code>。</li>
+<li>将 <code>fs_config_dirs</code> 和/或 <code>fs_config_files</code> 添加到板级配置文件(例如 <code>$(TARGET_DEVICE_DIR)/device.mk</code>)中的 <code>PRODUCT_PACKAGES </code>。</li>
</ol>
-<h2 id="migration-concerns">迁移问题</h2>
-<p>将系统配置从 Android 5.0 及更早版本中迁出会造成干扰。在规划此类迁移时,请注意以下事项:</p>
-<ul>
-<li>Android 6.0 会移除部分头文件、结构和内嵌定义。</li>
-<li>Android 6.0 需要引用 <code>libcutils</code>,而不是直接从 <code>system/core/include/private/android_filesystem_config.h</code> 运行。依赖于 <code>system/code/include/private_filesystem_config.h</code> 的文件/目录结构或者 <code>fs_config</code> 的设备制造商私有可执行文件必须添加 <code>libcutils</code> 库依赖关系。</li>
-<li>Android 6.0 需要使用 <code>system/core/include/private/android_filesystem_config.h</code> 的设备制造商私有分支副本,该副本应包含有关现有目标的附加内容,以便移至 <code>device/<em>vendor</em>/<em>device</em>/android_filesystem_config.h</code>。
-</li>
-<li>由于 Android 保留将 SELinux 强制访问控制 (MAC) 应用于目标系统中配置文件的权利,因此包含使用 <code>fs_config()</code> 的自定义目标可执行文件的实现必须确保具有访问权限。</li>
-</ul>
+<h3 id="older-example">替换示例</h3>
-<h2 id="example">示例</h2>
-
-<p>此示例展示了用于替换 <code>system/bin/glgps</code> 守护进程以在 <code>device/<em>vendor</em>/<em>device</em></code> 目录中添加唤醒锁定支持的补丁。请注意以下几点:</p>
+<p>此示例展示了用于替换 <code>system/bin/glgps</code> 守护进程以在 <code>device/<em>vendor</em>/<em>device</em></code> 目录中添加唤醒锁定支持的补丁程序。请注意以下几点:</p>
<ul>
-<li>每个结构条目都包含模式、uid、gid、功能和名称。
+<li>每个结构条目都包含模式、uid、gid、权能和名称。
已自动包含 <code>system/core/include/private/android_filesystem_config.h</code> 来提供清单 #defines(<code>AID_ROOT</code>、<code>AID_SHELL</code>、<code>CAP_BLOCK_SUSPEND</code>)。</li>
-<li><code>android_device_files[]</code> 区段包含在未指定时禁止访问 <code>system/etc/fs_config_dirs</code> 的操作,其作用是在缺少目录替换内容时提供额外 DAC 保护。但此保护的强度较弱;如果有人拥有超过 <code>/system</code> 的控制权,那么他通常可以执行任何操作。</li>
+<li><code>android_device_files[]</code> 区段包含在未指定时禁止访问 <code>system/etc/fs_config_dirs</code> 的操作,其作用是在缺少目录替换内容时提供额外 DAC 保护。但此保护的强度较弱;如果有人拥有对 <code>/system</code> 的控制权,那么他通常可以执行任何操作。</li>
</ul>
-<pre>
+<pre class="devsite-click-to-copy">
diff --git a/android_filesystem_config.h b/android_filesystem_config.h
new file mode 100644
index 0000000..874195f
@@ -133,4 +300,15 @@
ifeq ($(USE_SVELTE_KERNEL), true)
</pre>
+<h3 id="older-migration">从早期版本迁移文件系统</h3>
+<p>当从 Android 5.x 及更低版本迁移文件系统时,请注意以下事项:</p>
+<ul>
+<li>Android 6.x 移除了部分头文件、结构和内嵌定义。</li>
+<li>Android 6.x 需要引用 <code>libcutils</code>,而不是直接从 <code>system/core/include/private/android_filesystem_config.h</code> 运行。依赖于 <code>system/code/include/private_filesystem_config.h</code> 的文件/目录结构或者 <code>fs_config</code> 的设备制造商私有可执行文件必须添加 <code>libcutils</code> 库依赖关系。</li>
+<li>Android 6.x 需要 <code>system/core/include/private/android_filesystem_config.h</code> 的设备制造商专有分支副本,该副本应包含有关现有目标的附加内容,以便移至 <code>device/<em>vendor</em>/<em>device</em>/android_filesystem_config.h</code>。
+</li>
+<li>由于 Android 保留将 SELinux 强制访问控制 (MAC) 应用于目标系统中配置文件的权利,因此包含使用 <code>fs_config()</code> 的自定义目标可执行文件的实现必须确保具有访问权限。
+</li>
+</ul>
+
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/config/perms-whitelist.html b/zh-cn/devices/tech/config/perms-whitelist.html
new file mode 100644
index 0000000..19bda94
--- /dev/null
+++ b/zh-cn/devices/tech/config/perms-whitelist.html
@@ -0,0 +1,150 @@
+<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>
+过去,设备实现人员几乎无法控制可以向特权应用授予哪些签名|特许权限。
+特权应用是位于系统映像上 <code>/system/priv-app</code> 目录下的系统应用。
+ </p>
+
+ <p>
+从 Android 8.0 开始,所有特权应用均必须显式加入到 <code>/etc/permissions</code> 目录下的系统配置 XML 文件的白名单中。
+如果不这样做,则设备可以启动,但设备实现将无法通过 CTS。</p>
+
+ <h2 id="adding-the-whitelists">添加白名单</h2>
+
+ <p>
+
+应用的权限白名单可列在位于 <code>frameworks/base/etc/permissions</code> 目录下的单个或多个 XML 文件中,如下所示:
+ </p>
+
+ <ul>
+ <li><code>/etc/permissions/privapp-permissions-<OEM_NAME>.xml</code>
+ </li><li><code>/etc/permissions/privapp-permissions-<DEVICE_NAME>.xml</code>。
+ </li></ul>
+
+ <p>
+对于如何组织内容,没有任何严格的规则,只要将 <code>/system/priv-app</code> 下的所有应用均列入白名单,设备实现人员就可以自行决定如何组织内容。例如,Google 会针对由 Google 开发的所有特权应用提供一个白名单。
+ </p>
+
+ <p>
+建议使用以下组织方式:
+ </p>
+
+ <ul>
+ <li>对于已包含在 AOSP 树中的应用,将其权限列在以下文件中:<code>/etc/permissions/privapp-permissions-platform.xml</code>
+ </li><li>对于 Google 应用,将其权限列在以下文件中:<code>/etc/permissions/privapp-permissions-google.xml </code>
+ </li><li>对于其他应用,使用以下格式的文件:<code>
+ /etc/permissions/privapp-permissions-<device_name>.xml</code></li>
+ </ul>
+
+ <h3 id="whitelist-generation-tool">白名单生成工具</h3>
+
+ <p>
+可使用 AOSP 中提供的命令行工具在以下位置自动生成系统映像上提供的针对所有应用的白名单:
+ </p>
+
+ <pre class="prettyprint">development/tools/privapp_permissions/privapp_permissions.py
+ </pre>
+
+ <p>
+要生成特定于设备的 <code>privapp-permissions.xml</code> 的初始版本,请完成以下步骤:
+
+ </p>
+ <ol>
+ <li>编译系统映像,如下所示:<br />
+ <pre>$ . build/envsetup.sh
+$ lunch product_name
+$ make -j</pre>
+ </li>
+
+ <li>运行以下工具以生成一个 <code>privapp-permissions.xml
+ </code> 文件,该文件会列出需要列入白名单的所有签名|特许权限。<br />
+ <pre>$ development/tools/privapp_permissions/privapp_permissions.py</pre><br />
+
+此工具会打印可在 <code>/etc/permissions</code> 下用作单个文件或拆分为多个文件的 XML 内容。<br /><br />
+如果设备已在 <code>/etc/permissions</code> 目录下包含白名单,则该工具将打印出差异内容,也就是说只打印缺少的需要列入白名单的签名|特许权限。这对审核也很有用,当添加新版本的应用时,该工具将检测所需的其他权限。
+ </li>
+ <li>将生成的文件复制到 <code>/etc/permissions</code> 目录下,系统将在这里读取该文件(在启动过程中)。</li>
+ </ol>
+ <h3 id="whitelist-format">白名单格式</h3>
+ <ul>
+ <li>由于实现已在 AOSP 中,因此只需进行自定义即可。
+ </li><li>AOSP 树中包含的应用的权限已在 <code>/etc/permissions/privapp-permissions-platform.xml</code> 下列入白名单
+ </li>
+ </ul>
+
+ <pre class="prettyprint"><!--
+ This XML file declares which signature|privileged permissions should be granted to privileged
+ applications that come with the platform
+ -->
+ <permissions>
+ <privapp-permissions package="com.android.backupconfirm">
+ <permission name="android.permission.BACKUP"/>
+ <permission name="android.permission.CRYPT_KEEPER"/>
+ </privapp-permissions>
+ <privapp-permissions package="com.android.cellbroadcastreceiver">
+ <permission name="android.permission.INTERACT_ACROSS_USERS"/>
+ <permission name="android.permission.MANAGE_USERS"/>
+ <permission name="android.permission.MODIFY_PHONE_STATE"/>
+ <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+ <permission name="android.permission.RECEIVE_EMERGENCY_BROADCAST"/>
+ </privapp-permissions>
+ ...</pre>
+
+ <h3 id="enabling-logs-to-find-missing-permissions">启用日志以查找缺少的权限</h3>
+ <p>
+在启动新设备时,我们建议首先启用过渡日志模式,如下所示:
+ </p>
+ <p>
+ <strong> <code>ro.control_privapp_permission=log</code> </strong>
+
+ </p><p>
+违规行为将在日志文件中予以报告,但所授予的权限仍将有效。这样可使设备处于工作状态,同时又能提供违规行为列表。
+ </p>
+ <p>
+错误消息格式如下:
+ </p>
+ <p>
+
+ <code>PackageManager: Privileged permission {PERMISSION_NAME} for package
+ {PACKAGE_NAME} - not in privapp-permissions whitelist</code>
+ </p>
+ <p>
+所有违规行为均必须通过列入白名单来予以解决。否则,设备将无法通过 CTS 测试。
+ </p>
+ <h2 id="cts-tests-for-whitelists">针对白名单的 CTS 测试</h2>
+ <p>
+如果您的设备实现包含未显示在 <code>/etc/permissions.</code> 下的白名单中的特权应用,则该实现不会通过 CTS 测试。
+ </p>
+ <p>
+ <code>The </code>PrivappPermissionsTest.java 测试会强制执行签名|特许权限白名单,具体方式如下:
+ </p><ul>
+ <li>报告已向 CTS 日志授予的权限。
+ </li><li>确保所有特许权限只向在 <code><privapp-permissions>,</code> 中声明的应用授予,即如果特权应用请求获取未列入白名单的签名|特许权限或系统未授予的白名单权限,则请求会失败。</li></ul>
+ <h2 id="run-time-enforcement-of-whitelists">运行时强制执行白名单</h2>
+ <p>
+白名单列好后,可通过设置版本属性 <code>ro.control_privapp_permission=enforce</code> 来启用运行时强制执行。
+ </p>
+ <p>
+ <strong>注意</strong>:无论 <code>ro.control_privapp_permission</code> 属性状态如何,只有已针对所有特权应用将特许权限正确列入白名单的设备才能通过 CTS 测试。
+ </p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/config/timezone-rules.html b/zh-cn/devices/tech/config/timezone-rules.html
new file mode 100644
index 0000000..c6b9d32
--- /dev/null
+++ b/zh-cn/devices/tech/config/timezone-rules.html
@@ -0,0 +1,470 @@
+<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>Android 8.1 为 OEM 提供了一种新机制:无需进行系统更新就可以将更新的时区规则数据推送至设备中。此机制使用户能够及时获得更新(从而延长 Android 设备的使用期限),并且使 OEM 能够独立于系统映像更新来测试时区更新。</p>
+
+<p>Android 核心库团队将提供必要的数据文件,用于更新原生 Android 设备上的时区规则。OEM 在为其设备创建时区更新时可以选择使用这些数据文件,也可以根据需要创建自己的数据文件。在任何情况下,OEM 都可以自己掌控其受支持设备的时区规则更新的质量保证/测试、时间规划及发布。</p>
+
+<h2 id="source-code">Android 时区源代码和数据</h2>
+<p>所有原生 Android 设备(即使是不使用此功能的设备)都需要时区规则数据,并且必须在 <code>/system</code> 分区中提供一组默认的时区规则数据。然后,这些数据将供 Android 源代码树中以下库中的代码使用:</p>
+
+<ul>
+<li><code>libcore/</code> 中的受管理代码(例如 <code>java.util.TimeZone</code>)使用 <code>tzdata</code> 和 <code>tzlookup.xml</code> 文件。</li>
+<li><code>bionic/</code> 中的原生库代码(例如,对于 <code>mktime</code>,本地时间系统调用)使用 <code>tzdata</code> 文件。</li>
+<li><code>external/icu/</code> 中的 ICU4J/ICU4C 库代码使用 ICU .dat 文件。</li>
+</ul>
+
+<p>这些库经过配置,能够发现 <code>/data/misc/zoneinfo/current</code> 目录中可能存在的叠加层文件。叠加层文件中应包含经过改进的时区规则数据,从而能够在不更改 <code>/system</code> 的情况下更新设备。</p>
+
+<p>需使用时区规则数据的 Android 系统组件首先检查以下位置:</p>
+
+<ul>
+<li><code>libcore/</code> 和 <code>bionic/</code> 代码使用 <code>tzdata</code> 和 <code>tzlookup.xml</code> 文件的 <code>/data</code> 副本。</li>
+<li>ICU4J/ICU4C 代码使用 <code>/data</code> 中的文件,如果在其中找不到特定数据(针对格式、本地化的字符串等),则回退到 <code>/system</code> 文件。</li>
+</ul>
+
+<h2 id="distro-files">发行版文件</h2>
+<p>发行版 .zip 文件包含填充 <code>/data/misc/zoneinfo/current</code> 目录时所需的数据文件。发行版文件还包含用于供设备检测版本问题的元数据。</p>
+<p>由于发行版文件的内容会随 ICU 版本、Android 平台要求等因素而改变,因此发行版文件的格式取决于 Android 版本。Android 会为每次 IANA 更新(在更新系统平台文件之外)提供所支持 Android 版本的发行版文件。为了使设备保持最新状态,OEM 可以选择使用此发行版文件,也可以使用 Android 源代码树(包含生成发行版文件所需的脚本和其他文件)创建自己的发行版文件。</p>
+
+<h2>时区更新组件</h2>
+<p>时区规则更新过程会将发行版文件传输到设备,并且安全地安装其中所含的文件。传输和安装过程需用到以下组件:</p>
+
+<ul>
+<li>平台服务功能 (<a href="https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/timezone/RulesManagerService.java">timezone.RulesManagerService</a>),其在默认情况下处于停用状态。OEM 必须通过相应配置来启用该功能。RulesManagerService 在系统服务器进程中运行,并通过写入 <code>/data/misc/zoneinfo/staged</code> 来暂存时区更新操作。它也可以替换或删除已经暂存的操作。</li>
+<li>
+<a href="https://android.googlesource.com/platform/packages/apps/TimeZoneUpdater/">Time Zone Updater</a>,一个不可更新的系统应用(又名 Updater App)。<em></em>OEM 必须将此应用包含在要使用该功能的设备的系统映像中。</li>
+<li>OEM <a href="https://android.googlesource.com/platform/packages/apps/TimeZoneData/">Time Zone Data</a>,一个可更新的系统应用(又名 Data App),它将发行版文件传输到设备中并使其可供 Updater App 使用。OEM 必须将此应用包含在要使用该功能的设备的系统映像中。<em></em></li>
+<li>
+<a href="https://android.googlesource.com/platform/system/timezone/+/master/tzdatacheck/">tzdatacheck</a>,一个启动时二进制文件,用于正确、安全地执行时区更新。</li>
+</ul>
+
+<p>Android 源代码树中包含上述组件的通用源代码,OEM 可以选择使用这些代码,无需做出变更。
+为使 OEM 能够自动检查是否已正确启用该功能,我们专门提供了<a href="https://android.googlesource.com/platform/packages/apps/TimeZoneData/+/master/testing/">测试代码</a>。</p>
+
+<h3 id="distro-install">发行版安装</h3>
+<p>发行版安装过程包括以下步骤:</p>
+
+<ol>
+<li>通过从应用商店下载或旁加载来<strong>更新 Data App</strong>。系统服务器进程(通过 <code>timezone.RulesManagerServer/timezone.PackageTracker</code> 类)监控对已配置的 OEM 专属 Data App 软件包名称的更改。
+<figure>
+<img src="images/tz_data_app_updates.png" alt="Data App 更新" id="data-app-updates"/>
+<figcaption><strong>图 1.</strong> Data App 更新。</figcaption></figure>
+</li>
+<li><strong>系统服务器进程触发更新检查</strong>,方法是向 Updater App 广播一个包含独一无二的一次性令牌的定向 Intent。系统服务器会持续跟踪自己生成的最新令牌,从而稍后能够确定最近一次触发的检查操作完成的时间;其他令牌一概会被忽略。
+<figure>
+<img src="images/tz_trigger_update.png" alt="触发更新" id="trigger-update"/>
+<figcaption><strong>图 2.</strong> 触发更新检查。</figcaption>
+</figure>
+</li>
+<li><strong>更新检查</strong>。在此期间,Updater App 会执行以下任务:<ul>
+<li>通过调用 RulesManagerService 来查询当前的设备状态。
+<figure>
+<img src="images/tz_call_rulesmanagerservice.png" alt="调用 RulesManagerService" id="call-rulesmanagerservice"/>
+<figcaption><strong>图 3.</strong> Data App 更新,调用 RulesManagerService。</figcaption></figure>
+</li>
+<li>通过查询明确定义的 ContentProvider URL 和列规范来查询 Data App,从而获取有关发行版的信息:<figure>
+<img src="images/tz_get_info_distro.png" alt="获取发行版信息" id="get-distro-info"/>
+<figcaption><strong>图 4.</strong> Data App 更新,获取有关发行版的信息。
+</figcaption></figure>
+</li>
+</ul>
+</li><li><strong>Updater App 执行适当的操作</strong>(根据其获得的信息)。可用的操作包括:<ul>
+<li><em></em>请求安装。从 Data App 中读取发行版数据并将此数据传递给系统服务器中的 RulesManagerService。RulesManagerService 重新确认发行版格式版本和内容是否适用于设备,然后准备安装。</li>
+<li><em></em>请求卸载(这种情况很少出现)。例如,如果要停用或卸载 <code>/data</code> 中已更新的 .apk,并且设备将退回到 <code>/system</code> 中的现有版本。</li>
+<li><em></em>不执行任何操作。在 Data App 发行版无效时会发生此情况。
+</li>
+</ul>
+在所有情况下,Updater App 都会使用检查令牌调用 RulesManagerService,以便系统服务器知道检查已成功完成。
+<figure>
+<img src="images/tz_check_complete.png" alt="检查完成" id="check-complete"/>
+<figcaption><strong>图 5.</strong> 检查完成。</figcaption></figure>
+</li>
+<li><strong>重新启动并运行 tzdatacheck</strong>。当设备下次启动时,tzdatacheck 二进制文件将执行所有暂存操作。tzdatacheck 二进制文件可以执行以下任务:<ul>
+<li>在其他系统组件打开并开始使用 <code>/data/misc/zoneinfo/current</code> 文件之前,根据暂存操作相应地创建、替换和/或删除这些文件。</li>
+<li>检查 <code>/data</code> 中的文件是否适合当前平台版本。如果设备刚刚收到系统更新并且发行版格式版本已更改,则可能不适合。</li>
+<li>确保 IANA 规则版本不低于 <code>/system</code> 中的版本。这样可防止在系统更新后设备拥有的时区规则数据版本低于 <code>/system</code> 映像中的时区规则数据版本。
+</li>
+</ul>
+</li>
+</ol>
+
+<h3 id="reliability">可靠性</h3>
+<p>端到端安装过程是异步进行的,可以分为三个操作系统进程。在安装过程中的任何时刻,如果出现设备断电、磁盘空间不足等情况,都将导致安装检查无法成功完成。在情况最好的失败案例中,Updater App 能够通知系统服务器检查失败;在情况最坏的失败案例中,RulesManagerService 不会收到任何调用。</p>
+<p>为了解决此问题,系统服务器代码会持续跟踪所触发的更新检查是否已完成,以及上次检查到的 Data App 版本号是什么。当设备空闲并在充电时,系统服务器代码可以检查当前状态。如果发现更新检查未完成或发现非预期的 Data App 版本,它会自发地触发更新检查。</p>
+
+<h3 id="security">安全性</h3>
+<p>系统服务器中的 RulesManagerService 代码在启用后会执行多项检查,以确保可以安全使用系统。</p>
+<ul>
+<li>表明系统映像配置有误的问题将导致设备无法正常启动;示例包括 Updater App 或 Data App 配置错误,或者 Updater App 或 Data App 不在 <code>/system/priv-app</code> 中。</li>
+<li>表明所安装的 Data App 有误的问题不会阻碍设备启动,但会阻碍触发更新检查;示例包括缺少必要的系统权限,或者 Data App 没有在预期的 URI 上提供 ContentProvider。</li>
+</ul>
+
+<p><code>/data/misc/zoneinfo</code> 目录的文件权限通过 SELinux 规则强制执行。与任何 APK 一样,Data App 必须使用 <code>/system/priv-app</code> 版本所用的同一密钥签名。Data App 应采用专属的 OEM 软件包名称和密钥。</p>
+
+<h2 id="integrating">集成时区更新</h2>
+<p>为了启用时区更新功能,OEM 通常要执行以下操作:</p>
+<ul>
+<li>创建自己的 Data App。</li>
+<li>在系统映像编译中加入 Updater App 和 Data App。</li>
+<li>配置系统服务器以启用 RulesManagerService。</li>
+</ul>
+
+<h3 id="preparing">准备工作</h3>
+<p>开始操作前,请查看以下政策、质量保证和安全注意事项:</p>
+<ul>
+<li>OEM 应当为其 Data App 创建该应用专用的签名密钥。</li>
+<li>OEM 应当针对时区更新拟订版本发布和版本控制策略,以了解将更新哪些设备以及如何确保只在需要的设备上安装更新。例如,OEM 可能希望为所有设备使用相同的 Data App,或者为各个设备使用不同的 Data App。相关决定会影响所选择的软件包名称和质量保证策略,还有可能影响所使用的版本号。</li>
+<li>OEM 应明确自己是要使用 AOSP 的原生 Android 时区数据,还是要创建自己的 Android 时区数据。</li>
+</ul>
+
+<h3 id="creating-data-app">创建 Data App</h3>
+<p>AOSP 在 <code>packages/apps/TimeZoneData</code> 中提供了创建 Data App 所需的所有源代码和编译规则,还提供了针对 <code>AndroidManifest.xml</code> 文件以及 <code>packages/apps/TimeZoneData/oem_template</code> 中的其他文件的说明和示例模板。示例模板包括用于实际 Data App .apk 文件的编译目标,以及用于创建 Data App 测试版本的额外目标。</p>
+<p>OEM 可以使用自己的图标、名称、翻译等内容自定义 Data App。但是,由于 Data App 无法启动,图标仅会显示在“设置 > 应用”屏幕中。<em></em></p>
+<p>Data App 按计划应采用 <strong>Tapas</strong> 编译进程进行编译。该编译进程生成的 .apk 适合添加到系统映像(针对初始版本)并适合通过应用商店进行签名和分发(针对后续更新)。要详细了解如何使用 Tapas,请参阅<a href="#building-tapas">使用 Tapas 编译 Data App</a>。</p>
+
+<aside class="note"><strong>注意</strong>:如何对 APK 进行安全签名和如何进行密钥管理不在本文讨论范围之内。</aside>
+
+<p>OEM 必须在 <code>/system/priv-app</code> 中安装设备的系统映像中预编译的 Data App。要在系统映像中包含预编译的 .apk(由 Tapas 编译进程生成),OEM 可以复制 <code>packages/apps/TimeZoneData/oem_template/data_app_prebuilt</code> 中的示例文件。示例模板还包括编译目标,以便在测试套件中包含 Data App 的测试版本。</p>
+
+<h3 id="including">在系统映像中加入 Updater App 和 Data App</h3>
+<p>OEM 必须将 Updater App 和 Data App .apk 文件放在系统映像的 <code>/system/priv-app</code> 目录中。为此,系统映像编译必须明确包含 Updater App 和 Data App 预编译目标。</p>
+<p>Updater App 应使用平台密钥进行签名,并与其他系统应用一样包含在映像内。目标在 <code>packages/apps/TimeZoneUpdater</code> 中定义为 <code>TimeZoneUpdater</code>。将 Data App 加入映像的方式因 OEM 而异,并取决于为预编译选择的目标名称。</p>
+
+<h3 id="configuring-system-server">配置系统服务器</h3>
+<p>为了启用时区更新,OEM 可以通过替换在 <code>frameworks/base/core/res/res/values/config.xml</code> 中定义的配置属性来配置系统服务器。</p>
+
+<table>
+<thead>
+<tr>
+<th>属性</th>
+<th width="20%">需要替换?</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>
+<pre class="prettyprint">
+
+config_enableUpdateableTimeZoneRules</pre>
+必须设置为 true 才能启用 RulesManagerService。</td>
+<td>是</td>
+</tr>
+<tr>
+<td><pre class="prettyprint">
+
+config_timeZoneRulesUpdateTrackingEnabled</pre>
+必须设置为 true 才能让系统监听对 Data App 的更改。</td>
+<td>是</td>
+</tr>
+<tr>
+<td><pre class="prettyprint">
+
+config_timeZoneRulesDataPackage</pre>
+OEM 专属 Data App 的软件包名称。</td>
+<td>是</td>
+</tr>
+<tr>
+<td><pre class="prettyprint">
+
+config_timeZoneRulesUpdaterPackage</pre>
+针对默认 Updater App 的配置。仅在提供不同的 Updater App 实现时才更改。</td>
+<td>否</td>
+</tr>
+<tr>
+<td><pre class="prettyprint">
+
+config_timeZoneRulesCheckTimeMillisAllowed</pre>
+RulesManagerService 触发更新检查的操作与安装、卸载或无操作响应之间所允许的间隔时间。在此时间之后,可能会自发地触发可靠性检查。</td>
+<td>否</td>
+</tr>
+<tr>
+<td><pre class="prettyprint">
+
+config_timeZoneRulesCheckRetryCount</pre>
+在 RulesManagerService 停止触发更多更新检查前所允许的连续失败更新检查次数。</td>
+<td>否</td>
+</tr>
+</tbody>
+</table>
+
+<p>配置替换文件应位于系统映像(而非 vendor 或 other 目录)中,因为配置错误的设备可能会无法启动。如果配置替换文件位于 <code>/vendor</code> 中,则更新到不含 Data App(或所含的 Data App/Updater App 具有不同的软件包名称)的系统映像将被视为配置错误。</p>
+
+<h3 id="xts-testing">xTS 测试</h3>
+<p>xTS 是指任何 OEM 专属测试套件,类似于采用 Tradefed 的标准 Android 测试套件(例如 CTS 和 VTS)。具有此类测试套件的 OEM 可添加以下位置中提供的 Android 时区更新测试:</p>
+
+<ul>
+<li><code>packages/apps/TimeZoneData/testing/xts</code>。包含自动执行基本功能测试所需的代码。</li>
+<li><code>packages/apps/TimeZoneData/oem_template/xts</code>。包含一个示例目录结构,用于将测试添加到类似 Tradefed 的 xTS 套件中。与其他模板目录一样,OEM 应根据自己的需求复制和自定义代码。</li>
+<li><code>packages/apps/TimeZoneData/oem_template/data_app_prebuilt</code>。包含编译时配置,用于纳入测试所需的预编译测试 .apk 文件。</li>
+</ul>
+
+<aside class="note"><strong>注意</strong>:设置 OEM 专属测试套件不在本文的讨论范围内。</aside>
+
+<h2 id="creating-updates">创建时区更新</h2>
+<p>当 IANA 发布一组新时区规则时,Android 核心库团队将生成补丁程序来更新 AOSP 中的版本。那些采用原生 Android 系统和发行版文件的 OEM 可提取这些变更,用它们来创建新版 Data App,然后发布新版本来更新其正式版设备。</p>
+
+<aside class="note"><strong>注意</strong>:以下步骤未说明如何更新 <code>/system</code> 映像中的基础数据文件,这是在准备出厂映像或系统更新时需要执行的工作。该过程还会生成要包含在 Data App 中的发行版文件。有关如何更新平台文件的说明,请参阅 <code>/system/timezone/README.android</code>。</aside>
+
+<p>由于 Data App 包含与 Android 版本紧密关联的发行版文件,OEM 必须为其要更新的每个受支持的 Android 版本创建一个新的 Data App 版本。<em></em>例如,如果 OEM 想要更新 O-MR1、P 和 Q 设备,则必须完成该过程三次。</p>
+
+<h3 id="step1">第 1 步:更新 system/timezone 和 external/icu 数据文件</h3>
+<p>在此步骤中,OEM 从 AOSP 的 release-dev 分支中提取 <code>system/timezone</code> 和 <code>external/icu</code> 的原生 Android 代码变更,并将这些变更应用到其 Android 源代码副本中。<em></em></p>
+<p>system/timezone AOSP 修补程序更新后的文件位于 <code>system/timezone/input_data</code> 和 <code>system/timezone/output_data</code> 中。需要在本地进行其他修复的 OEM 可以修改输入文件,然后使用 <code>system/timezone/input_data</code> 和 <code>external/icu</code> 中的文件生成 <code>output_data</code> 中的文件。</p>
+<p>最重要的文件是 <code>system/timezone/output_data/distro/distro.zip</code>。编译 Data App .apk 时,会自动包含该文件。</p>
+
+<h3 id="step2">第 2 步:更新 Data App 的版本号</h3>
+<p>在此步骤中,OEM 将更新 Data App 的版本号。编译进程会自动选取 <code>distro.zip</code>,但新版 Data App 必须具有新的版本号,以便被识别为新版本并用于替换预加载的 Data App 或之前的设备更新所安装的 Data App。</p>
+<p>使用从 <code>package/apps/TimeZoneData/oem_template/data_app</code> 复制的文件编译 Data App 时,可以在 <code>Android.mk</code> 中查找应用于 .apk 的版本号/版本名称:
+</p>
+
+<pre class="prettyprint">
+TIME_ZONE_DATA_APP_VERSION_CODE :=
+TIME_ZONE_DATA_APP_VERSION_NAME :=
+</pre>
+
+<p>类似的条目可以在 <code>testing/Android.mk</code> 中找到(但是,测试版本号必须高于系统映像版本)。要了解详情,请参阅<a href="#example-version-code-strategy">示例版本号策略方案</a>;如果使用示例方案或类似方案,则不需要更新测试版本号,因为它们肯定高于实际版本号。</p>
+
+<h3 id="step3">第 3 步:重新编译、签名、测试和发布</h3>
+<p>在此步骤中,OEM 使用 Tapas 重新编译 .apk 文件,对生成的 .apk 文件进行签名,然后测试并发布 .apk:</p>
+<ul>
+<li>对于未发布的设备(或准备已发布设备的系统更新时),请在 Data App 预编译目录中提交新的 .apk 文件,以确保系统映像和 xTS 测试具有最新的 .apk。OEM 应测试新文件能否正常工作(通过 CTS 和任何 OEM 专属的自动和手动测试)。</li>
+<li>对于不再接收系统更新的已发布设备,可能只能通过应用商店发布已签名的 .apk。</li>
+</ul>
+<p>OEM 全权负责质量保证以及在发布之前在其设备上测试更新的 Data App。</p>
+
+<h2 id="version-code-strategy">Data App 版本号策略</h2>
+<p>Data App 必须具有<a href="https://developer.android.com/google/play/publishing/multiple-apks.html#VersionCodes">适当的版本控制策略</a>,以确保设备接收正确的 .apk 文件。例如,如果收到的系统更新中包含的 .apk 版本低于从应用商店下载的版本,则应保留应用商店版本。</p>
+<p>.apk 版本号应包含以下信息:</p>
+<ul>
+<li>发行版格式版本 (Major + Minor)</li>
+<li>递增(不透明)版本号</li>
+</ul>
+<p>目前,平台 API 级别与发行版格式版本密切相关,因为每个 API 级别通常都与新版本的 ICU 相关联(这会造成发行版文件不兼容)。将来的 Android 版本可能会改变这一情况,使得一个发行版文件适用于多个 Android 平台版本(并且不在 Data App 版本号方案中使用 API 级别)。</p>
+
+<h3 id="example-version-code-strategy">版本号策略示例</h3>
+<p>此示例版本号方案可确保较高的发行版格式版本优先于较低的发行版格式版本。<code>AndroidManifest.xml</code> 使用 <code>android:minSdkVersion</code> 来确保旧版设备不会收到高于其可处理的版本的发行版格式版本。</p>
+
+<figure>
+<img src="images/tz_version_check.png" alt="版本检查" id="version-check"/>
+<figcaption><strong>图 6.</strong> 版本号策略示例。
+</figcaption></figure>
+
+<table>
+<thead>
+<tr>
+<th>示例</th>
+<th width="20%">值</th>
+<th>用途</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><strong>Y</strong></td>
+<td>保留</td>
+<td>用于在将来指定替代方案和/或测试 APK。该值最初(隐式)为 0。由于基础类型是一个带符号的 32 位整数类型,因此该方案未来最多支持两种编号方案修订版本。</td>
+</tr>
+<tr>
+<td><strong>01</strong></td>
+<td>Major 格式版本</td>
+<td>用于跟踪 3 位十进制数字 Major 格式版本。发行版格式支持 3 位十进制数字,但在此处仅使用 2 位。根据每个 API 级别的 Major 版本号预期递增情况,此数字不太可能达到 100。Major 版本 1 == API 级别 27。</td>
+</tr>
+<tr>
+<td><strong>1</strong></td>
+<td>Minor 格式版本</td>
+<td>用于跟踪 3 位十进制数字 Minor 格式版本。发行版格式支持 3 位十进制数字,但在此处仅使用 1 位。此数字不太可能达到 10。</td>
+</tr>
+<tr>
+<td><strong>X</strong></td>
+<td>保留</td>
+<td>正式版为 0(对于测试 APK,可为不同的值)。</td>
+</tr>
+<tr>
+<td><strong>ZZZZZ</strong></td>
+<td>不透明版本号</td>
+<td>按需分配的十进制数字。可存在间隙,以便在需要时执行间隙式更新。</td>
+</tr>
+</tbody>
+</table>
+
+<p>如果采用二进制而非十进制,则可以更好地打包该方案,但在可读性方面,十进制方案更具优势。如果整个范围的数字已用尽,则将来的版本可以更改 Data App 软件包名称并重新开始编号。</p>
+
+<p>版本名称将采用相关详情的可读表示法,例如:<code>major=001,minor=001,iana=2017a, revision=1,respin=2</code>。示例:</p>
+
+<table>
+<thead>
+<tr>
+<th>编号</th>
+<th>版本号</th>
+<th>minSdkVersion</th>
+<th>{Major 格式版本}.{Minor 格式版本}.{IANA 规则版本}.{修订版本}</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td>1</td>
+<td>11000010</td>
+<td>O-MR1</td>
+<td>major=001,minor=001,iana=2017a,revision=1</td>
+</tr>
+<tr>
+<td>2</td>
+<td>21000010</td>
+<td>P</td>
+<td>major=002,minor=001,iana=2017a,revision=1</td>
+</tr>
+<tr>
+<td>3</td>
+<td>11000020</td>
+<td>O-MR1</td>
+<td>major=001,minor=001,iana=2017a,revision=2</td>
+</tr>
+<tr>
+<td>4</td>
+<td>11000030</td>
+<td>O-MR1</td>
+<td>major=001,minor=001,iana=2017b,revision=1</td>
+</tr>
+<tr>
+<td>5</td>
+<td>21000020</td>
+<td>P</td>
+<td>major=002,minor=001,iana=2017b,revision=1</td>
+</tr>
+<tr>
+<td>6</td>
+<td>11000040</td>
+<td>O-MR1</td>
+<td>major=001,minor=001,iana=2018a,revision=1</td>
+</tr>
+<tr>
+<td>7</td>
+<td>21000030</td>
+<td>P</td>
+<td>major=002,minor=001,iana=2018a,revision=1</td>
+</tr>
+<tr>
+<td>8</td>
+<td>1123456789</td>
+<td>-</td>
+<td>-</td>
+</tr>
+<tr>
+<td>9</td>
+<td>11000021</td>
+<td>O-MR1</td>
+<td>major=001,minor=001,iana=2017a,revision=2,respin=2</td>
+</tr>
+</tbody>
+</table>
+
+<ul>
+<li>示例 1 和示例 2 分别显示了同一 2017a IANA 版本的两个具有不同 Major 格式版本的 .apk 版本。示例 2 在数值上高于示例 1,这是为了确保较新的设备接收较高的格式版本。minSdkVersion 可确保不会将 P 版本提供给 O 设备。</li>
+<li>示例 3 是示例 1 的示例修订版本/修复版本,在数值上高于示例 1。
+</li>
+<li>示例 4 和示例 5 显示用于 O-MR1 和 P 的 2017b 版本。由于在数值上更高,这两个示例取代了各自之前的 IANA 版本/Android 修订版本。</li>
+<li>示例 6 和示例 7 显示用于 O-MR1 和 P 的 2018a 版本。</li>
+<li>示例 8 演示使用 Y 来完全替换 Y=0 方案。
+</li>
+<li>示例 9 演示使用示例 3 和示例 4 之间的间隙来重制 apk。</li>
+</ul>
+
+<p>由于每个设备在出厂时,其系统映像中都会附带适当版本的默认 .apk,因此在 P 设备上安装 O-MR1 版本不会有任何风险,因为它的版本号低于 P 系统映像的版本。如果设备在 <code>/data</code> 中安装了 O-MR1 版本,随后又收到了更新至 P 版本的系统更新,则该设备将优先使用 <code>/system</code> 版本而非 <code> /data</code> 中的 O-MR1 版本,因为 P 版本将始终高于旨在用于 O-MR1 的任何应用版本。</p>
+
+<h2 id="building-tapas">使用 Tapas 编译 Data App</h2>
+<p>OEM 负责管理时区 Data App 的大部分内容,并负责正确配置系统映像。Data App 按计划应采用 <strong>Tapas</strong> 编译进程进行编译。该编译进程生成的 .apk 适合添加到系统映像(针对初始版本)并适合通过应用商店进行签名和分发(针对后续更新)。</p><p>
+</p><p><strong>Tapas</strong> 是 Android 编译系统的精简版本,它使用简化的源代码树来生成可分发的应用版本。熟悉常规 Android 编译系统的 OEM 可认出其编译文件与常规 Android 平台编译文件的不同之处。</p>
+
+<h3 id="creating-manifest">创建清单</h3>
+<p>简化的源代码树通常可通过自定义清单文件来实现,该文件仅会引用编译系统及编译应用所需的 Git 项目。按照<a href="#creating-data-app">创建 Data App</a> 中的说明操作后,OEM 应至少有两个使用 <code>packages/apps/TimeZoneData/oem_template</code> 下的模板文件创建的 OEM 专属 Git 项目:</p>
+
+<ul>
+<li>一个 Git 项目中包含应用文件,例如创建应用 .apk 文件(如 <code>vendor/<em>oem</em>/apps/TimeZoneData</code>)时所需的清单和编译文件。此项目还包含可供 xTS 测试使用的测试 APK 的编译规则。</li>
+<li>一个 Git 项目中包含由应用编译生成的已签名 .apk 文件,以将其包含在系统映像编译和 xTS 测试中。</li>
+</ul>
+
+<p>应用编译会用到几个其他的 Git 项目,这些 Git 项目要么与平台编译共享,要么包含独立于 OEM 的代码库。</p>
+<p>以下清单代码段包含时区 Data App 的 O-MR1 编译在最低限度下所需的一组 Git 项目(将来的 Android 版本将采用不同的列表,甚至可能会更改编译系统)。OEM 必须将其 OEM 专属 Git 项目(通常包括一个含签名证书的项目)添加到此清单,并可以相应地配置不同的分支。</p>
+
+<pre class="prettyprint">
+ <!-- Tapas Build -->
+ <project
+ path="build"
+ name="platform/build">
+ <copyfile src="core/root.mk" dest="Makefile" />
+ </project>
+ <project
+ path="prebuilts/build-tools"
+ name="platform/prebuilts/build-tools"
+ clone-depth="1" />
+ <project
+ path="prebuilts/go/linux-x86"
+ name="platform/prebuilts/go/linux-x86"
+ clone-depth="1" />
+ <project
+ path="build/blueprint"
+ name="platform/build/blueprint" />
+ <project
+ path="build/kati"
+ name="platform/build/kati" />
+ <project
+ path="build/soong"
+ name="platform/build/soong">
+ <linkfile src="root.bp" dest="Android.bp" />
+ <linkfile src="bootstrap.bash" dest="bootstrap.bash" />
+ </project>
+
+ <!-- SDK for system / public API stubs -->
+ <project
+ path="prebuilts/sdk"
+ name="platform/prebuilts/sdk"
+ clone-depth="1" />
+ <!-- App source -->
+ <project
+ path="system/timezone"
+ name="platform/system/timezone" />
+ <project
+ path="packages/apps/TimeZoneData"
+ name="platform/packages/apps/TimeZoneData" />
+ <!-- Enable repohooks -->
+ <project
+ path="tools/repohooks"
+ name="platform/tools/repohooks"
+ revision="master"
+ clone_depth="1" />
+ <repo-hooks
+ in-project="platform/tools/repohooks"
+ enabled-list="pre-upload" />
+</pre>
+
+<h3 id="running-tapas">运行 Tapas 编译</h3>
+<p>建立源代码树之后,使用以下命令调用 <strong>Tapas</strong> 编译:</p>
+
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">source build/envsetup.sh</code>
+<code class="devsite-terminal">tapas</code>
+<code class="devsite-terminal">make -j30 showcommands dist TARGET_BUILD_APPS='TimeZoneData TimeZoneData_test1 TimeZoneData_test2' TARGET_BUILD_VARIANT=userdebug</code>
+</pre>
+
+<p>成功的编译将在 <code>out/dist</code> 目录中生成用于测试的文件。可以将这些文件放在预编译目录中,以便加入到系统映像中,和/或通过应用商店分发到兼容设备。</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/connect/block-numbers.html b/zh-cn/devices/tech/connect/block-numbers.html
index 991cbb0..1fea01c 100644
--- a/zh-cn/devices/tech/connect/block-numbers.html
+++ b/zh-cn/devices/tech/connect/block-numbers.html
@@ -51,7 +51,7 @@
<h2 id="data-flow">数据流</h2>
-<img src="images/block-numbers-flow.png" alt="屏蔽号码数据流" id="block-numbers-flow"/>
+<img src="/devices/tech/connect/images/block-numbers-flow.png" alt="屏蔽号码数据流" id="block-numbers-flow"/>
<p class="img-caption">
<strong>图 1.</strong> 屏蔽电话号码数据流</p>
@@ -63,13 +63,13 @@
<h3 id="launch-from-app">从应用启动屏蔽号码管理程序</h3>
-<pre>
+<pre class="prettyprint">
Context.startActivity(telecomManager.createManageBlockedNumbersIntent(), null);
</pre>
<h3 id="query-blocked-numbers">查询屏蔽号码</h3>
-<pre>
+<pre class="prettyprint">
Cursor c = getContentResolver().query(BlockedNumbers.CONTENT_URI,
new String[]{BlockedNumbers.COLUMN_ID,
BlockedNumbers.COLUMN_ORIGINAL_NUMBER,
@@ -78,7 +78,7 @@
<h3 id="put-blocked-number">添加屏蔽号码</h3>
-<pre>
+<pre class="prettyprint">
ContentValues values = new ContentValues();
values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890");
Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
@@ -86,7 +86,7 @@
<h3 id="delete-blocked-number">删除屏蔽号码</h3>
-<pre>
+<pre class="prettyprint">
ContentValues values = new ContentValues();
values.put(BlockedNumbers.COLUMN_ORIGINAL_NUMBER, "1234567890");
Uri uri = getContentResolver().insert(BlockedNumbers.CONTENT_URI, values);
@@ -112,7 +112,7 @@
</p>
<p>
-如果设备之前配备了呼叫/短信限制功能,请调整该功能,以便所有严格匹配的屏蔽电话号码都存储在 <code>BlockedNumberProvider,</code> 中,并且围绕提供程序的行为满足 Android 兼容性定义文档 (CDD) 中针对此功能的要求。<em></em>
+如果设备之前配备了呼叫/短信限制功能,请调整该功能,以便所有严格匹配的屏蔽电话号码都存储在 <code>BlockedNumberProvider,</code> 中,并且围绕该提供程序的行为满足 Android 兼容性定义文档 (CDD) 中针对此功能的要求。<em></em>
</p>
<p>
@@ -164,7 +164,7 @@
实现人员可以通过运行以下 CTS 测试来确保其功能版本能够按预期运转:
</p>
-<pre>
+<pre class="devsite-click-to-copy">
android.provider.cts.BlockedNumberContractTest
com.android.cts.numberblocking.hostside.NumberBlockingTest
android.telecom.cts.ExtendedInCallServiceTest#testIncomingCallFromBlockedNumber_IsRejected
@@ -174,11 +174,11 @@
<p>
在运行 <code>$ adb root</code> 之后,可以使用 <code>adb</code> 命令来操作 <code>BlockedNumberProvider</code>。例如:
</p>
-<pre>
-$ adb root
-$ adb shell content query --uri content://com.android.blockednumber/blocked
-$ adb shell content insert --uri / content://com.android.blockednumber/blocked --bind / original_number:s:'6501002000'
-$ adb shell content delete --uri / content://com.android.blockednumber/blocked/1
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb root</code>
+<code class="devsite-terminal">adb shell content query --uri content://com.android.blockednumber/blocked</code>
+<code class="devsite-terminal">adb shell content insert --uri / content://com.android.blockednumber/blocked --bind / original_number:s:'6501002000'</code>
+<code class="devsite-terminal">adb shell content delete --uri / content://com.android.blockednumber/blocked/1</code>
</pre>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/connect/connect_tests.html b/zh-cn/devices/tech/connect/connect_tests.html
new file mode 100644
index 0000000..d6c89fb
--- /dev/null
+++ b/zh-cn/devices/tech/connect/connect_tests.html
@@ -0,0 +1,66 @@
+<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>Android Connectivity Testing Suite (ACTS) 测试填补了 Android 框架 API 和芯片组认证之间的测试空白。这些测试可验证 Android 框架所用的蓝牙、WLAN 和移动网络各方面的功能。</p>
+
+<h2 id="users">哪些人应该运行 ACTS 测试?</h2>
+
+<p>应该由负责 Android 堆栈的连接(蓝牙、WLAN 和移动网络)部分的开发者和集成人员运行 ACTS 测试。如果您要添加新功能、集成芯片组或驱动程序变更,这些测试可帮助您确保所做的更改功能和稳定性正常且符合基本的性能标准。</p>
+
+<p>这些测试为可选测试,任何 Android 设备认证都不强制要求完成这些测试。</p>
+
+<h2 id="how">如何运行 ACTS</h2>
+
+<p>ACTS 测试利用特权 Android API 解锁原本不可用的更深层次的测试。因此,只能使用 ACTS 来测试工程和 userdebug 版本。</p>
+
+<p>ACTS 测试旨在以最少且通常是现成的硬件运行,不过,测试也需要一些设备(因测试类型而异)。对于很多测试,两台 Android 设备或一台设备以及一个 WLAN 接入点就足够了。请参阅针对其中一个主要测试方面(蓝牙、WLAN 或移动网络)的文档,以确定具体的设置要求。</p>
+
+<h2 id="test-types">测试类型</h2>
+
+<h3 id="script-android">Android 脚本层</h3>
+
+<p><code><a href="https://android.googlesource.com/platform/external/sl4a/"><platform>/external/sl4a</platform></a></code> 中的 <a href="https://android.googlesource.com/platform/external/sl4a/+/master/README.md">Android 脚本层</a>是来自同名开放源代码项目的一个分支。该工具提供精简型 RPC 服务器来公开 Android 的 Java API。它允许测试脱机驻留,支持设备的协同自动化,从而实现更丰富的动态测试。在过去的 18 个月中,Google 已经调整、更新、扩展并使用该项目来远程运用 Android 的 Java API 测试无线连接。</p>
+
+<h3 id="script-native">原生脚本层</h3>
+
+<p><code><a href="https://android.googlesource.com/platform/packages/apps/Test/connectivity/"><platform>/packages/apps/Test/connectivity</platform></a></code> 中的<a href="https://android.googlesource.com/platform/packages/apps/Test/connectivity/+/master/sl4n/README.md">原生脚本层</a>是全新的内部发展型 RPC 服务器,用于以 Android 脚本层公开 Java API 的方式公开 Android 的原生 API。该工具目前用于测试 Brillo,我们预计该项目将迅速扩展,以满足越来越重要的原生无线 API 的测试需求。</p>
+
+<h3 id="script-android">Android 通讯测试套件</h3>
+
+<p><code><a href="https://android.googlesource.com/platform/tools/test/connectivity/"><platform>/tools/test/connectivity</platform></a></code> 中的 <a href="https://android.googlesource.com/platform/tools/test/connectivity/+/master/acts/README.md">Android 通讯测试套件</a>为基于 Python 的轻量级自动化工具集,用于针对当前和即将推出的 Android 设备执行自动化测试。它提供了简洁的执行界面、一组用于访问衰减器等设备和 Android 设备的可插拔库,以及一些可进一步简化测试开发的实用函数。我们认为它是一种非常适合无线堆栈开发者或集成人员的桌面工具,无论他们是创建新的代码路径、执行基本的完整性测试,还是运行扩展的回归测试套件都没问题。</p>
+
+<p>本测试套件还包括一系列测试,很多测试在一台或两台具有 WLAN、移动网络或蓝牙连接的 Android 设备上即可运行,其中包括:</p>
+
+<ul>
+<li>针对 AP IOT、企业连接、WifiScanner、Autojoin 和 RTT 的 WLAN 测试。</li><li>针对 BLE、GATT、SPP 和 Bonding 的蓝牙测试。
+</li><li>针对 CS 和 IMS 呼叫、数据网络连接、短信、网络切换和热点的移动网络测试。</li>
+</ul>
+
+<p>我们相信,通过降低基本测试的门槛,并作为整个社区基于改进的系统测试进行协作的聚合点,这些工具的发布将帮助开发者、集成人员和测试人员等。</p>
+
+<h2 id="failures-contributors">失败和贡献</h2>
+
+<p>ACTS 测试并非认证套件,严格意义上来说,发布 Android 设备无需通过这些测试,但是,测试失败可能说明用户体验不佳。也就是说,如果测试失败,也无需感到失望。一些测试有意让您很难通过。其目的是帮助开发者推出高性能设备。</p>
+
+<p>ACTS 是一项相对较新的举措,并且来自开发社区的参与至关重要。如需添加测试、报告问题或提出问题,请在 <a href="https://code.google.com/p/android/issues/entry">Android 问题跟踪器</a>上使用连接性测试模板新开一个错误,以发起相关交流。</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/connect/data-saver.html b/zh-cn/devices/tech/connect/data-saver.html
index 9ae8253..eb46d9e 100644
--- a/zh-cn/devices/tech/connect/data-saver.html
+++ b/zh-cn/devices/tech/connect/data-saver.html
@@ -45,19 +45,19 @@
<p>这些屏幕截图显示了使用中的流量节省程序模式。
</p>
-<img src="images/data-saver-use.png" width="397" alt="关闭/开启流量节省程序"/>
+<img src="/devices/tech/connect/images/data-saver-use.png" width="397" alt="关闭/开启流量节省程序"/>
<p class="img-caption">
<strong>图 1.</strong> 关闭/打开流量节省程序</p>
-<img src="images/data-battery-saver.png" width="641" alt="省电模式和流量节省程序同时开启"/>
+<img src="/devices/tech/connect/images/data-battery-saver.png" width="641" alt="省电模式和流量节省程序同时开启"/>
<p class="img-caption">
<strong>图 2.</strong> 省电模式和流量节省程序同时开启</p>
-<img src="images/data-saver-app.png" width="376" alt="特定应用流量使用情况屏幕"/>
+<img src="/devices/tech/connect/images/data-saver-app.png" width="376" alt="特定应用流量使用情况屏幕"/>
<p class="img-caption">
<strong>图 3.</strong> 特定应用流量使用情况屏幕:“设置”>“应用”>“流量使用情况”</p>
-<img src="images/data-saver-quick-settings.png" width="446" alt="“快捷设置”中的流量节省程序"/>
+<img src="/devices/tech/connect/images/data-saver-quick-settings.png" width="446" alt="“快捷设置”中的流量节省程序"/>
<p class="img-caption">
<strong>图 4.</strong> “快捷设置”菜单中的流量节省程序状态</p>
@@ -92,16 +92,18 @@
<p>实现人员可以运行以下 CTS 测试,从而确保其功能版本能够按预期运行。</p>
-<pre>
+<pre class="devsite-click-to-copy">
com.android.cts.net.HostsideRestrictBackgroundNetworkTests
</pre>
-<p>此外,还可以先运行以下命令来查看所有可用选项,从而使用 <code>adb</code> 命令手动执行测试:<br />
-<code>$ adb shell cmd netpolicy</code>
-</p>
+<p>此外,还可以先运行以下命令来查看所有可用选项,从而使用 <code>adb</code> 命令手动执行测试:</p>
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell cmd netpolicy
+</pre>
-<p>例如,执行此命令可返回白名单应用的 UID:<br />
-<code>$ adb shell cmd netpolicy list restrict-background-whitelist</code>
-</p>
+<p>例如,执行此命令可返回白名单应用的 UID:</p>
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell cmd netpolicy list restrict-background-whitelist
+</pre>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/connect/wifi-aware.html b/zh-cn/devices/tech/connect/wifi-aware.html
new file mode 100644
index 0000000..102cc97
--- /dev/null
+++ b/zh-cn/devices/tech/connect/wifi-aware.html
@@ -0,0 +1,85 @@
+<html devsite><head>
+ <title>WLAN 感知</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 (O MR1) 版本中的 <a href="https://developer.android.com/guide/topics/connectivity/wifi-aware.html">WLAN 感知</a>功能支持多个设备直接通过 WLAN 进行互连(无需连接到互联网或移动网络)。此功能是基于 <a href="https://www.wi-fi.org/">WLAN 联盟</a> <a href="https://www.wi-fi.org/discover-wi-fi/wi-fi-aware">WLAN 感知规范</a>(2.0 版)构建的,它支持在断开网络的情况下,在可信设备与应用之间轻松共享高吞吐量数据。
+</p>
+
+<h2 id="examples-and-source">示例和源代码</h2>
+
+<p>
+要使用此功能,设备制造商应采用在 Android 开源项目 (AOSP) 中提供的 WLAN 硬件接口设计语言 (HIDL)。在 Android 8.0 (O) 版本中,HIDL 取代了之前使用的硬件抽象层 (HAL) 结构,以便通过指定收集到接口和软件包的类型和方法调用来简化实现流程。
+</p>
+
+<p>
+借助 WLAN HIDL 使用 WLAN 感知功能:hardware/interfaces/wifi/1.0。WLAN 感知 HAL 表面非常大;<a href="https://android.googlesource.com/platform/hardware/interfaces/+/master/wifi/1.0/README-NAN.md">hardware/interfaces/wifi/1.0/README-NAN.md</a> 文件描述了当前使用的子集。
+</p>
+
+<p>
+您可以参考旧版 WLAN HAL 来了解它与新 HIDL 接口之间的关系:<a href="https://android.googlesource.com/platform/hardware/libhardware_legacy/+/master/include/hardware_legacy/wifi_nan.h">hardware/libhardware_legacy/+/master/include/hardware_legacy/wifi_nan.h</a>。
+</p>
+
+<h2 id="implementation">实现</h2>
+
+<p>
+设备制造商需要提供框架和 HAL/固件支持:</p>
+<ul>
+ <li>框架:
+ <ul>
+ <li>AOSP 代码</li>
+ <li>启用感知功能:需要功能标记和 HIDL 编译标记</li>
+ </ul>
+ </li><li>WLAN 感知 (NAN) HAL 支持(意味着固件支持)</li>
+
+</ul>
+
+<p>
+为实现此功能,设备制造商需采用 WLAN HIDL,另外还要启用两个功能标记:</p>
+
+<p>
+在 <code>BoardConfig.mk</code> 中,添加此标记可指示 WLAN HIDL 包含 WLAN 感知功能:<code>WIFI_HIDL_FEATURE_AWARE := true</code>
+</p>
+
+<p>
+在 <code>device.mk</code> 中,修改 <code>PRODUCT_COPY_FILES</code> 环境变量以提供对 WLAN 感知功能的支持:
+<code>PRODUCT_COPY_FILES +=
+frameworks/native/data/etc/android.hardware.wifi.aware.xml:system/etc/permissions/android.hardware.wifi.aware.xml</code>
+</p>
+
+<p>
+否则,实现此功能所需的所有内容都会包含在 AOSP 中。</p>
+
+<h2 id="validation">验证</h2>
+
+<p>
+这项功能有适用的 Android 兼容性测试套件 (CTS) 测试。CTS 会检测何时启用了这项功能,并会自动包含相关测试。
+</p>
+
+<p>
+您也可以使用<a href="/devices/tech/test_infra/tradefed/fundamentals/vts">供应商测试套件 (VTS) </a>和 <a href="https://android.googlesource.com/platform/tools/test/connectivity/+/master/acts/tests/google/wifi/">acts/sl4a</a>(用于执行扩展程序集成测试的测试套件)来测试此功能。
+</p>
+
+<p>
+acts/sl4a 测试套件(在 <a href="https://android.googlesource.com/platform/tools/test/connectivity/+/master/acts/tests/google/wifi/aware/README.md">tools/test/connectivity/acts/tests/google/wifi/aware/README.md</a> 中有相应说明)提供了功能测试、性能测试和压力测试。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/dalvik/gc-debug.html b/zh-cn/devices/tech/dalvik/gc-debug.html
index 2827db7..674c6d0 100644
--- a/zh-cn/devices/tech/dalvik/gc-debug.html
+++ b/zh-cn/devices/tech/dalvik/gc-debug.html
@@ -22,7 +22,7 @@
<p>本文档介绍如何调试 Android 运行时 (ART) 垃圾回收 (GC) 的正确性和性能问题。本文档解释了如何使用 GC 验证选项、确定 GC 验证失败的解决方案,以及测量并解决 GC 性能问题。</p>
-<p>有关处理 ART 的说明,请参阅 <a href="index.html">ART 和 Dalvik</a>、<a href="dex-format.html">Dalvik 可执行格式</a>以及 <a href="index.html">ART 和 Dalvik</a> 部分的其他页面。有关验证应用行为的其他帮助信息,请参阅<a href="http://developer.android.com/guide/practices/verifying-apps-art.html">在 Android 运行时 (ART) 上验证应用行为</a>。</p>
+<p>有关处理 ART 的说明,请参阅 <a href="index.html">ART 和 Dalvik</a>、<a href="dex-format.html">Dalvik 可执行格式</a>以及此 <a href="index.html">ART 和 Dalvik</a> 部分的其他页面。有关验证应用行为的其他帮助信息,请参阅<a href="http://developer.android.com/guide/practices/verifying-apps-art.html">在 Android 运行时 (ART) 上验证应用行为</a>。</p>
<h2 id="art_gc_overview">ART GC 概述</h2>
@@ -36,8 +36,9 @@
<ul>
<li>与 Dalvik 相比,暂停次数从 2 次减少到 1 次。Dalvik 的第一次暂停主要是为了进行根标记,即在 ART 中进行并发标记,让线程标记自己的根,然后马上恢复运行。
- </li><li>与 Dalvik 类似,ART GC 在清除过程开始之前也会暂停 1 次。两者在这方面的主要差异在于:在此暂停期间,某些 Dalvik 阶段在 ART 中并发进行。这些阶段包括 <code>java.lang.ref.Reference</code> 处理、系统弱清除(例如,jni 弱全局等)、重新标记非线程根和卡片预清理。在 ART 暂停期间仍进行的阶段包括扫描脏卡片以及重新标记线程根,这些操作有助于缩短暂停时间。
- </li><li>相对于 Dalvik,ART GC 改进的最后一个方面是粘性 CMS 回收器增加了 GC 吞吐量。不同于普通的分代 GC,粘性 CMS 不移动。年轻对象被保存在一个分配堆栈(基本上是 <code>java.lang. Object</code> 数组)中,而非为其设置一个专用区域。这样可以避免移动所需的对象以维持低暂停次数,但缺点是容易在堆栈中加入大量复杂对象图像而使堆栈变长。
+ </li><li>与 Dalvik 类似,ART GC 在清除过程开始之前也会暂停 1 次。
+两者在这方面的主要差异在于:在此暂停期间,某些 Dalvik 阶段在 ART 中并发进行。这些阶段包括 <code>java.lang.ref.Reference</code> 处理、系统弱清除(例如,jni 弱全局等)、重新标记非线程根和卡片预清理。在 ART 暂停期间仍进行的阶段包括扫描脏卡片以及重新标记线程根,这些操作有助于缩短暂停时间。
+ </li><li>相对于 Dalvik,ART GC 改进的最后一个方面是粘性 CMS 回收器增加了 GC 吞吐量。不同于普通的分代 GC,粘性 CMS 不移动。年轻对象会被保存在一个分配堆栈(基本上是 <code>java.lang.Object</code> 数组)中,而非为其设置一个专用区域。这样可以避免移动所需的对象以维持低暂停次数,但缺点是容易在堆栈中加入大量复杂对象图像而使堆栈变长。
</li></ul>
<p>ART GC 与 Dalvik 的另一个主要区别在于 ART GC 引入了移动垃圾回收器。使用移动 GC 的目的在于通过堆压缩来减少后台应用使用的内存。目前,触发堆压缩的事件是 ActivityManager 进程状态的改变。当应用转到后台运行时,它会通知 ART 已进入不再“感知”卡顿的进程状态。此时 ART 会进行一些操作(例如,压缩和监视器压缩),从而导致应用线程长时间暂停。目前正在使用的两个移动 GC 是同构空间压缩和半空间压缩。</p>
@@ -93,12 +94,15 @@
<p>通过将 SIGQUIT 发送到已运行的应用,或在启动命令行程序时通过将 -<code>XX:DumpGCPerformanceOnShutdown</code> 传递给 <code>dalvikvm</code>,可以获得应用的 GC 性能时序。当应用获得 ANR 请求信号 (SIGQUIT) 时,它将转储与锁定、线程堆栈和 GC 性能相关的信息。</p>
-<p>获取 GC 时序转储的方法是使用以下命令:<br />
-<code>$ adb shell kill -S QUIT <pid></pid></code></p>
+<p>获取 GC 时序转储的方法是使用以下命令:</p>
+
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell kill -S QUIT <var>PID</var>
+</pre>
<p>该操作将在 <code>/data/anr/</code> 中创建一个 <code>traces.txt</code> 文件。此文件包含一些 ANR 转储信息以及 GC 时序。您可以通过搜索“转储累计 GC 时序”来确定 GC 时序。这些时序会显示一些相关内容。它会显示各 GC 类型的阶段和暂停的直方图信息。暂停信息通常比较重要。例如:</p>
-<pre>
+<pre class="devsite-click-to-copy">
sticky concurrent mark sweep paused: Sum: 5.491ms 99% C.I. 1.464ms-2.133ms Avg: 1.830ms Max: 2.133ms
</pre>
@@ -106,26 +110,26 @@
<p>需要关注的另一个问题是挂起时间。挂起时间测量在 GC 要求某个线程挂起后,线程到达挂起点所需的时间。该时间包含在 GC 暂停中,所以可用于确定长时间暂停是否是由 GC 缓慢或线程挂起缓慢造成。以下是 Nexus 5 上的正常挂起时间示例:</p>
-<pre>
+<pre class="devsite-click-to-copy">
suspend all histogram: Sum: 1.513ms 99% C.I. 3us-546.560us Avg: 47.281us Max: 601us
</pre>
<p>还有一些其他要关注的方面,例如总耗时、GC 吞吐量等。示例如下:</p>
-<pre>
+<pre class="devsite-click-to-copy">
Total time spent in GC: 502.251ms
Mean GC size throughput: 92MB/s
Mean GC object throughput: 1.54702e+06 objects/s
</pre>
-<p>转储已运行应用的 GC 时序的示例如下:</p><pre>
-$ adb shell kill -s QUIT <pid>
-$ adb pull /data/anr/traces.txt
+<p>转储已运行应用的 GC 时序的示例如下:</p><pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb shell kill -s QUIT <var>PID</var></code>
+<code class="devsite-terminal">adb pull /data/anr/traces.txt</code>
</pre>
<p>此时,GC 时序包含在 trace.txt 中。Google 地图的输出示例如下:</p>
-<pre>
+<pre class="devsite-click-to-copy">
Start Dumping histograms for 34 iterations for sticky concurrent mark sweep
ScanGrayAllocSpaceObjects: Sum: 196.174ms 99% C.I. 0.011ms-11.615ms Avg: 1.442ms Max: 14.091ms
FreeList: Sum: 140.457ms 99% C.I. 6us-1676.749us Avg: 128.505us Max: 9886us
@@ -194,17 +198,17 @@
<p>验证应用行为的另一种方法是使用 CheckJNI。CheckJNI 是一种添加额外 JNI 检查的模式;出于性能考虑,这些选项在默认情况下并不会启用。此类检查将捕获一些可能导致堆损坏的错误,例如使用无效/过时的局部和全局引用。启用 CheckJNI 的方法如下:</p>
-<pre>
-$ adb shell setprop dalvik.vm.checkjni true
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell setprop dalvik.vm.checkjni true
</pre>
<p>Forcecopy 模式是 CheckJNI 的另一部分,对检测超出数组区域末端的写入非常有用。启用后,forcecopy 会促使数组访问 JNI 函数时始终返回带有红色区域的副本。<em></em>红色区域是返回指针结束/开始处的一个区域,该区域具有特殊值,并在数组释放时得到验证。如果红色区域中的值与预期值不匹配,则通常意味着发生缓冲区溢出或欠载。这将导致 CheckJNI 中止。启用 forcecopy 模式的方法如下:</p>
-<pre>
-$ adb shell setprop dalvik.vm.jniopts forcecopy
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell setprop dalvik.vm.jniopts forcecopy
</pre>
-<p>CheckJNI 应捕获错误的一个示例是超出从 <code>GetPrimitiveArrayCritical</code> 获取的数组末端的写入。该操作很可能会破坏 Java 堆。如果写入位于 CheckJNI 红色区域内,则在调用相应 <code>ReleasePrimitiveArrayCritical</code> 时,CheckJNI 将会捕获该问题。否则,写入将最终损坏 Java 堆中的一些随机对象,并可能会导致之后出现 GC 崩溃。如果崩溃的内存是引用字段,则 GC 可能会捕获错误并输出“Tried to mark not contained by any spaces<em></em><ptr></ptr>”的错误消息。</p>
+<p>CheckJNI 应捕获错误的一个示例是超出从 <code>GetPrimitiveArrayCritical</code> 获取的数组末端的写入。该操作很可能会破坏 Java 堆。如果写入位于 CheckJNI 红色区域内,则在调用相应 <code>ReleasePrimitiveArrayCritical</code> 时,CheckJNI 将会捕获该问题。否则,写入将最终损坏 Java 堆中的一些随机对象,并可能会导致之后出现 GC 崩溃。如果崩溃的内存是引用字段,则 GC 可能会捕获错误并输出“Tried to mark <ptr>not contained by any spaces</ptr>”的错误消息。<em></em></p>
<p>当 GC 尝试标记无法找到空间的对象时,就会发生此错误。在此检查失败后,GC 会遍历根,并尝试查看无效对象是否为根。结果共有两个选项:对象为根或非根。</p>
@@ -214,18 +218,18 @@
<p>以下是一个使用示例:</p>
-<pre>
+<pre class="devsite-click-to-copy">
# build and install
-$ mmm external/valgrind
-$ adb remount && adb sync
+<code class="devsite-terminal">mmm external/valgrind</code>
+<code class="devsite-terminal">adb remount && adb sync</code>
# disable selinux
-$ adb shell setenforce 0
-$ adb shell setprop wrap.com.android.calculator2
+<code class="devsite-terminal">adb shell setenforce 0</code>
+<code class="devsite-terminal">adb shell setprop wrap.com.android.calculator2</code>
"TMPDIR=/data/data/com.android.calculator2 logwrapper valgrind"
# push symbols
-$ adb shell mkdir /data/local/symbols
-$ adb push $OUT/symbols /data/local/symbols
-$ adb logcat
+<code class="devsite-terminal">adb shell mkdir /data/local/symbols</code>
+<code class="devsite-terminal">adb push $OUT/symbols /data/local/symbols</code>
+<code class="devsite-terminal">adb logcat</code>
</pre>
<h3 id="invalid_root_example">无效的根示例</h3>
@@ -234,7 +238,7 @@
<code>art E 5955 5955 art/runtime/gc/collector/mark_sweep.cc:383] Tried to mark 0x2
not contained by any spaces</code></p>
-<pre>
+<pre class="devsite-click-to-copy">
art E 5955 5955 art/runtime/gc/collector/mark_sweep.cc:384] Attempting see if
it's a bad root
art E 5955 5955 art/runtime/gc/collector/mark_sweep.cc:485] Found invalid
@@ -245,13 +249,13 @@
(native PC 0xf19609d9) vreg=1
</pre>
-<p>在这种情况下,<code>vreg 1</code>(在 <code>com.google.gwt.corp.collections.JavaReadableJsArray.get</code> 内)应该包含一个堆引用,但实际上包含地址 <code>0x2</code> 的一个无效指针。这显然是一个无效根。要调试此问题,下一步是在 oat 文件中使用 <code>oatdump</code>,并查看具有无效根的方法。在这种情况下,结果证明错误在于 x86 后端的编译器错误。修正该错误的更改列表如下:<a href="https://android-review.googlesource.com/#/c/133932/">https://android-review.googlesource.com/#/c/133932/</a></p>
+<p>在这种情况下,<code>vreg 1</code>(在 <code>com.google.gwt.corp.collections.JavaReadableJsArray.get</code> 内)应该包含一个堆引用,但实际上却包含了地址 <code>0x2</code> 的一个无效指针。这显然是一个无效根。要调试此问题,下一步是在 oat 文件中使用 <code>oatdump</code>,并查看具有无效根的方法。在这种情况下,结果证明错误在于 x86 后端的编译器错误。修正该错误的更改列表如下:<a href="https://android-review.googlesource.com/#/c/133932/">https://android-review.googlesource.com/#/c/133932/</a></p>
<h3 id="corrupted_object_example">损坏的对象示例</h3>
<p>如果对象不是根,则会输出类似于以下打印内容的消息:</p>
-<pre>
+<pre class="devsite-click-to-copy">
01-15 12:38:00.196 1217 1238 E art : Attempting see if it's a bad root
01-15 12:38:00.196 1217 1238 F art :
art/runtime/gc/collector/mark_sweep.cc:381] Can't mark invalid object
diff --git a/zh-cn/devices/tech/dalvik/improvements.html b/zh-cn/devices/tech/dalvik/improvements.html
new file mode 100644
index 0000000..8c82e4d
--- /dev/null
+++ b/zh-cn/devices/tech/dalvik/improvements.html
@@ -0,0 +1,147 @@
+<html devsite><head>
+ <title>Android 8.0 中的 ART 功能改进</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.0 版本中,Android Runtime (ART) 有了极大改进。下面的列表总结了设备制造商可以在 ART 中获得的增强功能。
+</p>
+
+<h2 id="loop-optimizations">循环优化</h2>
+
+<p>
+在 Android 8.0 版本中,ART 采用了多种循环优化,具体如下:
+</p>
+ <ul>
+ <li>消除边界检查
+ <ul>
+ <li>静态:证明范围在编译时位于边界内
+ </li><li>动态:运行时测试确保循环始终位于边界内(否则就是逆优化)
+ </li></ul>
+ </li><li>消除归纳变量
+ <ul>
+ <li>移除无用归纳</li><li>用封闭式表达式替换仅在循环后使用的归纳
+ </li></ul>
+ </li><li>消除循环主体内的无用代码,移除整个死循环</li><li>强度减少
+ </li><li>循环转换:逆转、交换、拆分、展开、单模等。
+ </li><li>SIMDization(也称为矢量化)</li>
+ </ul>
+
+<p>
+循环优化器位于 ART 编译器中其自身的优化遍数中。
+大多数循环优化与其他方面的优化和简化类似。由于大多数 CFG 实用工具(请参阅 nodes.h)侧重于编译而不是重写 CFG,因此通过更复杂(与平时相比)的方式进行一些重写 CFG 的优化时,会面临挑战。
+</p>
+
+<h2 id="class-hierarchy-analysis">类层次结构分析</h2>
+
+<p>
+在 Android 8.0 中,ART 会使用类层次结构分析 (CHA),这是一种编译器优化,可基于通过分析类层次结构所生成的信息,将虚拟调用去虚拟化为直接调用。虚拟调用代价高昂,因为它们围绕 vtable 查找来实现,且会占用几个依赖负载。另外,虚拟调用也不能内嵌。
+</p>
+
+<p>
+以下是对相关增强功能的总结:
+</p>
+ <ul>
+ <li>动态单一实现方法状态更新 - 在类关联时间结束时,如果 vtable 已被填充,ART 会按条目对超类的 vtable 进行比较。</li>
+ <li>编译器优化 - 编译器会利用某种方法的单一实现信息。如果方法 A.foo 设置了单一实现标记,则编译器会将虚拟调用去虚拟化为直接调用,并借此进一步尝试内联直接调用。</li>
+ <li>已编译代码无效 - 另外,在类关联时间结束时,如果单一实现信息进行了更新,且方法 A.foo 之前拥有单一实现,但该状态现已变为无效,则依赖方法 A.foo 拥有单一实现这一假设的所有已编译代码都需要变为无效代码。</li>
+ <li>去优化 - 对于堆栈上已编译的有效代码,系统会启动去优化功能,以强制使已编译代码进入解释器模式,从而确保正确性。系统会采用结合了同步和异步去优化的全新去优化机制。</li>
+</ul>
+
+<h2 id="inline-caches-in-oat-files">.oat 文件中的内联缓存</h2>
+
+<p>
+ART 现在采用的是内联缓存,并优化了有足够数据可用的调用站点。内联缓存功能会将额外的运行时信息记录到配置文件中,并会利用这类信息将动态优化添加到预先编译中。
+</p>
+
+<h2 id="dexlayout">Dexlayout</h2>
+
+<p>
+Dexlayout 是在 Android 8.0 中引入的一个库,用于分析 dex 文件,并根据配置文件对其进行重新排序。Dexlayout 旨在使用运行时配置信息对 dex 文件的各个部分进行重新排序(在设备的空闲维护编译期间)。通过将经常一起访问的部分 dex 文件集中在一起,程序可以因改进文件位置而拥有更好的内存访问模式,从而节省 RAM 并缩短启动时间。
+</p>
+
+<p>
+由于配置文件信息目前仅在运行应用后可用,因此系统会在空闲维护期间将 dexlayout 集成到 dex2oat 的设备编译中。
+</p>
+
+<h2 id="dex-cache-removal">Dex 缓存移除</h2>
+
+<p>
+在 Android 7.0 及更早版本中,DexCache 对象拥有四个大型数组,与 DexFile 中特定元素的数量成正比,即:
+</p>
+
+<ul>
+ <li>字符串(每个 DexFile :: StringId 一个引用),
+ </li>
+ <li>类型(每个 DexFile :: TypeId 一个引用),
+ </li>
+ <li>方法(每个 DexFile :: MethodId 一个原生指针),
+ </li>
+ <li>字段(每个 DexFile :: FieldId 一个原生指针)。
+ </li>
+</ul>
+
+<p>
+ 这些数组用于快速检索我们以前解决的对象。在 Android 8.0 中,除方法数组外,所有数组都已移除。
+</p>
+
+<h2 id="interpreter-performance">解释器性能</h2>
+
+<p>
+通过引入 Mterp(一种解释器,具有以汇编语言编写的核心提取/解码/解释机制),Android 7.0 版本中的解释器性能得以显著提升。Mterp 模仿了快速的 Dalvik 解释器,并支持 arm、arm64、x86、x86_64、mips 和 mips64。对于计算代码而言,ART 的 Mterp 大致相当于 Dalvik 的快速解释器。不过,有时候,它的速度可能会显著变慢,甚至急剧变慢:
+</p>
+
+ <ol>
+ <li>调用性能。</li>
+ <li>字符串操作和 Dalvik 中其他被视为内联函数的高频用户方法。</li>
+ <li>堆栈内存使用量较高。</li>
+ </ol>
+
+<p>
+Android 8.0 解决了这些问题。
+</p>
+
+<h2 id="more-inlining">详细了解内联</h2>
+
+<p>
+从 Android 6.0 开始,ART 可以内联同一个 dex 文件中的任何调用,但只能内联来自其他 dex 文件的叶方法。实施此项限制的两个原因如下:
+</p>
+
+ <ol>
+ <li>从其他 dex 文件进行内联需要使用该 dex 文件的 dex 缓存,这与同一 dex 文件内联(只能重复使用调用程序的 dex 缓存)有所不同。已编译代码中需要具有 dex 缓存,以便执行一系列指令,例如静态调用、字符串加载或类加载。
+ </li><li>堆栈映射只对当前 dex 文件中的方法索引进行编码。</li>
+ </ol>
+
+<p>
+为了取消这些限制,Android 8.0 做出了以下改进:
+</p>
+
+ <ol>
+ <li>从已编译代码中移除 dex 缓存访问(另请参阅“Dex 缓存移除”部分)</li>
+ <li>扩展堆栈映射编码。</li>
+ </ol>
+
+<h2 id="synchronization-improvements">同步方面的改进</h2>
+
+<p>
+ART 团队调整了 MonitorEnter/MonitorExit 代码路径,并减少了我们对 ARMv8 上传统内存屏障的依赖,尽可能将其替换为较新的(获取/释放)指令。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/dalvik/index.html b/zh-cn/devices/tech/dalvik/index.html
index d808ab5..2c2deab 100644
--- a/zh-cn/devices/tech/dalvik/index.html
+++ b/zh-cn/devices/tech/dalvik/index.html
@@ -42,7 +42,7 @@
<li>采用一个而非两个 GC 暂停</li>
<li>在 GC 保持暂停状态期间并行处理</li>
<li>采用总 GC 时间更短的回收器清理最近分配的短时对象这种特殊情况</li>
- <li>优化了垃圾回收人机工程学,这样能够更加及时地进行并行垃圾回收,这使得 <a href="http://developer.android.com/tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a> 事件在典型用例中极为罕见</li>
+ <li>优化了垃圾回收人机工程学,这样能够更加及时地进行并行垃圾回收,而这使得 <a href="http://developer.android.com/tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a> 事件在典型用例中极为罕见</li>
<li>压缩 GC 以减少后台内存使用和碎片</li>
</ul>
@@ -70,9 +70,10 @@
<h4 id="Crash_Reports">优化了异常和崩溃报告中的诊断详细信息</h4>
-<p>当发生运行时异常时,ART 会为您提供尽可能多的上下文和详细信息。ART 会提供 <code><a href="http://developer.android.com/reference/java/lang/ClassCastException.html">java.lang.ClassCastException</a></code>、<code><a href="http://developer.android.com/reference/java/lang/ClassNotFoundException.html">java.lang.ClassNotFoundException</a></code> 和 <code><a href="http://developer.android.com/reference/java/lang/NullPointerException.html">java.lang.NullPointerException</a></code> 的更多异常详细信息。(更高版本的 Dalvik 提供 <code><a href="http://developer.android.com/reference/java/lang/ArrayIndexOutOfBoundsException.html">java.lang.ArrayIndexOutOfBoundsException</a></code> 和 <code><a href="http://developer.android.com/reference/java/lang/ArrayStoreException.html">java.lang.ArrayStoreException</a></code> 的更多异常详细信息,现在包括数组大小和超出范围的偏移量。同样,ART 也提供此类信息。)</p>
+<p>当发生运行时异常时,ART 会为您提供尽可能多的上下文和详细信息。ART 会提供 <code><a href="http://developer.android.com/reference/java/lang/ClassCastException.html">java.lang.ClassCastException</a></code>、<code><a href="http://developer.android.com/reference/java/lang/ClassNotFoundException.html">java.lang.ClassNotFoundException</a></code> 和 <code><a href="http://developer.android.com/reference/java/lang/NullPointerException.html">java.lang.NullPointerException</a></code> 的更多异常详细信息。
+(更高版本的 Dalvik 提供 <code><a href="http://developer.android.com/reference/java/lang/ArrayIndexOutOfBoundsException.html">java.lang.ArrayIndexOutOfBoundsException</a></code> 和 <code><a href="http://developer.android.com/reference/java/lang/ArrayStoreException.html">java.lang.ArrayStoreException</a></code> 的更多异常详细信息,这些信息现在包括数组大小和超出范围的偏移量。同样,ART 也提供此类信息。)</p>
-<p>例如,<code><a href="http://developer.android.com/reference/java/lang/NullPointerException.html">java.lang.NullPointerException</a></code> 现在显示有关应用尝试处理 null 指针所进行操作(例如应用尝试写入的字段或尝试调用的方法)的信息。一些典型常见示例如下:</p>
+<p>例如,<code><a href="http://developer.android.com/reference/java/lang/NullPointerException.html">java.lang.NullPointerException</a></code> 现在会显示有关应用尝试处理 null 指针所进行操作(例如应用尝试写入的字段或尝试调用的方法)的信息。一些典型常见示例如下:</p>
<pre class="no-pretty-print">
java.lang.NullPointerException: Attempt to write to field 'int
@@ -87,6 +88,8 @@
<h2 id="Reporting_Problems">报告问题</h2>
-<p>如果您遇到任何并非由应用 JNI 问题导致的问题,请访问 <a href="http://b.android.com">http://b.android.com</a>,通过 Android 开放源代码项目问题跟踪器报告这些问题。请包含 <code>"adb bugreport"</code> 和应用在 Google Play 商店中的链接(如果有)。否则,如果可能,请附加可重现该问题的 APK。请注意,这些问题(包括附件)都是公开可见的。</p>
+<p>如果您遇到任何并非由应用 JNI 问题导致的问题,请通过 <a href="/source/report-bugs#platform">Android 开放源代码项目问题跟踪器</a>报告这些问题。请包含 <code>adb bugreport</code> 和应用在 Google Play 商店中的链接(如果有)。否则,如果可能,请附加可重现该问题的 APK。</p>
+
+<aside class="caution"><strong>提醒</strong>:这些问题(包括附件)都是公开可见的。</aside>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/datausage/tags-explained.html b/zh-cn/devices/tech/datausage/tags-explained.html
index 2f25b96..fee1478 100644
--- a/zh-cn/devices/tech/datausage/tags-explained.html
+++ b/zh-cn/devices/tech/datausage/tags-explained.html
@@ -22,10 +22,11 @@
<p>标签是跟踪流量消耗计数器的指标之一。默认情况下,标签仅以隐性方式基于 UID。UID 被用作监管的基础,不容忽视。因此,标签始终至少代表一个 UID (uid_tag)。可以通过与 UID 关联的“帐号标签”明确增强某个标签。用户空间可以使用 <code>TrafficStats.setThreadStatsTag()</code> 设置标签的 acct_tag 部分,然后将标签与套接字配合使用:属于相应套接字的所有数据都将被计入该标签。之后,监管基于该标签的 uid_tag 部分,并单独收集 acct_tag 部分的统计信息。</p>
<p>如果没有显式标记,则 qtaguid 模块将假设 <code>default_tag: {acct_tag=0, uid_tag=10003}</code></p>
-<pre><code> a: {acct_tag=1, uid_tag=10003}
+<pre class="devsite-click-to-copy">
+ a: {acct_tag=1, uid_tag=10003}
b: {acct_tag=2, uid_tag=10003}
c: {acct_tag=3, uid_tag=10003}
-</code></pre>
+</pre>
<p><code>a, b, c…</code> 表示与特定套接字关联的显式标签。</p>
<p><code>default_tag (acct_tag=0)</code> 是包含相应 uid 的总流量(包括所有未标记的流量)的默认帐号标签,通常用于强制执行监管/配额规则。</p>
<p>这些标签可用于将应用的网络流量划分到独立的逻辑类别中(在网络套接字级别)。可在运行时移除、重新应用或修改这些标签。</p>
diff --git a/zh-cn/devices/tech/debug/eval_perf.html b/zh-cn/devices/tech/debug/eval_perf.html
index 4ae4050..38a0c17 100644
--- a/zh-cn/devices/tech/debug/eval_perf.html
+++ b/zh-cn/devices/tech/debug/eval_perf.html
@@ -42,7 +42,7 @@
<p>特定时间内所需的容量在绝大多数情况下取决于正在运行的应用。因此,平台几乎不能调整特定工作负载所需的容量,调整所用的方式也仅限于运行时改进(Android 框架、ART、Bionic、GPU 编译器/驱动程序、内核)。</p>
<h3 id="jitter">抖动</h3>
-<p>工作负载所需的容量很容易看出来,抖动却是一个比较模糊的概念。有关抖动是快速系统的一种障碍的介绍,请参阅 <em><a href="http://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-UR-03-3116">THE CASE OF THE MISSING SUPERCOMPUTER PERFORMANCE: ACHIEVING OPTIMAL PERFORMANCE ON THE 8,192 PROCESSORS OF ASCl Q</a></em>。(这是一项针对 ASCI Q 超级计算机为何达不到预期性能的调查,同时充分介绍了如何优化大型系统。)</p>
+<p>工作负载所需的容量很容易看出来,抖动却是一个比较模糊的概念。有关抖动是快速系统的一种障碍的详细介绍,请参阅 <em><a href="http://permalink.lanl.gov/object/tr?what=info:lanl-repo/lareport/LA-UR-03-3116">THE CASE OF THE MISSING SUPERCOMPUTER PERFORMANCE: ACHIEVING OPTIMAL PERFORMANCE ON THE 8,192 PROCESSORS OF ASCl Q</a></em>。(这是一项针对 ASCI Q 超级计算机为何达不到预期性能的调查,同时充分介绍了如何优化大型系统。)</p>
<p>本页使用“抖动”这一术语来介绍 ASCI Q 论文中提到的噪点。<em></em>抖动是一种随机的系统行为,会阻止可察觉任务的运行。通常是必须运行的任务,但可能对在任一特定时间运行没有严格的定时要求。因为抖动具有随机性,所以很难证明某一特定工作负载不存在抖动,也很难证明某已知抖动源是导致某个特定性能问题的原因。诊断抖动原因最常用的工具(如跟踪或日志记录)可能会引入它们自己的抖动。</p>
@@ -76,7 +76,7 @@
<ol>
<li>使系统启动到所有驱动程序运行的界面和一些基本的频率调节器设置(如果更改频率调节器设置,请重复以下所有步骤)。</li>
<li>确保内核支持 <code>sched_blocked_reason</code> 跟踪点以及显示通道中指示何时将帧发送到显示屏的其他跟踪点。</li>
-<li>在运行轻量级的一致性工作负载(如 <a href="https://android.googlesource.com/platform/frameworks/base.git/+/master/tests/UiBench/">UiBench</a> 或 <a href="#touchlatency">TouchLatency 中的球测试</a>)的同时,对整个界面通道(从通过 IRQ 接收输入到最终的扫描输出)进行长时间的跟踪。</li>
+<li>在运行轻量级的一致性工作负载(如 <a href="https://android.googlesource.com/platform/frameworks/base.git/+/master/tests/UiBench/">UiBench</a> 或 <a href="#touchlatency">TouchLatency</a> 中的球测试)的同时,对整个界面通道(从通过 IRQ 接收输入到最终的扫描输出)进行长时间的跟踪。</li>
<li>修复在轻量级的一致性工作负载中检测到的帧丢失。</li>
<li>重复执行第 3-4 步,直到您可以在零丢帧的情况下一次运行 20 秒以上的时间。</li>
<li>转向用户可见的其他卡顿源。</li>
@@ -87,8 +87,10 @@
<ul>
<li>确保您的内核有 <a href="https://android.googlesource.com/kernel/msm/+/c9f00aa0e25e397533c198a0fcf6246715f99a7b%5E!/">sched_blocked_reason 跟踪点补丁程序</a>。该跟踪点通过 systrace 中的 sched 跟踪类别启用,并在线程进入不间断休眠时提供负责休眠的函数。它对性能分析非常重要,因为不间断休眠是非常常见的抖动指标。</li>
<li>确保您拥有足够的 GPU 和显示通道的跟踪。在最近的 Qualcomm SOC 上,跟踪点的启用方法是:</li>
-<pre>$ adb shell "echo 1 > /d/tracing/events/kgsl/enable"
-$ adb shell "echo 1 > /d/tracing/events/mdss/enable"</pre>
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb shell "echo 1 > /d/tracing/events/kgsl/enable"</code>
+<code class="devsite-terminal">adb shell "echo 1 > /d/tracing/events/mdss/enable"</code>
+</pre>
<p>运行 systrace 时,这些事件将保持启用状态,以便您在 <code>mdss_fb0</code> 部分的跟踪记录中查看有关显示通道 (MDSS) 的其他信息。在 Qualcomm SOC 上,您无法在 systrace 标准视图下看到有关 GPU 的其他信息,只能看到跟踪记录本身所显示的结果(如需了解详情,请参阅<a href="/devices/tech/debug/systrace.html">了解 systrace</a> 一文)。</p>
diff --git a/zh-cn/devices/tech/debug/fuzz-sanitize.html b/zh-cn/devices/tech/debug/fuzz-sanitize.html
new file mode 100644
index 0000000..f24e41f
--- /dev/null
+++ b/zh-cn/devices/tech/debug/fuzz-sanitize.html
@@ -0,0 +1,35 @@
+<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
+
+ //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>
+模糊测试(仅仅是将可能无效的数据、异常数据或随机数据输入到程序中)是在大型软件系统中查找错误的一种非常有效的方法,也是软件开发生命周期的重要组成部分。
+</p>
+<p>
+LLVM 是用于编译 Android 的编译器基础架构,它包含可执行静态和动态分析的多个组件,其中排错程序可用于消除错误和改进 Android。
+</p>
+<p>
+尽管 Android 的多个版本都支持模糊测试工具,但 Android 8.0 可提供更多模糊测试方面的支持,并可在 Android 编译系统中提供更紧密的模糊测试工具,还能针对 Android 内核提供更有力的动态分析支持。
+</p>
+<p>
+本部分介绍了如何设置和使用各种模糊测试和排错工具。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/debug/index.html b/zh-cn/devices/tech/debug/index.html
index aaee824..c315317 100644
--- a/zh-cn/devices/tech/debug/index.html
+++ b/zh-cn/devices/tech/debug/index.html
@@ -22,9 +22,9 @@
<p>本部分总结了开发平台级功能时,可用于调试、跟踪和分析原生 Android 平台代码的实用工具和相关命令。</p>
-<p class="note"><strong>注意</strong>:本节和本网站其他部分的页面建议您使用 <code>adb</code> 与 <code>setprop</code> 参数一起调试 Android 的某些方面。请注意,在 Android 操作系统的 O 版本之前,属性名称的长度上限为 32 个字符。也就是说,要创建一个包含应用名称的 wrap 属性,您需要截断该名称以使其符合字符数限制。在 Android O 及更高版本中,此字符数上限值要大得多,应该不需要截断。</p>
+<p class="note"><strong>注意</strong>:本部分和本网站其他部分的页面建议您使用 <code>adb</code> 和 <code>setprop</code> 参数一起调试 Android 的某些方面。请注意,在 Android 操作系统的 O 版本之前,属性名称的长度上限为 32 个字符。也就是说,要创建一个包含应用名称的 wrap 属性,您需要截断该名称以使其符合字符数限制。在 Android O 及更高版本中,此字符数上限值要大得多,应该不需要截断。</p>
-<p>本页面介绍了 <code>debuggerd</code> 的用法,debuggerd 是一种用于在应用崩溃后收集错误信息的守护进程。本部分的其他页面介绍了如何通过 <a href="https://developer.android.com/studio/command-line/dumpsys.html">Dumpsys</a> 了解系统服务状况,其中包括查看<a href="/devices/tech/debug/native-memory.html">本地内存</a>、<a href="https://developer.android.com/studio/command-line/dumpsys.html#network">网络</a>和 <a href="https://developer.android.com/studio/command-line/dumpsys.html#procstats">RAM</a> 使用情况、使用 <a href="/devices/tech/debug/asan.html">AddressSanitizer</a> 检测原生代码中的内存错误、评估<a href="/devices/tech/debug/eval_perf.html">性能问题</a>(包括 <a href="/devices/tech/debug/systrace">systrace</a>),以及使用 <a href="/devices/tech/debug/gdb.html">GNU 项目调试程序 (GDB)</a> 和其他调试工具。</p>
+<p>本页面介绍了 <code>debuggerd</code> 的用法,debuggerd 是一种用于在应用崩溃后收集错误信息的守护进程。其他页面介绍了如何通过 <a href="https://developer.android.com/studio/command-line/dumpsys.html"><code>dumpsys</code></a> 了解系统服务状况,其中包括查看<a href="/devices/tech/debug/native-memory.html">本地内存</a>、<a href="https://developer.android.com/studio/command-line/dumpsys.html#network">网络</a>和 <a href="https://developer.android.com/studio/command-line/dumpsys.html#procstats">RAM</a> 使用情况、使用 <a href="/devices/tech/debug/asan.html">AddressSanitizer</a> 检测原生代码中的内存错误、评估<a href="/devices/tech/debug/eval_perf.html">性能问题</a>(包括 <a href="/devices/tech/debug/systrace">systrace</a>),以及使用 <a href="/devices/tech/debug/gdb.html">GNU 项目调试程序 (GDB)</a> 和其他调试工具。</p>
<h2 id="debuggerd">使用 debuggerd</h2>
diff --git a/zh-cn/devices/tech/debug/libfuzzer.html b/zh-cn/devices/tech/debug/libfuzzer.html
new file mode 100644
index 0000000..3bd133a
--- /dev/null
+++ b/zh-cn/devices/tech/debug/libfuzzer.html
@@ -0,0 +1,247 @@
+<html devsite><head>
+ <title>通过 libFuzzer 进行模糊测试</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
+
+ //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>
+模糊测试(只是将可能无效的数据、异常数据或随机数据作为输入内容提供给程序)是在大型软件系统中查找错误的一种非常有效的方式,也是软件开发生命周期的重要组成部分。
+</p>
+<p>
+Android 编译系统通过从 LLVM 编译器基础架构项目纳入 <a href="http://llvm.org/docs/LibFuzzer.html">libFuzzer 项目</a>来支持模糊测试。LibFuzzer 会与被测函数相关联,并会处理在模糊测试会话期间出现的所有输入选择、变更和崩溃报告。LLVM 的排错程序用于协助内存损坏检测以及提供代码覆盖率指标。
+</p>
+<p>
+本文介绍了 Android 上的 libFuzzer 以及如何执行插桩编译,还介绍了如何编写、运行和自定义模糊测试工具。
+</p>
+<h3 id="setup-and-build">设置和编译</h3>
+<p>
+为了确保映像能够在设备上正常运行,请按照以下设置和编译示例进行操作。
+</p>
+<aside class="note"><strong>提示</strong>:要详细了解设置信息,请参阅<a href="/setup/requirements">下载和编译</a>部分。
+请按照说明<a href="/setup/initializing">设置</a>您的编译环境,<a href="/setup/downloading">下载</a>源代码,然后编译 Android(借助 <a href="/setup/building.html#build-the-code">make 命令</a>)。</aside>
+
+<p>使用标准的 Android 编译系统刷写您的设备后,请按照说明刷写 <a href="/devices/tech/debug/asan.html#sanitize_target">AddressSanitizer 编译</a>,然后通过使用 <code>SANITIZE_TARGET='address
+coverage'</code>(而非 <code>SANITIZE_TARGET='address'</code>)来开启覆盖率。
+</p>
+<h4 id="setup-example">设置示例</h4>
+<p>
+本例假设目标设备为 Pixel (<code>sailfish</code>),且已为 USB 调试 (<code>aosp_sailfish-userdebug</code>) 做好准备。
+</p>
+
+<pre class="prettyprint"><code class="devsite-terminal">mkdir ~/bin</code>
+<code class="devsite-terminal">export PATH=~/bin:$PATH</code>
+<code class="devsite-terminal">curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo</code>
+<code class="devsite-terminal">chmod a+x ~/bin/repo</code>
+<code class="devsite-terminal">repo init -u https://android.googlesource.com/platform/manifest -b master</code>
+<code class="devsite-terminal">repo sync -c -j8</code>
+<code class="devsite-terminal">wget https://dl.google.com/dl/android/aosp/google_devices-sailfish-nde63p-c36cb625.tgz</code>
+<code class="devsite-terminal">tar xvf google_devices-sailfish-nde63p-c36cb625.tgz</code>
+<code class="devsite-terminal">extract-google_devices-sailfish.sh</code>
+<code class="devsite-terminal">wget https://dl.google.com/dl/android/aosp/qcom-sailfish-nde63p-50a5f1e0.tgz</code>
+<code class="devsite-terminal">tar xvf qcom-sailfish-nde63p-50a5f1e0.tgz</code>
+<code class="devsite-terminal">extract-qcom-sailfish.sh</code>
+<code class="devsite-terminal">. build/envsetup.sh</code>
+<code class="devsite-terminal">lunch aosp_sailfish-userdebug</code>
+</pre>
+
+<h4 id="build-example">编译示例</h4>
+<p>
+要创建支持可重现模糊测试会话的插桩系统映像,您需要完成具有两个步骤的编译过程。
+</p>
+<p>
+首先,请执行完整的 Android 编译,并将其刷写到设备。接下来,以现有编译为起点,编译 Android 的插桩版本。编译系统要足够复杂,以便只编译所需的二进制文件并将其放在正确的位置。
+</p>
+
+<ol>
+<li>通过执行以下命令来执行初始编译:
+<pre class="devsite-terminal devsite-click-to-copy">make -j$(nproc)</pre></li>
+<li>要刷写设备,请在启动设备后使用<a href="/source/running.html#booting-into-fastboot-mode">相应的键组合</a>进入 fastboot 模式。</li>
+<li>解锁引导加载程序,并使用下列命令刷写新编译的映像(<code>-w</code> 选项可用于擦除用户数据,以确保干净的初始状态)。
+<pre class="prettyprint"><code class="devsite-terminal">fastboot oem unlock</code>
+<code class="devsite-terminal">fastboot flashall -w</code>
+</pre></li>
+<li>执行插桩编译,并将修改后的二进制文件刷写到设备:
+<pre class="prettyprint"><code class="devsite-terminal">make -j$(nproc) SANITIZE_TARGET='address coverage'</code>
+<code class="devsite-terminal">fastboot flash userdata</code>
+<code class="devsite-terminal">fastboot flashall</code></pre>
+</li>
+</ol>
+
+<p>
+目标设备现在应该已经准备好进行 libFuzzer 模糊测试。为了确保您的编译是插桩编译,请将 adb 作为根来检查 <code>/data/asan/lib</code> 是否存在:
+</p>
+
+<pre class="prettyprint"><code class="devsite-terminal">adb root</code>
+<code class="devsite-terminal">adb shell ls -ld /data/asan/lib*
+drwxrwx--x 6 system system 8192 2016-10-05 14:52 /data/asan/lib
+drwxrwx--x 6 system system 8192 2016-10-05 14:52 /data/asan/lib64</code>
+</pre>
+<p>
+常规的非插桩编译中不存在这类目录。
+</p>
+
+<h2 id="write-a-fuzzer">编写模糊测试工具</h2>
+<p>
+为了说明如何在 Android 中使用 libFuzzer 编写端到端的模糊测试工具,请将以下易受攻击的代码作为测试用例。这样做有助于对模糊测试工具进行测试,确保一切运行正常,并说明崩溃数据是什么样的。
+</p>
+<p>
+以下是测试函数。
+</p>
+
+<pre class="prettyprint">#include <stdint.h>
+#include <stddef.h>
+bool FuzzMe(const uint8_t *Data, size_t DataSize) {
+ return DataSize >= 3 &&
+ Data[0] == 'F' &&
+ Data[1] == 'U' &&
+ Data[2] == 'Z' &&
+ Data[3] == 'Z'; // ← Out of bounds access
+}
+</pre>
+
+<p>
+要编译并运行此模糊测试工具,请执行以下操作:</p>
+<ol>
+<li>在 Android 源代码树中创建一个目录,例如,<code>tools/fuzzers/fuzz_me_fuzzer</code>。后续文件都将在此目录下创建。</li>
+<li>使用 libFuzzer 编写模糊测试目标。模糊测试目标是一个函数,该函数可接收指定大小的 blob 数据,并将其传递给要接受模糊测试的函数。以下是针对易受攻击的测试函数的基本模糊测试工具:
+
+<pre class="prettyprint">extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
+ FuzzMe(buf, len);
+ return 0;
+}
+</pre></li>
+<li>指示 Android 的编译系统创建模糊测试工具二进制文件。
+要编译模糊测试工具,请将此代码添加到 <code>Android.mk</code> 文件:
+
+<pre class="prettyprint">LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := fuzz_me_fuzzer.cpp
+LOCAL_CFLAGS += -Wno-multichar -g -O0
+LOCAL_MODULE_TAGS := optional
+LOCAL_CLANG := true
+LOCAL_MODULE:= fuzz_me_fuzzer
+
+Include $(BUILD_FUZZ_TEST)
+</pre>
+<p>
+实现这个目的所需的大部分逻辑都包含在 BUILD_FUZZ_TEST 宏(在 <code>build/core/fuzz_test.mk.</code> 中进行定义)中</p></li>
+
+<li>使用以下代码编译模糊测试工具:
+
+<pre class="devsite-terminal devsite-click-to-copy">make -j$(nproc) fuzz_me_fuzzer SANITIZE_TARGET="address coverage"
+</pre></li>
+</ol>
+<p>
+完成这些步骤之后,您便会得到一个编译好的模糊测试工具。模糊测试工具的默认位置(本例中为 Pixel 编译)为 <code>out/target/product/sailfish/data/nativetest/fuzzers/fuzz_me_fuzzer/fuzz_me_fuzzer</code>
+</p>
+<h2 id="run-your-fuzzer">运行您的模糊测试工具</h2>
+<p>
+编译好模糊测试工具之后,请上传该工具和易受攻击的库以进行关联。</p>
+<ol>
+<li>要将这些文件上传到设备上的某个目录下,请运行以下命令:
+
+<pre class="prettyprint"><code class="devsite-terminal">adb root</code>
+<code class="devsite-terminal">adb shell mkdir -p /data/tmp/fuzz_me_fuzzer/corpus</code>
+<code class="devsite-terminal">adb push $OUT/data/asan/nativetest/fuzzers/fuzz_me_fuzzer/fuzz_me_fuzzer
+ /data/tmp/fuzz_me_fuzzer/</code>
+ </pre>
+</li>
+<li>使用以下命令运行模糊测试工具:
+
+<pre class="devsite-terminal devsite-click-to-copy">adb shell /data/tmp/fuzz_me_fuzzer/fuzz_me_fuzzer /data/tmp/fuzz_me_fuzzer/corpus</pre>
+</li></ol>
+<p>
+执行此操作后,系统将输出类似于下方示例输出的内容。
+</p>
+<aside class="note"><strong>提示</strong>:要详细了解如何读取 libFuzzer 输出,请参阅 <a href="http://llvm.org/docs/LibFuzzer.html">LibFuzzer 文档</a>。
+</aside>
+
+<pre class="prettyprint">
+INFO: Seed: 702890555
+INFO: Loaded 1 modules (9 guards): [0xaaac6000, 0xaaac6024),
+Loading corpus dir: /data/tmp/fuzz_me_fuzzer/corpus
+INFO: -max_len is not provided, using 64
+INFO: A corpus is not provided, starting from an empty corpus
+#0
+READ units: 1
+#1
+INITED cov: 5 ft: 3 corp: 1/1b exec/s: 0 rss: 11Mb
+#6
+NEW cov: 6 ft: 4 corp: 2/62b exec/s: 0 rss: 11Mb L: 61 MS: 1 InsertRepeatedBytes-
+#3008
+NEW cov: 7 ft: 5 corp: 3/67b exec/s: 0 rss: 11Mb L: 5 MS: 1 CMP- DE: "F\x00\x00\x00"-
+#7962
+NEW cov: 8 ft: 6 corp: 4/115b exec/s: 0 rss: 11Mb L: 48 MS: 1 InsertRepeatedBytes-
+#35324
+NEW cov: 9 ft: 7 corp: 5/163b exec/s: 0 rss: 13Mb L: 48 MS: 1 ChangeBinInt-
+=================================================================
+==28219==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xe6423fb3 at pc 0xaaaae938 bp 0xffa31ab0 sp 0xffa31aa8
+READ of size 1 at 0xe6423fb3 thread T0
+#0 0xef72f6df in __sanitizer_print_stack_trace [asan_rtl] (discriminator 1)
+ #1 0xaaab813d in fuzzer::Fuzzer::CrashCallback() external/llvm/lib/Fuzzer/FuzzerLoop.cpp:251
+ #2 0xaaab811b in fuzzer::Fuzzer::StaticCrashSignalCallback() external/llvm/lib/Fuzzer/FuzzerLoop.cpp:240
+ #3 0xef5a9a2b in $a.0 /proc/self/cwd/bionic/libc/arch-arm/bionic/__restore.S:48
+ #4 0xef5dba37 in tgkill /proc/self/cwd/bionic/libc/arch-arm/syscalls/tgkill.S:9
+ #5 0xef5ab511 in abort bionic/libc/bionic/abort.cpp:42 (discriminator 2)
+ #6 0xef73b0a9 in __sanitizer::Abort() external/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc:141
+ #7 0xef73f831 in __sanitizer::Die() external/compiler-rt/lib/sanitizer_common/sanitizer_termination.cc:59
+ #8 0xef72a117 in ~ScopedInErrorReport [asan_rtl]
+ #9 0xef72b38f in __asan::ReportGenericError(unsigned long, unsigned long, unsigned long, unsigned long, bool, unsigned long, unsigned int, bool) [asan_rtl]
+ #10 0xef72bd33 in __asan_report_load1 [asan_rtl]
+ #11 0xaaaae937 in FuzzMe(unsigned char const*, unsigned int) tools/fuzzers/fuzz_me_fuzzer/fuzz_me_fuzzer.cpp:10
+ #12 0xaaaaead7 in LLVMFuzzerTestOneInput tools/fuzzers/fuzz_me_fuzzer/fuzz_me_fuzzer.cpp:15
+ #13 0xaaab8d5d in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned int) external/llvm/lib/Fuzzer/FuzzerLoop.cpp:515
+ #14 0xaaab8f3b in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned int) external/llvm/lib/Fuzzer/FuzzerLoop.cpp:469
+ #15 0xaaab9829 in fuzzer::Fuzzer::MutateAndTestOne() external/llvm/lib/Fuzzer/FuzzerLoop.cpp:701
+ #16 0xaaab9933 in fuzzer::Fuzzer::Loop() external/llvm/lib/Fuzzer/FuzzerLoop.cpp:734
+ #17 0xaaab48e5 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned int)) external/llvm/lib/Fuzzer/FuzzerDriver.cpp:524
+ #18 0xaaab306f in main external/llvm/lib/Fuzzer/FuzzerMain.cpp:20
+ #19 0xef5a8da1 in __libc_init bionic/libc/bionic/libc_init_dynamic.cpp:114
+
+SUMMARY: AddressSanitizer: heap-buffer-overflow
+...
+==28219==ABORTING
+MS: 1 CrossOver-; base unit: 10cc0cb80aa760479e932609f700d8cbb5d54d37
+0x46,0x55,0x5a,
+FUZ
+artifact_prefix='./'; Test unit written to ./crash-0eb8e4ed029b774d80f2b66408203801cb982a60
+Base64: RlVa
+</pre>
+
+<p>
+在示例输出中,崩溃是由第 10 行中的 <code>fuzz_me_fuzzer.cpp</code> 导致的:</p>
+<pre class="prettyprint"> Data[3] == 'Z'; // :(
+</pre>
+<p>
+如果数据长度为 3,则这属于简单的出界读取。
+</p>
+<p>
+运行模糊测试工具后,输出常常会导致系统崩溃,而攻击性输入则会保存到语料库中,并被指定一个 ID。在本示例输出中,ID 为 <code>crash-0eb8e4ed029b774d80f2b66408203801cb982a60</code>。
+</p>
+<p>
+要检索崩溃信息,请运行以下命令(先指定好您的崩溃 ID):</p>
+<pre class="devsite-terminal devsite-click-to-copy">adb pull
+/data/tmp/fuzz_me_fuzzer/corpus/<var>CRASH_ID</var></pre>
+
+<p>
+要详细了解 libFuzzer,请参阅<a href="http://llvm.org/docs/LibFuzzer.html">上游文档</a>。由于 Android 的 libFuzzer 是上游之后的几个版本,请检查 <a href="https://android.googlesource.com/platform/external/llvm/+/master/lib/Fuzzer/">external/llvm/lib/Fuzzer</a> 以确保接口支持您正尝试执行的操作。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/debug/rescue-party.html b/zh-cn/devices/tech/debug/rescue-party.html
new file mode 100644
index 0000000..184b3a3
--- /dev/null
+++ b/zh-cn/devices/tech/debug/rescue-party.html
@@ -0,0 +1,75 @@
+<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>
+很多用户严重依赖他们的手机,需要一台始终可以正常工作的设备。然而,有时设备会陷入重新启动循环僵局,这样,用户便需要提交支持服务单据或保修咨询。这个过程会让用户不舒服,而对于设备制造商和运营商来说,则需要支付高昂的费用。
+</p>
+<p>
+Android 8.0 中纳入了一个功能,当该功能注意到核心系统组件陷入崩溃循环僵局时,就会派出“救援程序”。然后救援程序会通过一系列操作来上报相关情况,以期恢复设备。最后的解决方法是,救援程序使设备重新启动并进入恢复模式,然后提示用户恢复出厂设置。
+</p>
+<p>
+<a href="/compatibility/android-cdd">Android 兼容性定义文档</a>并未要求提供此类救援功能,但此类功能对减少邮件支持记录来说非常有用。
+</p>
+
+<h2 id="implementation">实现</h2>
+<p>
+在 Android 8.0 中,救援程序默认处于启用状态,其实现位于 <code>/services/core/java/com/android/server/RescueParty.java</code> 中。
+在出现以下情况时,救援程序会收到有关启动和崩溃事件的信息,然后即会启动:
+</p>
+<ul>
+ <li>system_server 在 5 分钟内重启 5 次以上。</li>
+ <li>永久性系统应用在 30 秒内崩溃 5 次以上。</li>
+</ul>
+<p>
+当检测到上述某种情况时,救援程序会将其上报给下一救援级别、处理与该级别相关联的任务,并让设备继续运行,看看能否恢复。清除或重置内容的程度随级别而增加。最高级别会提示用户将设备恢复出厂设置。
+</p>
+<p>
+要支持救援程序,无需特别的硬件支持。实现后,设备的恢复系统必须响应 <code>--prompt_and_wipe_data</code> 命令,且设备必须先提供一种方法,让用户确认用户数据是否有任何损坏,然后再继续运行。此外,恢复系统还应为用户提供有关尝试再次启动设备的选项。
+</p>
+<p>
+由于每个救援级别都会使设备再次变为可运行状态的时间延后(可能长达 5 分钟),因此设备制造商不应添加自定义救援级别。设备处于不可运行的状态的时间越长,用户发出支持请求或保修咨询,而不是自行恢复其设备的可能性就越大。
+</p>
+<h2 id="validation">验证</h2>
+<p>
+当设备具有有效的 USB 数据连接时,系统会停止所有救援事件,因为这是一个较强的信号,表示有人正在调试设备。
+</p>
+<p>
+要停止此类抑制行为,请运行:</p>
+
+<pre class="devsite-terminal devsite-click-to-copy">adb shell setprop persist.sys.enable_rescue 1</pre>
+<p>
+在此处,您可以触发系统或界面崩溃循环。
+</p>
+<p>
+要触发低级 <code>system_server</code> 崩溃循环,请运行:</p>
+
+<pre class="devsite-terminal devsite-click-to-copy">adb shell setprop debug.crash_system 1</pre>
+<p>
+要触发中级 SystemUI 崩溃循环,请运行:</p>
+
+<pre class="devsite-terminal devsite-click-to-copy">adb shell setprop debug.crash_sysui 1</pre>
+<p>
+这两个崩溃循环都会启动救援逻辑。所有的救援操作也都会记录到存储在 <code>/data/system/uiderrors.txt</code> 中的永久性的 PackageManager 日志中,以供日后进行检查和调试。
+此外,“软件包警告消息”部分下的每个错误报告中也会包含这些永久性的日志。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/debug/sanitizers.html b/zh-cn/devices/tech/debug/sanitizers.html
new file mode 100644
index 0000000..0747ebd
--- /dev/null
+++ b/zh-cn/devices/tech/debug/sanitizers.html
@@ -0,0 +1,256 @@
+<html devsite><head>
+ <title>LLVM 排错程序</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>
+LLVM 是用于编译 Android 的编译器基础架构,包含可执行静态和动态分析的多个组件。在这些组件中,排错程序(特别是 AddressSanitizer 和 UndefinedBehaviorSanitizer)可以广泛用于分析 Android。排错程序是包含在 external/compiler-rt 中的基于编译器的插桩组件,可用于在开发和测试期间消除错误和改进 Android。Android 目前的排错程序系列可以发现和诊断许多内存滥用错误以及可能危险的未定义行为。
+</p>
+<p>
+Android 编译版本最好在启用排错程序(如 AddressSanitizer 和 UndefinedBehaviorSanitizer)的情况下启动并运行。本页面介绍了 AddressSanitizer、UndefinedBehaviorSanitizer 和 KernelAddressSanitizer,展示了如何在 Android 编译系统中使用它们,并且提供了在启用这些排错程序的情况下编译原生组件的 Android.mk 和 Android.bp 示例文件。
+</p>
+
+<h2 id="addresssanitizer">AddressSanitizer</h2>
+<p>
+<a href="https://clang.llvm.org/docs/AddressSanitizer.html">AddressSanitizer</a> (ASan) 是一种基于编译器的插桩功能,可在运行时检测 C/C++ 代码中许多类型的内存错误。ASan 可以检测许多类别的内存错误,包括:
+</p>
+<ul>
+ <li>出界内存访问</li>
+ <li>双重释放</li>
+ <li>释放后再使用</li>
+</ul>
+<p>
+Android 允许在完整编译级别和在<a href="/devices/tech/debug/asan#addresssanitizer_in_the_apps">应用级别</a>(通过 asanwrapper)进行 <a href="/devices/tech/debug/asan">ASan 插桩</a>。
+</p>
+<p>
+AddressSanitizer 对所有与内存相关的函数调用(包括 alloca、malloc 和 free)进行插桩,并使用被读取或写入时会触发 ASan 回调的内存填充所有变量和已分配的内存区域。
+</p>
+<p>
+这种插桩使 ASan 能够检测无效内存使用错误,包括双重释放以及 UAS (use-after-scope)、UAR (use-after-return) 和 UAF (use-after-free) 错误,而内存区域填充会检测出界读取或写入错误。如果出现对此填充区域的读取或写入操作,则 ASan 会捕获这一情况并输出信息以帮助诊断内存违规行为,包括调用堆栈、影子内存映射、内存违规的类型、读取或写入的内容、导致违规的指令以及内存内容。
+</p>
+
+<pre class="devsite-click-to-copy">
+pixel-xl:/ # sanitizer-status
+=================================================================
+==14164==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x0032000054b0 at pc 0x005df16ffc3c bp 0x007fc236fdf0 sp 0x007fc236fdd0
+WRITE of size 1 at 0x0032000054b0 thread T0
+ #0 0x5df16ffc3b in test_crash_malloc sanitizer-status/sanitizer-status.c:36:13
+ #1 0x5df17004e3 in main sanitizer-status/sanitizer-status.c:76:7
+ #2 0x794cf665f3 in __libc_init (/system/lib64/libc.so+0x1b5f3)
+ #3 0x5df16ffa53 in do_arm64_start (/system/bin/sanitizer-status+0xa53)
+
+0x0032000054b0 is located 0 bytes to the right of 32-byte region [0x003200005490,0x0032000054b0)
+allocated by thread T0 here:
+ #0 0x794d0bdc67 in malloc (/system/lib64/libclang_rt.asan-aarch64-android.so+0x74c67)
+ #1 0x5df16ffb47 in test_crash_malloc sanitizer-status/sanitizer-status.c:34:25
+ #2 0x5df17004e3 in main sanitizer-status/sanitizer-status.c:76:7
+ #3 0x794cf665f3 in __libc_init (/system/lib64/libc.so+0x1b5f3)
+ #4 0x5df16ffa53 in do_arm64_start (/system/bin/sanitizer-status+0xa53)
+ #5 0x794df78893 (<unknown module>)
+
+SUMMARY: AddressSanitizer: heap-buffer-overflow sanitizer-status/sanitizer-status.c:36:13 in test_crash_malloc
+</pre>
+
+<p>
+有时,错误发现过程可能看起来具有不确定性,特别是对于需要特殊设置或更先进技术的错误,例如堆启动或竞态条件利用。许多这样的错误并不能立即显现出来,而且可能需要从成千上万条指令中找出作为真正根本原因的内存违规行为。ASan 对所有与内存相关的函数进行插桩,并为数据填充无法在不触发 ASan 回调的情况下访问的区域。这意味着,内存违规行为一旦出现即被捕获,不用等待出现会导致崩溃的损坏。这在发现错误和诊断根本原因过程中非常有用。
+</p>
+<p>
+为了验证 ASAN 在目标设备上能否正常运行,Android 已经包含了 asan_test 可执行文件。asan_test 可执行文件会测试并验证目标设备上的 ASAN 功能,并提供诊断消息(包括每个测试的状态)。使用 ASAN Android 编译版本时,它默认位于 <code>/data/nativetest/asan_test/asan_test</code> 或 <code>/data/nativetest64/asan_test/asan_test</code> 中。
+</p>
+
+<h2 id="undefinedbehaviorsanitizer">UndefinedBehaviorSanitizer</h2>
+<p>
+UndefinedBehaviorSanitizer (UBSan) 会执行编译时插桩,以检查各种类型的未定义行为。UBSan 能够检测<a href="https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html">许多未定义行为</a>,而 Android 支持 alignment、bool、bounds、enum、float-cast-overflow、float-divide-by-zero、integer-divide-by-zero、nonnull-attribute、null、return、returns-nonnull-attribute、shift-base、shift-exponent、signed-integer-overflow、unreachable、unsigned-integer-overflow 和 vla-bound。虽然 unsigned-integer-overflow 在技术上不是未定义行为,但其包含在排错程序中,并用在许多 Android 模块(包括 mediaserver 组件)中,以消除任何潜在的整数溢出漏洞。
+</p>
+
+<h3 id="ubsan-implementation">实现</h3>
+<p>
+在 Android 编译系统中,您可以全局或局部地启用 UBSan。要全局启用 UBSan,请在 Android.mk 中设置 SANITIZE_TARGET。要在每个模块级别启用 UBSan,请在 Android.mk 中设置 LOCAL_SANITIZE 并指定要查找的未定义行为。例如:
+</p>
+
+<pre class="devsite-click-to-copy">LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0
+
+LOCAL_SRC_FILES:= sanitizer-status.c
+
+LOCAL_MODULE:= sanitizer-status
+LOCAL_MODULE_TAGS := debug
+
+LOCAL_SANITIZE := alignment bounds null unreachable integer
+LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer
+
+include $(BUILD_EXECUTABLE)
+</pre>
+
+<p>
+Android 编译系统尚不支持像对 Makefile 那样在蓝图文件中进行详细诊断。以下是编写为蓝图 (Android.bp) 的最接近等同项:
+</p>
+
+<pre class="devsite-click-to-copy">cc_binary {
+
+ cflags: [
+ "-std=c11",
+ "-Wall",
+ "-Werror",
+ "-O0",
+ ],
+
+ srcs: ["sanitizer-status.c"],
+
+ name: "sanitizer-status",
+ tags: ["debug"],
+
+ sanitize: {
+ misc_undefined: [
+ "alignment",
+ "bounds",
+ "null",
+ "unreachable",
+ "integer",
+ ],
+ diag: {
+ undefined : true
+ },
+ },
+
+}
+</pre>
+
+<h3 id="ubsan-shortcuts">UBSan 快捷方式</h3>
+<p>
+Android 还有两种快捷方式 - <code>integer</code> 和 <code>default-ub</code>,它们可同时启用一组排错程序。integer 会启用<code> integer-divide-by-zero</code>、<code>signed-integer-overflow</code> 和 <code>unsigned-integer-overflow</code>。
+<code>default-ub</code> 会启用编译器性能问题极小的检查:bool、integer-divide-by-zero、return、returns-nonnull-attribute、shift-exponent、unreachable 和 vla-bound。integer 排错程序类可以与 SANITIZE_TARGET 和 LOCAL_SANITIZE 一起使用,而default-ub 只能与 SANITIZE_TARGET 一起使用。
+</p>
+
+<h3 id="better-error-reporting">更好的错误报告</h3>
+<p>
+Android 的默认 UBSan 实现在遇到未定义行为时会调用指定的函数。默认情况下,此函数被中止。但是,从 2016 年 10 月开始,Android 上的 UBSan 有一个可选的运行时库,可以提供更详细的错误报告,包括遇到的未定义行为的类型、文件和源代码行信息。要对 integer 检查启用此错误报告,请将以下内容添加到 Android.mk 文件中:
+</p>
+
+<pre class="devsite-click-to-copy">LOCAL_SANITIZE:=integer
+LOCAL_SANITIZE_DIAG:=integer
+</pre>
+
+<p>
+LOCAL_SANITIZE 值在编译过程中启用排错程序。LOCAL_SANITIZE_DIAG 为指定排错程序开启诊断模式。可以将 LOCAL_SANITIZE 和 LOCAL_SANITIZE_DIAG 设置为不同的值,但系统只启用 LOCAL_SANITIZE 中的检查。如果某个检查未在 LOCAL_SANITIZE 中指定,但在 LOCAL_SANITIZE_DIAG 中指定了,则系统不会启用该检查,且不会提供诊断消息。
+</p>
+<p>
+以下是由 UBSan 运行时库提供的信息示例:
+</p>
+
+<pre class="devsite-click-to-copy">pixel-xl:/ # sanitizer-status ubsan
+sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')
+</pre>
+
+<h2 id="kernel-address-sanitizer">内核地址排错程序</h2>
+<p>
+与针对用户空间组件的基于 LLVM 的排错程序一样,Android 包括内核地址排错程序 (KASAN)。KASAN 是内核与编译时修改的组合,形成了一个插桩系统,可以实现更简单的错误发现和根本原因分析。
+</p>
+<p>
+KASAN 可以检测内核中许多类型的内存违规行为。它还可以检测堆栈、堆和全局变量中的出界读取和写入操作,并可检测释放后再使用和双重释放错误。
+</p>
+<p>
+与 ASAN 一样,KASAN 将编译时内存函数插桩与影子内存相结合,以便跟踪运行时的内存访问。在 KASAN 中,八分之一的内核内存空间专用于影子内存,以确定内存访问是否有效。
+</p>
+<p>
+KASAN 在 x86_64 和 arm64 架构中受支持。自 4.0 以来,它一直是上游内核的一部分,并且已经反向移植到基于 Android 3.18 的内核。KASAN 已在基于 4.9.2 通过 gcc 编译的 Android 内核上进行了测试。
+</p>
+<p>
+除了 KASAN,kcov 是另一个对测试非常有用的内核修改。kcov 旨在允许在内核中进行覆盖率引导模糊测试。它会测量在系统调用输入方面的覆盖率,对于模糊系统(如 <a href="https://github.com/google/syzkaller">syzkaller</a>)非常有用。
+</p>
+
+<h3 id="kasan-implementation">实现</h3>
+<p>
+要在启用 KASAN 和 kcov 的情况下编译内核,请将以下编译标记添加到内核编译配置:
+</p>
+<pre class="devsite-click-to-copy">
+CONFIG_KASAN
+CONFIG_KASAN_INLINE
+CONFIG_TEST_KASAN
+CONFIG_KCOV
+CONFIG_SLUB
+CONFIG_SLUB_DEBUG
+CONFIG_CC_OPTIMIZE_FOR_SIZE
+</pre>
+
+<p>
+并移除以下内容:
+</p>
+<pre class="devsite-click-to-copy">
+CONFIG_SLUB_DEBUG_ON
+CONFIG_SLUB_DEBUG_PANIC_ON
+CONFIG_KASAN_OUTLINE
+CONFIG_KERNEL_LZ4
+</pre>
+<p>
+然后照常编译和刷写内核。KASAN 内核比原始内核大得多。考虑到这一点,请修改任何启动参数和引导加载程序设置(如果适用)。
+</p>
+<p>
+刷写内核后,检查内核启动日志,看看 KASAN 是否已启用并正在运行。内核将启动并显示 KASAN 的内存映射信息,例如:
+</p>
+
+<pre class="devsite-click-to-copy">
+...
+[ 0.000000] c0 0 Virtual kernel memory layout:
+[ 0.000000] c0 0 kasan : 0xffffff8000000000 - 0xffffff9000000000 ( 64 GB)
+[ 0.000000] c0 0 vmalloc : 0xffffff9000010000 - 0xffffffbdbfff0000 ( 182 GB)
+[ 0.000000] c0 0 vmemmap : 0xffffffbdc0000000 - 0xffffffbfc0000000 ( 8 GB maximum)
+[ 0.000000] c0 0 0xffffffbdc0000000 - 0xffffffbdc3f95400 ( 63 MB actual)
+[ 0.000000] c0 0 PCI I/O : 0xffffffbffa000000 - 0xffffffbffb000000 ( 16 MB)
+[ 0.000000] c0 0 fixed : 0xffffffbffbdfd000 - 0xffffffbffbdff000 ( 8 KB)
+[ 0.000000] c0 0 modules : 0xffffffbffc000000 - 0xffffffc000000000 ( 64 MB)
+[ 0.000000] c0 0 memory : 0xffffffc000000000 - 0xffffffc0fe550000 ( 4069 MB)
+[ 0.000000] c0 0 .init : 0xffffffc001d33000 - 0xffffffc001dce000 ( 620 KB)
+[ 0.000000] c0 0 .text : 0xffffffc000080000 - 0xffffffc001d32284 ( 29385 KB)
+...
+</pre>
+
+<p>
+错误将如下所示:
+</p>
+
+<pre class="devsite-click-to-copy">
+[ 18.539668] c3 1 ==================================================================
+[ 18.547662] c3 1 BUG: KASAN: null-ptr-deref on address 0000000000000008
+[ 18.554689] c3 1 Read of size 8 by task swapper/0/1
+[ 18.559988] c3 1 CPU: 3 PID: 1 Comm: swapper/0 Tainted: G W 3.18.24-xxx #1
+[ 18.569275] c3 1 Hardware name: Android Device
+[ 18.577433] c3 1 Call trace:
+[ 18.580739] c3 1 [<ffffffc00008b32c>] dump_backtrace+0x0/0x2c4
+[ 18.586985] c3 1 [<ffffffc00008b600>] show_stack+0x10/0x1c
+[ 18.592889] c3 1 [<ffffffc001481194>] dump_stack+0x74/0xc8
+[ 18.598792] c3 1 [<ffffffc000202ee0>] kasan_report+0x11c/0x4d0
+[ 18.605038] c3 1 [<ffffffc00020286c>] __asan_load8+0x20/0x80
+[ 18.611115] c3 1 [<ffffffc000bdefe8>] android_verity_ctr+0x8cc/0x1024
+[ 18.617976] c3 1 [<ffffffc000bcaa2c>] dm_table_add_target+0x3dc/0x50c
+[ 18.624832] c3 1 [<ffffffc001bdbe60>] dm_run_setup+0x50c/0x678
+[ 18.631082] c3 1 [<ffffffc001bda8c0>] prepare_namespace+0x44/0x1ac
+[ 18.637676] c3 1 [<ffffffc001bda170>] kernel_init_freeable+0x328/0x364
+[ 18.644625] c3 1 [<ffffffc001478e20>] kernel_init+0x10/0xd8
+[ 18.650613] c3 1 ==================================================================
+</pre>
+
+<p>
+此外,如果在内核中启用了模块,则可以加载 test_kasan 内核模块以供进一步测试。该模块会尝试出界内存访问和释放后再使用,有助于在目标设备上测试 KASAN。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/debug/systrace.html b/zh-cn/devices/tech/debug/systrace.html
index 2cff4c6..d0dba1c 100644
--- a/zh-cn/devices/tech/debug/systrace.html
+++ b/zh-cn/devices/tech/debug/systrace.html
@@ -29,7 +29,9 @@
<h2 id="running_systrace">运行 systrace</h2>
<p>要在 Pixel/Pixel XL 上调试抖动问题,请从以下命令开始:</p>
-<pre>$ ./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000</pre>
+<pre class="devsite-terminal devsite-click-to-copy">
+./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000
+</pre>
<p>当将该命令用于 GPU 活动和显示通道活动所需的附加跟踪点时,您将能够跟踪从用户输入直到屏幕上显示的帧。将缓冲区大小设为较大的值,以避免丢失事件(通常表现为一些 CPU 在跟踪记录中的某个点之后不包含任何事件)。</p>
@@ -54,7 +56,7 @@
<p>下面我们详细介绍一下从 15409 毫秒开始的帧:</p>
-<p><img src="images/perf_trace_normal_pipeline.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_normal_pipeline.png"/></p>
<p class="img-caption"><strong>图 1. </strong> 正常界面通道(EventThread 正在运行)。</p>
<p>图 1 显示了一个由多个正常帧围绕的正常帧,因此对于理解界面通道的工作原理来说,它是一个很好的切入点。TouchLatency 的界面线程所在行在不同的时间显示为不同的颜色。柱形表示线程的不同状态:</p>
@@ -72,96 +74,96 @@
<p>要查看不可中断休眠的原因(可从 <code>sched_blocked_reason</code> 跟踪点获取),请选择红色的不可中断休眠图块。</p>
<p>当 EventThread 运行时,TouchLatency 的界面线程会变为可运行。要查看是什么唤醒的它,请点击蓝色部分:</p>
-<p><img src="images/perf_trace_tl.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_tl.png"/></p>
<p class="img-caption"><strong>图 2. </strong> TouchLatency 的界面线程。</p>
<p>图 2 显示了 TouchLatency 的界面线程被与 EventThread 对应的 tid 6843 唤醒。界面线程被唤醒:</p>
-<p><img src="images/perf_trace_wake_render_enqueue.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_wake_render_enqueue.png"/></p>
<p class="img-caption"><strong>图 3. </strong> 界面线程被唤醒、渲染一个帧,并将其加入队列以供 SurfaceFlinger 使用。</p>
<p>如果跟踪记录中的 <code>binder_driver</code> 标记已启用,则您可以选择一个 Binder 事务,并查看该事务涉及的所有进程的相关信息:</p>
-<p><img src="images/perf_trace_binder_trans.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_binder_trans.png"/></p>
<p class="img-caption"><strong>图 4. </strong> Binder 事务。</p>
<p>图 4 显示了在 15423.65 毫秒,SurfaceFlinger 中的 Binder:6832_1 由于 tid 9579(即 TouchLatency 的 RenderThread)变为可运行。此外,您还可以在 Binder 事务的两侧看到 queueBuffer。</p>
<p>在 SurfaceFlinger 端的 queueBuffer 期间,TouchLatency 中待处理帧的数量从 1 变为 2:</p>
-<p><img src="images/perf_trace_pending_frames.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_pending_frames.png"/></p>
<p class="img-caption"><strong>图 5. </strong> 待处理帧从 1 个变为 2 个。</p>
<p>图 5 显示了三重缓冲,其中两个帧已完成渲染,应用将很快开始渲染第三个帧。这是因为一些帧已经丢弃,所以应用保留两个待处理的帧而不是一个,以避免以后再丢弃帧。</p>
<p>稍后,SurfaceFlinger 的主线程会被第二个 EventThread 唤醒,以便它可以将较早的待处理帧输出到显示部分:</p>
-<p><img src="images/perf_trace_sf_woken_et.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_sf_woken_et.png"/></p>
<p class="img-caption"><strong>图 6. </strong> SurfaceFlinger 的主线程被第二个 EventThread 唤醒。</p>
<p>SurfaceFlinger 首先锁定较早的待处理缓冲区,而这将导致待处理缓冲区的计数从 2 减为 1:</p>
-<p><img src="images/perf_trace_sf_latches_pend.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_sf_latches_pend.png"/></p>
<p class="img-caption"><strong>图 7. </strong> SurfaceFlinger 首先锁定较早的待处理缓冲区。</p>
<p>锁定缓冲区后,SurfaceFlinger 会设置构图并将最终帧提交给显示部分(其中某些区段作为 <code>mdss</code> 跟踪点的一部分启用,因此它们可能不在您 SOC 的相应位置上)。</p>
-<p><img src="images/perf_trace_sf_comp_submit.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_sf_comp_submit.png"/></p>
<p class="img-caption"><strong>图 8. </strong> SurfaceFlinger 设置构图并提交最终帧。</p>
<p>接下来,<code>mdss_fb0</code> 在 CPU 0 上被唤醒。<code>mdss_fb0</code> 是显示通道的内核线程,用于将渲染过的帧输出到显示部分。我们可以看到 <code>mdss_fb0</code> 位于跟踪记录中其自己所在行中的情形(向下滚动即可查看)。</p>
-<p><img src="images/perf_trace_wake_cpu0.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_wake_cpu0.png"/></p>
<p class="img-caption"><strong>图 9</strong>. <code>mdss_fb0</code> 在 CPU 0 上被唤醒。</p>
<p><code>mdss_fb0</code> 被唤醒,短暂运行,进入不可中断休眠状态,然后再次被唤醒。</p>
-<p class="note"><strong>注意</strong>:从此时起,跟踪记录将变得更为复杂,因为最后的工作会在 <code>mdss_fb0</code>、中断和工作队列函数之间划分。如果您需要该级别的详细信息,请参阅您的 SOC 的驱动程序堆栈的确切特性(因为了解 Pixel XL 上发生的活动可能对您并无帮助)。</p>
+<p class="note"><strong>注意</strong>:从现在开始,跟踪记录将变得更为复杂,因为最后的工作会在 <code>mdss_fb0</code>、中断和工作队列函数之间划分。如果您需要该级别的详细信息,请参阅您的 SOC 的驱动程序堆栈的确切特性(因为了解 Pixel XL 上发生的活动可能对您并无帮助)。</p>
<h2 id="example_2">示例:非工作帧</h2>
-<p>该示例介绍了用于调试 Pixel/Pixel XL 抖动问题的 systrace。要按照示例操作,请<a href="perf_traces.zip">下载跟踪记录的 ZIP 文件</a>(包括本节中提及的其他跟踪记录),将文件解压缩,然后在浏览器中打开 systrace_tutorial.html 文件。</p>
+<p>该示例介绍了用于调试 Pixel/Pixel XL 抖动问题的 systrace。要按照示例操作,请<a href="/devices/tech/debug/perf_traces.zip">下载跟踪记录的 ZIP 文件</a>(包括本节中提及的其他跟踪记录),将文件解压缩,然后在浏览器中打开 systrace_tutorial.html 文件。</p>
<p>首次打开 systrace 时,您会看到如下内容:</p>
-<p><img src="images/perf_trace_tl_pxl.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_tl_pxl.png"/></p>
<p class="img-caption"><strong>图 10</strong>. 在 Pixel XL 上运行的 TouchLatency(大多数选项已启用,包括 mdss 和 kgsl 跟踪点)。</p>
<p>查找卡顿时,请检查 SurfaceFlinger 下的 FrameMissed 行。FrameMissed 是一项可提升用户体验的改进,由硬件合成器 2 (HWC2) 提供。自 2016 年 12 月起,HWC2 只能用于 Pixel/Pixel XL;当您查看其他设备的 systrace 时,可能不会看到 FrameMissed 行。在任一情况下,FrameMissed 都会与具有以下特点的 SurfaceFlinger 相关联:缺少一个很常用的运行时,以及在 vsync 时的应用 (<code>com.prefabulated.touchlatency</code>) 存在未更改的待处理缓冲区计数:</p>
-<p><img src="images/perf_trace_fm_sf.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_fm_sf.png"/></p>
<p class="img-caption"><strong>图 11</strong>. FrameMissed 与 SurfaceFlinger 的关联。</p>
<p>图 11 显示了 15598.29 毫秒处的已丢失帧。SurfaceFlinger 在 vsync 间隔时间被短暂唤醒,并在未执行任何任务的情况下返回休眠状态,这意味着 SurfaceFlinger 确定不值得再次向显示部分发送帧。为什么?</p>
<p>要了解在渲染此帧时通道是如何出现故障的,请先回顾上面的工作帧示例,了解正常界面通道是如何在 systrace 中出现的。准备就绪后,返回到丢失的帧并进行反推。请注意,SurfaceFlinger 被唤醒后立即进入休眠状态。查看来自 TouchLatency 的待处理帧的数量时,可以看到有两个帧(这是一条很好的线索,可帮助弄清楚发生的实际情况)。</p>
-<p><img src="images/perf_trace_sf_wake_sleep.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_sf_wake_sleep.png"/></p>
<p class="img-caption"><strong>图 12. </strong> SurfaceFlinger 被唤醒后立即进入休眠状态。</p>
<p>因为我们在 SurfaceFlinger 中有一些帧,所以这不是一个应用问题。此外,SurfaceFlinger 在正确的时间被唤醒,所以这也不是一个 SurfaceFlinger 问题。如果 SurfaceFlinger 和应用看起来都正常,那么这可能是一个驱动程序问题。</p>
<p>因为启用了 <code>mdss</code> 和 <code>sync</code> 跟踪点,所以我们可以获得有关相应栅栏(在显示驱动程序和 SurfaceFlinger 之间共享,控制帧实际提交到显示部分的时间)的信息。我们关心的栅栏列于 <code>mdss_fb0_retire</code> 下,它指示帧实际在显示部分出现的时间。这些栅栏作为 <code>sync</code> 跟踪类别的一部分提供。哪些栅栏与 SurfaceFlinger 中的特定事件相对应,取决于您的 SOC 和驱动程序堆栈,因此请与您的 SOC 供应商联系,以了解您的跟踪记录中栅栏类别的含义。</p>
-<p><img src="images/perf_traces_fences.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_traces_fences.png"/></p>
<p class="img-caption"><strong>图 13</strong>. <code>mdss_fb0_retire</code> 栅栏。</p>
<p>图 13 显示的帧显示了 33 毫秒,而不是预期的 16.7 毫秒。图块前进到中途时,该帧应该被新帧替换,但实际上没有。请查看上一帧,看看是否可以找到蛛丝马迹:</p>
-<p><img src="images/perf_trace_frame_previous.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_frame_previous.png"/></p>
<p class="img-caption"><strong>图 14. </strong> 被损坏帧的上一帧。</p>
<p>图 14 显示了时长为 14.482 毫秒的一个帧。被损坏的两帧片段是 33.6 毫秒,这和我们预期的两帧时长大致接近(我们以 60Hz 渲染,每帧 16.7 毫秒,很接近)。但是 14.482 毫秒与 16.7 毫秒相去甚远,这表明显示通道存在严重错误。</p>
<p>调查栅栏的确切结束位置,以确定是什么在控制它:</p>
-<p><img src="images/perf_trace_fence_end.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_fence_end.png"/></p>
<p class="img-caption"><strong>图 15. </strong> 调查栅栏的结束位置。</p>
<p>工作队列包含一个 <code>__vsync_retire_work_handler</code>,它在栅栏发生变化时运行。通过浏览内核源代码,您可以看到它是显示驱动程序的一部分。它显然位于显示通道的关键路径上,所以必须以尽可能快的速度运行。它可运行约 70 微秒(不是很长的调度延迟),但它是一个工作队列,系统可能无法准确地排定其运行时间。</p>
<p>检查上一帧,以确定它是否会导致该问题;有时抖动会随时间而累加,最终导致我们错过最后期限。</p>
-<p><img src="images/perf_trace_previous_frame.png"/></p>
+<p><img src="/devices/tech/debug/images/perf_trace_previous_frame.png"/></p>
<p class="img-caption"><strong>图 16. </strong> 上一帧。</p>
<p>kworker 上的可运行行不可见,因为当该行被选择时,查看器会将它变为白色,不过,通过统计数据,我们可以了解到问题所在:部分显示通道关键路径的 2.3 毫秒调度程序延迟时间<strong>很不乐观</strong>。在执行任何其他操作之前,我们应该先解决该问题,方法是:将显示通道关键路径的这一部分从工作队列(作为 <code>SCHED_OTHER</code> CFS 线程运行)移动到专用的 <code>SCHED_FIFO</code> kthread。这一功能需要时间保证,而工作队列不能(也不打算)提供这一保证。</p>
diff --git a/zh-cn/devices/tech/debug/valgrind.html b/zh-cn/devices/tech/debug/valgrind.html
index 94ac00e..971790a 100644
--- a/zh-cn/devices/tech/debug/valgrind.html
+++ b/zh-cn/devices/tech/debug/valgrind.html
@@ -22,20 +22,20 @@
<p><a href="http://valgrind.org/">Valgrind</a> 工具套件包括 Memcheck(用于检测 C 和 C ++ 中与内存相关的错误)、Cachegrind(缓存分析器)、Massif(堆分析器)和其他几种工具。</p>
-<p class="note"><strong>注意</strong>:尽管您可以使用 Valgrind 对 Android 进行调试,但大多数 Android 平台开发人员都会使用 <a href="/devices/tech/debug/asan.html">AddressSanitizer</a>。</p>
+<p class="note"><strong>注意</strong>:尽管您可以使用 Valgrind 对 Android 进行调试,但大多数 Android 平台开发者会改用 <a href="/devices/tech/debug/asan.html">AddressSanitizer</a>。</p>
<h2 id="build-valgrind">构建 Valgrind</h2>
<p>要构建 Valgrind,请运行以下命令:</p>
-<pre class="no-pretty-print">
-$ mmma -j6 external/valgrind
+<pre class="devsite-terminal devsite-click-to-copy">
+mmma -j6 external/valgrind
</pre>
<h2 id="app-valgrind">在应用上使用</h2>
<p>要在某个应用上使用 Valgrind,请运行以下命令:</p>
-<pre class="no-pretty-print">
-$ adb shell setprop wrap.<em>app_name</em> "logwrapper valgrind"
-$ adb shell am start -a android.intent.action.MAIN -n <em>app_name</em>/.MainActivity
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb shell setprop wrap.<em>app_name</em> "logwrapper valgrind"</code>
+<code class="devsite-terminal">adb shell am start -a android.intent.action.MAIN -n <em>app_name</em>/.MainActivity</code>
</pre>
<code><em>app_name</em></code> 必须是一个完全符合要求的名称,例如 <strong>com.google.example_app</strong>。
@@ -43,23 +43,23 @@
<h2 id="server-valgrind">在系统服务器上使用</h2>
<p>要使用 Valgrind 运行系统服务器,请运行以下命令:</p>
-<pre class="no-pretty-print">
-$ adb shell setprop wrap.system_server "logwrapper valgrind"
-$ adb shell stop && adb shell start
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb shell setprop wrap.system_server "logwrapper valgrind"</code>
+<code class="devsite-terminal">adb shell stop && adb shell start</code>
</pre>
<h2 id="symbols-valgrind">获取调试符号</h2>
<p>要获取调试符号,请将未剥离的库推送到 <code>/data/local/symbols</code>:</p>
-<pre class="no-pretty-print">
-$ adb shell mkdir /data/local/symbols
-$ adb push $OUT/symbols /data/local/symbols
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">adb shell mkdir /data/local/symbols</code>
+<code class="devsite-terminal">adb push $OUT/symbols /data/local/symbols</code>
</pre>
<h2 id="boot-valgrind">在启动过程中使用</h2>
<p>要在启动过程中使用 Valgrind,请修改 <code>out/target/product/XXXX/root/init.rc</code>,具体方法是将</p>
-<p><code>service example /system/bin/foo --arg1 --arg2</code></p>
+<pre class="devsite-click-to-copy">service example /system/bin/foo --arg1 --arg2</pre>
<p>更改为:</p>
-<p><code>service example /system/bin/logwrapper /system/bin/valgrind /system/bin/foo --arg1 --arg2</code></p>
+<pre class="devsite-click-to-copy">>service example /system/bin/logwrapper /system/bin/valgrind /system/bin/foo --arg1 --arg2</pre>
<p>要查看效果,请创建一个 <code>boot.img</code> 并重新刷入设备。</p>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/display/adaptive-icons.html b/zh-cn/devices/tech/display/adaptive-icons.html
new file mode 100644
index 0000000..c28254b
--- /dev/null
+++ b/zh-cn/devices/tech/display/adaptive-icons.html
@@ -0,0 +1,108 @@
+<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>
+如果开发者仅提供一个图标素材资源,自适应图标的形状在设备内会保持一致,但在设备之间会有所差异。此外,图标支持可用于实现动作的两个层(前台和后台),以便为用户提供愉悦的视觉体验。
+ </p>
+ <p>
+设备实现人员会提供一个设备遮罩,该遮罩将决定设备上所有图标的形状。该图标将在任何使用启动器图标(例如,启动器、概览、设置和分享表单)的系统界面上使用。
+ </p>
+ <h2 id="examples-and-source">示例和源代码</h2>
+ <p>
+代码示例:</p><ul>
+ <li><code>platform/development/samples/AdaptiveIconSample/</code></li></ul>
+ <p>
+
+开发者文档:
+ </p><ul>
+ <li><a href="https://developer.android.com/preview/features/adaptive-icons.html">https://developer.android.com/preview/features/adaptive-icons.html</a>
+ </li><li><a href="https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html">https://developer.android.com/reference/android/graphics/drawable/AdaptiveIconDrawable.html</a>
+ </li><li><a href="https://developer.android.com/reference/android/graphics/drawable/Icon.html#createWithAdaptiveBitmap(android.graphics.Bitmap)">https://developer.android.com/reference/android/graphics/drawable/Icon.html#createWithAdaptiveBitmap(android.graphics.Bitmap)</a></li></ul>
+ <p>
+
+源代码:
+ </p><ul>
+ <li><code>platform/frameworks/base/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java</code></li></ul>
+ <h2 id="implementation">实现</h2>
+ <p>
+要更改平台上图标的形状,请替换 <code>framework/base/core/res/res/values/config.xml</code> 中的一个字符串,如下所示:</p>
+
+ <pre class="prettyprint"><!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
+ <string name="config_icon_mask" translatable="false">"M50,0L100,0 100,100 0,100 0,0z"</string></pre>
+ <p>
+该字符串的格式和语法均遵循<a href="https://www.w3.org/TR/SVG/paths.html">路径定义的 W3-SVG 标准</a>。Android 矢量可绘制资源也支持 PathData 的这种格式。
+ </p>
+ <p>
+这个路径应该是上凸的,且应考虑视图边界范围内的安全区 (66/71 = 91%)。此要求在其中一项 CTS 测试中强制执行。
+ </p>
+ <p>
+如果您决定使用圆形作为平台遮罩,请确保也要替换 config_useRoundIcon = true。否则,请将此配置值设为 false 或不指定此配置值。
+ </p>
+ <h2>自适应图标 API</h2>
+ <p>
+<code>AdaptiveIconDrawable</code> 类的 API 如下所示:</p>
+
+ <pre class="prettyprint">package android.graphics.drawable;
+ public class AdaptiveIconDrawable extends Drawable implements Drawable.Callback {
+ method public Drawable getBackground();
+ method public Drawable getForeground();
+ method public Path getIconMask();
+ method public Region getSafeZone();
+ method public float getExtraInsetFraction();
+ method public int getOpacity();
+ method public void invalidateDrawable(Drawable);
+ method public void scheduleDrawable(Drawable, Runnable, long);
+ method public void setAlpha(int);
+ method public void setColorFilter(ColorFilter);
+ method public void setOpacity(int);
+ method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+ }</pre>
+
+ <pre class="prettyprint">public class Icon extends Parceleable {
+ method public Bitmap createWithAdaptiveBitmap();
+ }</pre>
+ <h2>参考实现</h2>
+ <p>
+无需执行任何操作,即可在任何系统界面上呈现静态自适应图标。当 PackageManager 返回可绘制资源时,只需将它绑定到 ImageView 即可。这就是图标在 Android O 之前版本的平台上呈现的方式。
+ </p>
+ <p>
+关于如何呈现动态动画效果,Launcher3 (platform/packages/apps/Launcher3) 中会提供相应的参考实现来说明如何在 O-MR1 中实现这种效果。
+ </p>
+ <h2 id="validation">验证</h2>
+ <p>
+要验证实现,请在替换其需要的遮罩后,查看图标是否可以在 Launcher3、设置、概览和设置中正确呈现。此外,您还可以在图形 CTS TestCase 中运行 AdaptiveIconDrawableTest.java 和 AdaptiveIconMaskTest.java 来测试实现。
+ </p>
+ <p>
+推荐的手动测试用例可以在以下位置找到:platform/development/samples/AdaptiveIconSample/。
+ </p>
+ <h2>已知问题</h2>
+ <p>
+已知问题包括:</p><ul>
+ <li>图标模糊(取决于遮罩路径的定义方式)。
+ </li><li>快捷方式图标被放大(如果应用开发者未使用 <code>Icon.createWithAdaptiveBitmap()</code> 方法或未正确使用此方法)。为使此方法正常发挥作用,如果图标是以位图形式传递的,则图标的四边应各保留 25% 的内边距。</li></ul>
+ <p>
+这些问题可以通过以下方式解决:</p><ul>
+ <li>应在 [0,100] x [0,100] 坐标系中定义遮罩。
+ </li><li>确保用于自适应图标(启动器图标、快捷方式)的图片的四边均保留了充足的内边距 (25%)。</li></ul>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/display/app-shortcuts.html b/zh-cn/devices/tech/display/app-shortcuts.html
index 4e51a52..4f9c418 100644
--- a/zh-cn/devices/tech/display/app-shortcuts.html
+++ b/zh-cn/devices/tech/display/app-shortcuts.html
@@ -39,7 +39,8 @@
<p>您可以在以下文件中找到此功能的主要实现方式:</p>
-<pre>frameworks/base/services/core/java/com/android/server/policy/ShortcutManager.java
+<pre class="devsite-click-to-copy">
+frameworks/base/services/core/java/com/android/server/policy/ShortcutManager.java
frameworks/base/services/core/java/com/android/server/pm/ShortcutPackage.java
frameworks/base/services/core/java/com/android/server/pm/ShortcutUser.java
frameworks/base/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -58,7 +59,7 @@
<p>
以下文件可提供支持功能(在 <code>ShortcutManager.java</code> 中称为隐藏 API):</p>
-<pre>
+<pre class="devsite-click-to-copy">
packages/apps/Settings/src/com/android/settings/DevelopmentSettings.java
frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
</pre>
@@ -67,7 +68,7 @@
另外,Android 开放源代码项目启动器版本 3 支持以下快捷方式:
</p>
-<pre>
+<pre class="devsite-click-to-copy">
packages/apps/Launcher3/
</pre>
@@ -75,7 +76,8 @@
最后,有关公共 Javadoc,请查看以下文件:
</p>
-<pre>frameworks/base/core/java/android/content/pm/ShortcutManager.java
+<pre class="devsite-click-to-copy">
+frameworks/base/core/java/android/content/pm/ShortcutManager.java
frameworks/base/core/java/android/content/pm/ShortcutInfo.java
frameworks/base/core/java/android/content/pm/LauncherApps.java
</pre>
@@ -106,7 +108,7 @@
<p>
使用以下 Android 兼容性测试套件 (CTS) 测试来确保您的功能(ShortcutManager 和 LauncherApps)版本可以正常运行:</p>
-<pre>
+<pre class="devsite-click-to-copy">
cts/tests/tests/shortcutmanager/
cts/hostsidetests/shortcuts/
</pre>
@@ -114,19 +116,21 @@
<p>
请在以下位置查找用于实现 AOSP 的单元测试:</p>
-<pre>frameworks/base/services/tests/servicestests/
+<pre class="devsite-click-to-copy">
+frameworks/base/services/tests/servicestests/
</pre>
<p>
其中包括:</p>
-<pre>src/com/android/server/pm/ShortcutManagerTest*.java
+<pre class="devsite-click-to-copy">
+src/com/android/server/pm/ShortcutManagerTest*.java
</pre>
<p>
-您还可以针对快捷方式管理器采用 CTS Verifier 测试:
+您还可以针对快捷方式管理器部署 CTS 验证程序测试:
</p>
-<pre>
+<pre class="devsite-click-to-copy">
cts/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ShortcutThrottlingResetActivity.java
</pre>
diff --git a/zh-cn/devices/tech/display/color-mgmt.html b/zh-cn/devices/tech/display/color-mgmt.html
new file mode 100644
index 0000000..f6c3bcf
--- /dev/null
+++ b/zh-cn/devices/tech/display/color-mgmt.html
@@ -0,0 +1,87 @@
+<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>Android 8.1 新增了对颜色管理功能的支持,此功能可用于在采用不同显示技术的设备间提供一致的体验。在 Android 8.1 上运行的应用可以访问广色域显示屏的所有功能,以便充分利用显示设备。</p>
+
+<p>之前的 Android 版本不支持颜色管理功能,而是依赖于内容和显示屏之间的兼容性(这个目标通常需要借助电视行业的帮助才能得以实现)。不过,最新的显示技术可让不能按预期显示现有内容的显示屏具有更广的色域。在使用 Android 8.1 时,采用广色域显示屏(例如有机发光二极管有源阵列或 AMOLED 及某些 LCD)的设备将能够从应用中查看到广色域内容。</p>
+
+<h2>确定设备支持</h2>
+<p>运行 Android 8.1 且采用广色域显示屏的设备应支持颜色管理(广色域)。在启用这项功能之前,请确保设备符合以下要求:</p>
+<ul>
+<li>设备显示屏符合硬件要求,其中包括可支持 Display-P3 颜色空间的性能良好的显示屏。如果显示屏不符合此要求,请勿启用颜色管理。为了降低 CPU 和 GPU 影响,有必要在显示通道中支持扩展的 sRGB 和 HDR10。</li>
+<li>设备支持出厂校准流程,该流程可生成校准数据(存储在设备上)来调整显示行为中的制造差异。校准数据至少应允许显示屏准确显示 sRGB 内容以及 D65 和 D73 白点(Android 的后续版本可能会针对每个设备支持完整 ICC 配置文件)。</li>
+</ul>
+<p>如果满足上述要求,您就可以为设备启用颜色管理功能。</p>
+
+<h2>实现颜色管理</h2>
+<p>要实现颜色管理,您必须先更新 <a href="/devices/graphics/implement-hwc">Hardware Composer 2 (HWC2)</a> 驱动程序,以便了解颜色模式并将这些模式应用到硬件。具体而言,HWC2 制作程序必须使用 <code>HWCDisplay::GetColorModes</code> 报告 Display-P3 和 sRGB 颜色模式。</p>
+
+<aside class="key-term"><strong>关键术语:</strong>Display-P3 使用数字电影院线联盟基元和 sRGB 传输功能。</aside>
+
+<p>接下来,启用必需的 OpenGL 扩展程序和库支持,以将 OpenGL 颜色空间转换为 HAL 数据空间。必需的 OpenGL 扩展程序包括:</p>
+<ul>
+<li>
+<a href="https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_pixel_format_float.txt" class="external">EGL_EXT_pixel_format_float</a>。允许应用使用 16 位浮点颜色组件创建可呈现的 EGLSurface。优先级:高(建议将这项作为宽色域感知应用的默认像素格式)。需要驱动程序支持。</li>
+<li>
+<a href="https://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_gl_colorspace.txt" class="external">EGL_KHR_gl_colorspace</a>。对于需要使用 sRGB 格式默认帧缓冲区来轻松实现显示设备的 sRGB 渲染的应用,此扩展程序允许创建将由支持该功能的 OpenGL 上下文采用 sRGB 格式进行渲染的 EGLSurface。需要驱动程序支持 sRGB 行为。</li>
+</ul>
+<p>Android 还提供以下可选的扩展程序:</p>
+<ul>
+<li>
+<a href="https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_gl_colorspace_scrgb_linear.txt" class="external">EGL_EXT_colorspace_scrgb_linear</a>。该扩展程序可提供一个新的颜色空间选项 (scRGB),供应用在创建 EGLSurface 时进行选择。scRGB 颜色空间可定义与 sRGB 具有相同白点和颜色基准(以便与 sRGB 向后兼容)的线性显示引用空间。此扩展程序应该不需要驱动程序支持,而且可以在 Android EGL 封装容器中实现。为了正常发挥作用,此扩展程序需支持 16 位浮点 (FP16)。</li>
+<li>
+<a href="https://github.com/KhronosGroup/EGL-Registry/pull/10/files" class="external">EGL_KHR_gl_colorspace_display_p3
+和 EGL_EXT_gl_colorspace_display_p3_linear</a>。对于需要使用 Display-P3 格式默认帧缓冲区来轻松实现显示设备的 sRGB 渲染的应用,此扩展程序允许创建将由支持该功能的 OpenGL 上下文采用 Display-P3 格式进行渲染的 EGLSurface。此扩展程序可以在 EGL 驱动程序封装容器中实现。</li>
+<li>
+<a href="https://www.khronos.org/registry/vulkan/specs/1.0-extensions/html/vkspec.html#VK_EXT_swapchain_colorspace" class="external">VK_EXT_swapchain_colorspace</a> (Vulkan)。可让应用通过它们正在使用的颜色空间来标记交换链。包括一些常见颜色空间,例如 DCI-P3、Display-P3、AdobeRGB、BT2020 等。</li>
+</ul>
+
+<h2>自定义</h2>
+<p>您可以通过提供对各种颜色标准(例如 DCI-P3、AdobeRGB、Rec709、Rec2020)的支持来自定义颜色管理功能。其他自定义项包括:</p>
+<ul>
+<li><strong>针对显示通道中颜色转换的硬件支持</strong>。在硬件中支持多种颜色转换。
+</li>
+<li><strong>支持在多个图层上进行独立的颜色转换</strong>(例如,某些图层可以是 sRGB,其他图层是扩展的 sRGB,每个图层都具有自己的颜色管道)。如果有多个颜色空间可见时,需要将某些颜色空间转换为显示屏的颜色空间。理想情况下,此转换最好由显示引擎提供(否则 Android 必须执行 GPU 合成)。</li>
+</ul>
+
+<h2>测试</h2>
+<p>要测试颜色管理,请使用 <code>opengl/tests</code> 中的以下资源:</p>
+<ul>
+<li><code>gl2_basic</code>。用于请求 Display-P3 颜色空间的简单 OpenGL 演示。</li>
+<li><code>
+<a href="https://android.googlesource.com/platform/frameworks/native/+/master/opengl/tests/EGLTest/EGL_test.cpp">EGL_test</a></code>。测试必要的扩展程序和配置支持(10:10:10:2 和 FP16)。</li>
+<li><code>test_wide_color</code>。以与 SurfaceFlinger 创建 surface 的方式相同的方式创建 surface(例如配置、颜色空间、像素格式)。</li>
+</ul>
+
+<h2>参考实现</h2>
+<p>有关参考实现,请参阅 <code>frameworks/native</code>。有关标题,请参阅:</p>
+<ul>
+<li>
+<code><a href="https://android.googlesource.com/platform/system/core/+/master/libsystem/include/system/graphics.h">system/core/include/system/graphics.h</a></code></li>
+<li>
+<code><a href="https://android.googlesource.com/platform/system/core/+/master/libsystem/include/system/graphics-base.h">system/core/include/system/graphics-base.h</a></code><ul>
+<li><code>HAL_DATASPACE_*</code></li>
+<li><code>HAL_COLOR_MODE_*</code></li>
+</ul>
+</li>
+</ul>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/display/night-light.html b/zh-cn/devices/tech/display/night-light.html
index b2d0a11..242bbcc 100644
--- a/zh-cn/devices/tech/display/night-light.html
+++ b/zh-cn/devices/tech/display/night-light.html
@@ -24,11 +24,12 @@
研究表明,屏幕的蓝光会对睡眠质量造成不良影响。Android 7.1.1 具备一种称为“夜间模式”的功能,可减少设备显示屏发出的蓝光量,以便达到更接近用户当前时间和地点的自然光效果。Android 8.0 提供一项功能,可让用户更好地控制夜间模式效果的强度。
</p>
<p>
-夜间模式需要实现 <a href="/devices/graphics/implement-hwc.html">Hardware Composer HAL 2.0</a> (HWC 2),它可应用传递到 <code>setColorTransform</code> 的矩阵以执行着色,而不会影响耗电量、性能和应用兼容性。
+夜间模式需要实现 <a href="/devices/graphics/implement-hwc.html">Hardware Composer HAL 2.0</a> (HWC 2),它可根据传递到 <code>setColorTransform</code> 的矩阵来执行着色,而不会影响耗电量、性能和应用兼容性。
</p>
<h2 id="implementation">实现</h2>
<p>
-设备制造商可以使用以下路径中定义的下列标记来启用该功能的默认实现:<code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/config.xml">
+设备制造商可以使用以下路径中定义的下列标记来启用该功能的默认实现:
+<code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/config.xml">
/android/frameworks/base/core/res/res/values/config.xml</a></code>
</p><pre class="devsite-click-to-copy">
@@ -95,7 +96,7 @@
<h2 id="ui-features">界面功能</h2>
<p>
-由于夜间模式是面向用户的功能,因此用户需要能够掌控这项功能。Android 开放源代码项目 (AOSP) <a href="https://android.googlesource.com/platform/packages/apps/Settings/">packages/apps/Settings</a> 项目中提供了全面的设置实现方法,以供设备制造商在实现其设置时参考。实现人员必须处理 <code><a href="https://developer.android.com/reference/android/provider/Settings.html#ACTION_NIGHT_DISPLAY_SETTINGS">Settings.ACTION_NIGHT_DISPLAY_SETTINGS</a></code> intent 才能显示此设置。
+由于夜间模式是面向用户的功能,因此用户需要能够掌控这项功能。Android 开源项目 (AOSP) 的 <a href="https://android.googlesource.com/platform/packages/apps/Settings/">packages/apps/Settings</a> 项目中提供了全面的设置实现方法,以供设备制造商在实现其设置时参考。实现人员必须处理 <code><a href="https://developer.android.com/reference/android/provider/Settings.html#ACTION_NIGHT_DISPLAY_SETTINGS">Settings.ACTION_NIGHT_DISPLAY_SETTINGS</a></code> intent 才能显示此设置。
</p>
<h3 id="settings">设置</h3>
<p>
@@ -119,7 +120,7 @@
</p>
<h3 id="quick-settings-tile">“快捷设置”图块</h3>
<p>
-您可以通过“快捷设置”图块执行相应操作,也可以通过“设置”>“显示”>“夜间模式”中的<strong>开启/关闭</strong>切换开关执行相应操作,两者效果是一样的。<em></em>
+用户可以通过“快捷设置”图块执行相应操作,也可以通过“设置”>“显示”>“夜间模式”中的<strong>开启/关闭</strong>切换开关执行相应操作,两者效果是一样的。<em></em>
</p>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/display/pip.html b/zh-cn/devices/tech/display/pip.html
new file mode 100644
index 0000000..b9f6824
--- /dev/null
+++ b/zh-cn/devices/tech/display/pip.html
@@ -0,0 +1,95 @@
+<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>
+Android 8.0 支持在 Android 手持设备上使用画中画 (PIP) 功能。借助画中画功能,用户可以将有正在进行的活动的应用调整到一个小窗口中。画中画对视频应用来说尤其有用,因为用户可以随时执行其他操作,而不会打断内容播放。用户可以通过 SystemUI 操控该窗口的位置,并通过应用提供的操作(最多三项)与当前处于画中画模式的应用流畅地互动。
+</p>
+<p>
+有关详情,请参阅 Android 开发者<a href="https://developer.android.com/training/tv/playback/picture-in-picture.html">画中画</a>文档。
+</p>
+
+<h2 id="overview">概览</h2>
+<p>画中画功能需要在支持它的应用中明确选择启用,并按 Activity 运作(一个应用可以有多个 Activity ,但其中只有一个可处于画中画模式)。Activity 通过调用 <code>enterPictureInPictureMode()</code> 来请求进入画中画模式,并以 <code>onPictureInPictureModeChanged()</code> 的形式接收 Activity 回调。
+</p>
+<p>
+Android 8.0 中新增了更多方法,包括 <code>setPictureInPictureParams()</code>,借助这种方法,Activity 可以控制其在画中画模式下的宽高比和自定义操作,这样一来,用户无需展开 Activity 便可以与之互动。在画中画中,Activity 处于暂停但继续呈现的状态,并且不直接接收触摸输入或窗口焦点。在同一时间点,只能有一项任务处于画中画模式。
+</p>
+<h2 id="device-requirements">设备要求</h2>
+<p>
+要支持画中画功能,请在 <code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/content/pm/PackageManager.java">/android/frameworks/base/core/java/android/content/pm/PackageManager.java</a></code> 中启用 <code>PackageManager#FEATURE_PICTURE_IN_PICTURE</code> 系统功能。
+支持画中画功能的设备的最小屏幕宽度必须大于 220dp。与分屏多窗口类似,画中画支持多个 Activity 同时在屏幕上运行。因此,设备的 CPU 和 RAM 要足以支持这类使用情形。
+</p>
+<h2 id="implementation">实现</h2>
+<p>
+大多数 Activity 生命周期管理都是由系统的 <code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/am/">ActivityManager</a></code> 和 <code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/wm/">WindowManager</a></code> 组件协作完成的。
+相应的参考界面实现位于 <code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/">SystemUI</a></code> 软件包中。
+</p>
+
+<p>
+对系统所做的修改不应影响其内在行为(如<a href="#cts-tests">兼容性测试套件 (CTS) 测试</a>中所定义)。画中画的系统逻辑主要围绕“置顶”堆栈中的任务和 Activity 管理而展开。以下是对系统逻辑类的简单介绍:
+</p>
+<ul>
+ <li><strong><code>ActivityRecord</code></strong>:跟踪每个 Activity 的画中画状态。为了防止用户在某些情况下(例如从锁定屏幕或在观看 VR 视频期间)进入画中画,请向 <code>checkEnterPictureInPictureState()</code> 添加用例。</li>
+ <li><strong><code>ActivityManagerService</code></strong>:Activity 在请求进入画中画模式时所调用的主接口,也是 <code>WindowManager</code> 和 <code>SystemUI</code> 在更改画中画 Activity 状态时所调用的接口。</li>
+ <li><strong><code>ActivityStackSupervisor</code></strong>:从 <code>ActivityManagerService</code> 调用,以向置顶堆栈移入任务或从中移出任务,必要时会更新 <code>WindowManager</code>。</li>
+ <li><strong><code>PinnedStackWindowController</code></strong>:来自 <code>ActivityManager</code> 的 <code>WindowManager</code> 接口。</li>
+ <li><strong><code>PinnedStackController</code></strong>:将系统中的变化告知 <code>SystemUI</code>,例如 IME 显示/隐藏、宽高比变化、操作变化。</li>
+ <li><strong><code>BoundsAnimationController</code></strong>:以调整大小时不触发配置更改的方式,对画中画 Activity 窗口进行动画处理。</li>
+ <li><strong><code>PipSnapAlgorithm</code></strong>:系统和 SystemUI 中使用的共享类,可控制屏幕边缘附近的画中画窗口的贴靠行为。</li>
+</ul>
+
+<p>
+参考 <code><a href="https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/">SystemUI</a></code> 中提供了画中画功能的完整实现(支持向用户呈现自定义操作并执行展开和关闭等常规操控)。
+设备制造商可以在该实现的基础上做进一步的开发,只要所做更改不影响 CDD 所定义的内在行为即可。以下是对相关类的简单介绍:</p>
+<ul>
+ <li><strong><code>PipManager</code></strong>:随 <code>SystemUI</code> 启动的 <code>SystemUI</code> 组件。</li>
+ <li><strong><code>PipTouchHandler</code></strong>:触摸处理程序,用于控制操纵画中画窗口的手势。仅在画中画的输入使用方处于活动状态时使用(请参阅 <code>InputConsumerController</code>)。在此处理程序中可添加新手势。</li>
+ <li><strong><code>PipMotionHelper</code></strong>:一个辅助类,用于跟踪画中画位置和屏幕上允许的区域。通过这个类调用 <code>ActivityManagerService</code> 可更新或调整画中画的位置和大小。</li>
+ <li><strong><code>PipMenuActivityController</code></strong>:用于启动一个 Activity,以便显示当前画中画中的 Activity 提供的操作。所启动的 Activity 属于任务叠加层 Activity,会移除上层的输入使用方,以使自身进入可互动状态。</li>
+ <li><strong><code>PipMenuActivity</code></strong>:菜单 Activity 的实现。</li>
+ <li><strong><code>PipMediaController</code></strong> :当媒体会话的变化可能会影响画中画上的默认操作时更新 <code>SystemUI</code> 的侦听器。</li>
+ <li><strong><code>PipNotificationController</code></strong>:确保在用户使用画中画功能时显示一条处于活动状态的通知的控制器。</li>
+ <li><strong><code>PipDismissViewController</code></strong>:当用户开始与画中画进行互动时向用户显示的叠加层,提示用户可以关闭画中画。</li>
+</ul>
+<h2 id="default-placement">默认显示位置</h2>
+<p>
+用于控制画中画的默认显示位置的系统资源有多项:
+</p>
+<ul>
+ <li><strong><code>config_defaultPictureInPictureGravity</code></strong>:<a href="https://developer.android.com/reference/android/view/Gravity.html">gravity</a> 整数,可控制放置画中画的角落,如 <code>BOTTOM|RIGHT</code>。</li>
+ <li><strong><code>config_defaultPictureInPictureScreenEdgeInsets</code></strong>:画中画的放置位置相对于屏幕侧边的偏移量。</li>
+ <li><strong><code>config_pictureInPictureDefaultSizePercent</code></strong> 和 <strong><code>config_pictureInPictureDefaultAspectRatio</code></strong>:占屏幕宽度的百分比与宽高比的组合,用于控制画中画的大小。计算得出的默认画中画大小不应小于 <code>@dimen/default_minimal_size_pip_resizable_task</code>(如 CTS 和 CDD 中所定义)。</li>
+ <li><strong><code>config_pictureInPictureSnapMode</code></strong>:贴靠行为(如 <code>PipSnapAlgorithm</code> 中所定义)。</li>
+</ul>
+<p>
+设备实现不应更改 CDD 和 CTS 中定义的宽高比上限和下限。
+</p>
+<h2 id="permissions">权限</h2>
+<p>
+Android 8.0 在 <code>AppOpsManager</code> (<code>master/core/java/android/app/AppOpsManager.java)</code> 中新增了基于软件包的“应用操作”(<code>OP_PICTURE_IN_PICTURE</code>),这样一来,用户便可以通过系统设置在应用级别控制画中画。
+当 Activity 请求进入画中画模式时,设备实现需要遵循此检查要求。
+</p>
+<h2 id="cts-tests">测试</h2>
+<p>
+要测试画中画实现,请运行主机端 CTS 测试中 <code><a href="https://android.googlesource.com/platform/cts/+/master/hostsidetests/services/activitymanager/src/android/server/cts">/cts/hostsidetests/services/activitymanager</a></code>(尤其是 <code>ActivityManagerPinnedStackTests.java</code> 中)下所有与画中画相关的测试。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/display/retail-mode.html b/zh-cn/devices/tech/display/retail-mode.html
index b637ac3..0d581a4 100644
--- a/zh-cn/devices/tech/display/retail-mode.html
+++ b/zh-cn/devices/tech/display/retail-mode.html
@@ -21,24 +21,87 @@
-->
<p>
-Android 7.1.1 及更高版本可为零售模式提供系统级支持,以便用户可以轻松检测运行中的设备。通过该功能,零售环境中的任何人都可以观看快速、安全、一致的 Android 设备演示,而原始设备制造商 (OEM) 也可以借此大幅降低零售模式的成本和复杂度,实现演示设备的普通化。
+Android 7.1.1 及更高版本可为零售模式提供系统级支持,以便用户可以轻松检测运行中的设备。Android 8.1 对这项支持进行了修订,以通过设备政策管理器创建演示用户。这有利于对标准零售模式进行更灵活的 OEM 自定义。
</p>
-<h2 id="key-use-cases">关键用例</h2>
+<h2 id="android-8-1-and-later">Android 8.1 及更高版本</h2>
+<p>Android 8.1 支持通过设备政策管理器向零售店用户展示设备功能。尽管设备政策管理器的 API 可以在 8.1 之前的版本上使用,但是对于 8.1 之前的版本,无法使用 <a href="https://developer.android.com/reference/android/app/admin/DevicePolicyManager.html#createAndManageUser(android.content.ComponentName, java.lang.String, android.content.ComponentName, android.os.PersistableBundle, int)">createAndManageUser</a> 创建演示类型的用户。
+</p>
+
+<h3 id="implementation">实现</h3>
+
+<h4 id="provisioning">配置</h4>
+<p>
+在配置前将 <code>Settings.Global.DEVICE_DEMO_MODE</code> 设置为 1,以表示设备应进入零售模式。系统服务器将使用此标记来管理零售模式的各个方面,例如电源配置文件。此外,零售员工必须向演示应用授予设备所有权。完成消费者设置后,将无法设置设备所有者。
+</p>
+
+<h4 id="create-demo-app">创建演示应用</h4>
+<p>
+设备所有者应用无需在系统映像上进行提权或预安装。一般来说,这类应用的实现方式与传统应用是一样的;以下是它们之间的差异:</p>
<ul>
-<li>任何现成的 Android 设备都可以通过向 build 添加一个演示视频来设置为零售模式。
-</li><li>所有设备上都具有突出设备独特功能的视频。
-</li><li>无论是在线还是离线环境,设备都可以运行。
-</li><li>设备可以进行自我维护,所需的员工互动极少。</li></ul>
+ <li>所有的设备所有者应用都必须扩展 <code>DeviceAdminReceiver</code> 组件,该组件可作为所有设备政策管理器 API 的授权令牌。该组件必须具有 <code>android.permission.BIND_DEVICE_ADMIN</code> 权限,包含请求的特殊政策(作为元数据),并过滤 <code>android.app.action.PROFILE_PROVISIONING_COMPLETE</code> 和 <code>android.app.action.DEVICE_ADMIN_ENABLED</code> intent。</li>
+ <li><code>DevicePolicyManager#MAKE_USER_DEMO</code> 标记是一个隐藏 API。设置此标记可以创建特殊的演示类型用户。此标记是一个常量 0x4。</li>
+ <li>设备所有权只能通过托管配置进行分配。</li>
+</ul>
-<h2 id="lifecycle">生命周期</h2>
+<h4 id="device-policy-manager">设备政策管理器</h4>
+<p>
+设备政策管理器 API 会授予所有的设备所有者 (DO) 和配置文件所有者 (PO) 权限(软件包安装权限除外,因为系统会自动授予这项权限)。与 DO 关联的 PO 可以使用 AIDL 接口来访问仅向 DO 授予的权限。可用的功能包括:</p>
+<ul>
+ <li>创建用户。通过 DevicePolicyManager 创建的用户将自动设置为 PO。</li>
+ <li>切换用户。</li>
+ <li>将权限政策设置为 <code>PERMISSION_POLICY_AUTO_GRANT</code>,这样可以自动授予所有运行时权限。权限的授予范围也可以缩小:单项权限授予单一应用。这不适用于 Appops 权限(用户仍必须基于每个用户、每个应用授予权限)。</li>
+ <li>添加用户限制。与零售模式相关的限制可能包括但不限于:<ul>
+ <li><code>DISALLOW_MODIFY_ACCOUNTS</code></li>
+ <li><code>DISALLOW_USB_FILE_TRANSFER</code></li>
+ <li><code>DISALLOW_DEBUGGING_FEATURES</code></li>
+ <li><code>DISALLOW_CONFIG_WIFI</code></li>
+ <li><code>DISALLOW_CONFIG_BLUETOOTH</code></li>
+ <li><code>DISALLOW_INSTALL_UNKNOWN_SOURCES</code></li>
+ <li><code>DISALLOW_CONFIG_MOBILE_NETWORKS</code></li>
+ </ul>
+ </li>
+ <li>启用自动系统更新。设备将自动下载并应用 OTA 更新。</li>
+ <li>设置 LockTask 允许的软件包。</li>
+ <li>将设备恢复出厂设置。</li>
+ <li>停用锁屏功能。</li>
+ <li>阻止设置密码/指纹。</li>
+ <li>控制 WLAN 网络更改。与用户限制 <code>DISALLOW_CONFIG_WIFI</code> 一起使用时,设备所有者应用可以控制对 WLAN 网络选择设置的访问权限。</li>
+ <li>重新启动设备。</li>
+ <li>通过 <a href="https://developer.android.com/reference/android/content/pm/PackageInstaller.html">PackageInstaller</a> 安装软件包。</li>
+ <li>设置一组已加入白名单的 <a href="https://developer.android.com/reference/android/provider/Settings.Global.html">
+Settings.Global</a>、<a href="https://developer.android.com/reference/android/provider/Settings.Secure.html">
+Settings.Secure</a> 和 <a href="https://developer.android.com/reference/android/provider/Settings.System.html">
+Settings.System</a> 设置。</li>
+ <li>阻止卸载软件包。</li>
+</ul>
+
+<h3 id="examples-additional-resources">示例和其他资源</h3>
+<ul>
+ <li>用户、配置文件和帐号的 <a href="/devices/tech/admin/multi-user">Android 开发者定义</a></li>
+ <li><a href="https://developer.android.com/reference/android/app/admin/DevicePolicyManager.html">设备政策管理器 API 文档</a></li>
+ <li><a href="https://developer.android.com/samples/DeviceOwner/index.html">示例设备所有者应用</a></li>
+</ul>
+
+<h3 id="validation">验证</h3>
+<p>
+CTS 不涵盖零售演示模式,因为该模式是一项可选功能。测试应手动进行,或对演示应用进行单元测试。
+</p>
+
+<h2 id="retail-demo-mode-8-and-earlier">Android 8.0 及更早版本</h2>
+
+<p>
+Android 7.1.1 引入了零售演示模式,并提供了一个简单 API 来播放演示视频。该实现已在 Android 8.1 中移除。
+</p>
+
+<h3 id="lifecycle">生命周期</h3>
<img src="/devices/tech/display/images/retail-demo-flow.png" alt="零售演示模式流程" width="XXX" id="retail-demo-flow"/>
<p class="img-caption">
<strong>图 1.</strong> 语言选择中的零售演示模式选项</p>
-<h3 id="setup-wizard-suw">设置向导 (SUW)</h3>
+<h4 id="setup-wizard-suw">设置向导 (SUW)</h4>
<p>零售员工可以从任何设置向导的首屏直接启用零售模式,具体方法是选择列表底部的语言 <strong>Retail demo</strong>。此选项适用于全新出厂的设备。一旦消费者完成设置,零售模式将不再可用。选择后,设备将完成具有简短流程的 SUW。
</p>
@@ -47,7 +110,7 @@
<p class="img-caption">
<strong>图 2.</strong> 语言选择中的零售演示模式选项</p>
-<h3 id="guest-session">访客会话</h3>
+<h4 id="guest-session">访客会话</h4>
<p>设备进入零售模式后,会切换到新的演示用户,并自动启动覆盖层资源中指定的自定义启动器(如“实现”部分所述)。默认情况下,此自定义启动器会重复播放演示视频,直至用户触摸屏幕开始访客会话。这时,自定义启动器会在启动系统启动器后退出。原始设备制造商 (OEM) 可以更改自定义启动器,使其在退出时额外启动其他服务或活动。有关详细信息,请参阅“实现”部分。<em></em>
</p>
@@ -70,27 +133,27 @@
<ul>
<li>亮度</li><li>自动旋转</li><li>手电筒</li><li>语言</li><li>无障碍</li></ul>
-<h3 id="exiting-retail-mode">退出零售模式</h3>
+<h4 id="exiting-retail-mode">退出零售模式</h4>
<p>要退出零售模式,零售员工必须从引导加载程序将设备恢复出厂设置。
</p>
-<h2 id="examples-and-source">示例和源代码</h2>
+<h3 id="examples-and-source">示例和源代码</h3>
<p>从以下位置查找循环播放视频的自定义启动器:</p>
<pre class="devsite-click-to-copy">
/packages/apps/RetailDemo
</pre>
-<h2 id="implementation">实现</h2>
+<h3 id="implementation">实现</h3>
-<h3 id="enabling-retaildemomodeservice">启用 RetailDemoModeService</h3>
+<h4 id="enabling-retaildemomodeservice">启用 RetailDemoModeService</h4>
<p>
-设置向导设置全局设置 <code>Global.DEVICE_DEMO_MODE=true</code>,以表示设备已进入零售模式。一遇到此设置,<code>RetailDemoModeService</code> 便会在用户 0 已启动时创建并切换至演示用户,启用覆盖层资源中指定的自定义启动器,并停用 SUW。系统服务器和 SystemUI 也会使用此标记来管理零售模式的各个方面。
+设置向导将设置全局设置 <code>Global.DEVICE_DEMO_MODE=true</code>,来表示设备已进入零售模式。一遇到此设置,<code>RetailDemoModeService</code> 便会在用户 0 已启动时创建并切换至演示用户,启用覆盖层资源中指定的自定义启动器,并停用 SUW。系统服务器和 SystemUI 也会使用此标记来管理零售模式的各个方面。
</p>
-<h3 id="setting-custom-launcher-or-video-player">设置自定义启动器或视频播放器</h3>
+<h4 id="setting-custom-launcher-or-video-player">设置自定义启动器或视频播放器</h4>
<p>原始设备制造商 (OEM) 可以通过覆盖 <code>/frameworks/base/core/res/res/config.xml</code> 中指定的框架资源 <code>config_demoModeLauncherComponent</code> 来指定自定义启动器
</p>
@@ -107,25 +170,26 @@
<p>自定义启动器必须将其自定义组件标记为默认停用,从而避免该组件在非演示情境下出现。在演示情境下,系统服务器会在启动新的演示会话时启用指定的 <code>config_demoModeLauncherComponent</code>。
</p>
-<p>设置向导也会查找上述视频作为素材,以提供给零售模式进行播放。如果视频不是演示的一部分,则可以修改 SUW 以查找其他表明支持零售模式的原始设备制造商 (OEM) 特定标志。
+<p>设置向导也会查找上述视频作为素材,以提供给零售模式进行播放。如果视频不是演示的一部分,则可以修改 SUW 以查找其他表明支持零售模式的 OEM 特定标志。
</p>
<p>如果有 A/B 两个系统分区,则 B 系统分区的 <code>/preloads/demo</code> 中必须包含演示视频。在首次启动时,系统会将该视频复制到 <code>/data/preloads/demo</code>。
</p>
<p>
-要设置特定于零售模式的设置,请使用:<code>Settings.Global.retail_demo_mode_constants</code>。例如:<code>user_inactivity_timeout_ms=90000,warning_dialog_timeout_ms=10000</code>
+要设置特定于零售模式的设置,请使用:
+<code>Settings.Global.retail_demo_mode_constants</code>。例如:<code>user_inactivity_timeout_ms=90000,warning_dialog_timeout_ms=10000</code>
</p>
<p class="note"><strong>注意</strong>:目前的超时默认值为 90000 毫秒,但可对其进行配置。
</p>
-<h3 id="finding-sample-images">查找示例图片</h3>
+<h4 id="finding-sample-images">查找示例图片</h4>
<p>此功能可将示例照片放在对任何图库应用均可见的特殊文件夹中。这些照片仅在演示模式下可用,并且由于处在受保护的目录中,所以演示用户无法对其进行修改。
</p>
-<h3 id="preventing-google-accounts">阻止 Google 帐号</h3>
+<h4 id="preventing-google-accounts">阻止 Google 帐号</h4>
<p>访客用户中设置了一些限制,类似于通过托管设备/资料策略防止应用和用户执行某些操作。其中一项限制是 <code>DISALLOW_MODIFY_ACCOUNTS</code>。在此限制之下,AccountManager 和“设置”不允许添加帐号。某些 Google 应用会对此限制做出反应并显示一条错误消息,其他应用则不提示登录帐号(如 YouTube 和 Google 照片)。
</p>
@@ -133,37 +197,38 @@
<p>原始设备制造商 (OEM) 应用也应检查是否已设置 <code>DISALLOW_MODIFY_ACCOUNTS</code>。但这是一个一般问题,并非零售模式所独有。企业用例很可能已解决此问题。
</p>
-<h3 id="customizing-the-system-launcher">自定义系统启动器</h3>
+<h4 id="customizing-the-system-launcher">自定义系统启动器</h4>
<p>原始设备制造商 (OEM) 可以自由选择布局,但应该在主屏幕和底部区域包含正常运行的应用。
</p>
-<h3 id="Customizing-built-in-apps">针对零售演示模式自定义内置应用</h3>
+<h4 id="Customizing-built-in-apps">针对零售演示模式自定义内置应用</h4>
<p>内置应用可调用 API <code>UserManager.isDemoUser()</code> 来查看应用是否在演示环境中启动,以此针对零售演示模式自定义应用体验。
</p>
-<h3 id="following-demo-video-guidelines">遵循演示视频指南</h3>
+<h4 id="following-demo-video-guidelines">遵循演示视频指南</h4>
<p>演示视频应采用纵向布局(如果是平板电脑,则为设备的自然方向),且时长在 5 秒以上。由于视频将在展示期间全天候播放,因此视频内容不能导致烧机。
</p>
-<h2 id="maintenance">维护</h2>
+<h3 id="maintenance">维护</h3>
-<h3 id="bringing-the-device-out-of-retail-mode">使设备退出零售模式</h3>
+<h4 id="bringing-the-device-out-of-retail-mode">使设备退出零售模式</h4>
<p>只能通过从引导加载程序恢复出厂设置来实现。
</p>
-<h3 id="auto-ota-of-system-software">系统软件的自动 OTA</h3>
+<h4 id="auto-ota-of-system-software">系统软件的自动 OTA</h4>
-<p>默认情况下,启用零售模式时,设备策略将被自动设置为无线 (OTA) 更新。零售设备将不经过确认,自动下载、重新启动并安装更新(考虑电池阈值),即使更新被标记为可选亦如此。
+<p>
+默认情况下,启用零售模式时,设备政策将自动设置为无线下载 (OTA) 更新。零售设备将不经过确认,自动下载、重新启动并安装更新(考虑电池阈值),即使更新被标记为可选亦如此。
</p>
<p class="caution"><strong>注意</strong>:如果针对 OTA 使用 A/B 系统分区,则接收 OTA 更新后,设备将无法在 B 系统分区中找到原始的零售模式资源。因此,之后的任何恢复出厂设置操作都会导致设备无法返回零售模式。
</p>
-<h3 id="updating-demo-video-via-the-web">通过网络更新演示视频</h3>
+<h4 id="updating-demo-video-via-the-web">通过网络更新演示视频</h4>
<p>只要有网络连接,<code>/packages/apps/RetailDemo</code> 中的 RetailDemo 应用便可以更新演示视频。通过在 RetailDemo 应用中替换以下字符串值,可配置下载视频的网址:</p>
@@ -189,7 +254,7 @@
<p>每次设备重新启动时,此视频最多只能下载一次。视频在设备上播放时,RetailDemo 应用会在后台检查是否提供了下载网址以及网址中的视频是否比正在播放的视频新。
-</p><p>如果是,RetailDemo 应用就会下载该视频并开始播放。视频下载完成后,下载的视频将用于在之后的演示会话中播放。在下次重新启动之前,将不再执行此类检查。
+</p><p>如果是,RetailDemo 应用就会下载该视频并开始播放。视频下载完成后,下载的视频将用于在之后的演示会话中播放。在下次重新启动之前,将不再执行任何此类检查。
</p>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/display/split-screen.html b/zh-cn/devices/tech/display/split-screen.html
new file mode 100644
index 0000000..64021c6
--- /dev/null
+++ b/zh-cn/devices/tech/display/split-screen.html
@@ -0,0 +1,81 @@
+<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>
+在 Android 7.0 及更高版本中,用户可以借助平台功能(<a href="/devices/tech/display/multi-window">多窗口模式</a>)在设备屏幕上同时显示多个应用。
+默认模式是分屏,该模式可为用户提供两个活动窗格供他们放置应用。
+</p>
+<p>
+Android 8.0 通过优化分屏功能并为其添加更多功能来改进分屏模式。在默认实现中,如果用户在进入分屏模式后点按<strong>主屏幕</strong>,则系统会压缩顶部窗格,并调整启动器的大小。这是为了向用户展示顶部应用依然处于打开状态,同时保持用户的启动器布局,以便用户从主屏幕中查找和启动应用。
+</p>
+<h2 id="examples-and-source">示例和源代码</h2>
+<p><code>/platform/packages/apps/Launcher3/</code> 中的 Launcher3 代码中有这项新功能的参考实现
+</p>
+<p>
+以下更改 ID 与在 Launcher3 中实现分屏相关,并且可供要对其启动器进行类似更新的设备制造商作为参考。
+</p>
+<ul>
+ <li>Change-Id:<code>I48e5cb3bd15e70627d9bf007d93bc731612fba2e</code></li>
+ <li>Change-Id:<code>I86753bab5b24aafc417e0f77d8c471fc4c0dc7f0</code></li>
+ <li>Change-Id:<code>Id6557d070edb664aa1f4851de7abf494cf8a0677</code></li>
+ <li>Change-Id:<code>Icdaf73ecd89a30e57fe7f405292d793f2d6a3ee8</code></li>
+ <li>Change-Id:<code>Ie50279f4edb94812120dea492aefa4f18218162f</code></li>
+ <li>Change-Id:<code>I6f9ee7be12d3266f021796576c771f86f6120246</code></li>
+ <li>Change-Id:<code>I106fe12041565a090047f146a07d4bc80a074b4a</code></li>
+ <li>Change-Id:<code>Ibb49c56aab29d1223a0ab36476a32d565566eb25</code></li>
+ <li>Change-Id:<code>Id60c793730d982277c9d91860e9fb0e6a0df7d38</code></li>
+ <li>Change-Id:<code>I9d358e74ab403989929dee87542d3dde78c2f229</code></li>
+ <li>Change-Id:<code>I925d5ac9d29439c5d61cf089e7784065a8cb5ebd</code></li>
+ <li>Change-Id:<code>I776c6f710e081645cff891487022cf787869ee3f</code></li>
+ <li>Change-Id:<code>I2d17c89db2eb8d60b3393c2abc3b026e5574085d</code></li>
+ <li>Change-Id:<code>Id6ee68826c4f3cc579880540812fd8ed834f8267</code></li>
+</ul>
+<h2 id="example-ux">UX 示例</h2>
+<p>
+以下是示例屏幕,用于展示此功能的默认实现的用户体验。
+</p>
+<p><img src="/devices/tech/display/images/split-screen-example-ux.png" alt="用于展示启动器调整大小行为的示例屏幕"/>
+</p>
+<p class="img-caption"><strong>图 1</strong>. 用于展示在分屏模式下调整启动器大小的示例屏幕。
+</p>
+<h2 id="implementation">实现</h2>
+<p>
+尽管 Android 8.0 可为此分屏更新提供参考实现,但设备制造商在其启动器中的实现还是要由他们自己来确定。为了支持此功能,请执行以下操作:
+</p>
+<ul>
+ <li>实现符合 Android 兼容性定义文档 (CDD) <a href="/compatibility/android-cdd#3814-multi-windows">多窗口要求</a>的多窗口(或具有多窗口的现有实现)。</li>
+ <li>使启动器可供调整大小。Launcher3 中的参考实现会在屏幕变小的情况下移除应用名称,但具体实现可能会因启动器压缩方式而异(特别是在存在自定义启动器代码的情况下)。</li>
+ <li>在启动器清单中设置最小指定高度值。为此,请在以下位置调整 <code>task_height_of_minimized_mode</code> 值:<code>frameworks/base/core/res/res/values/dimens.xml</code></li>
+</ul>
+<h2 id="testing">测试</h2>
+<p>
+使用手动测试来确保您的实现正常运行。
+</p>
+<ol>
+ <li>进入分屏模式。</li>
+ <li>按<strong>主屏幕</strong>按钮。</li>
+ <li>观察可调整大小的启动器。</li>
+</ol>
+<p>
+确保启动器在其支持的所有设备屏幕方向上均可正确调整大小。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/display/textclassifier.html b/zh-cn/devices/tech/display/textclassifier.html
new file mode 100644
index 0000000..0a2e20e
--- /dev/null
+++ b/zh-cn/devices/tech/display/textclassifier.html
@@ -0,0 +1,123 @@
+<html devsite><head>
+ <title>实现 TEXTCLASSIFIER</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.
+ -->
+
+<h2 id="overview">概览</h2>
+
+<p>
+Android 8.1 引入了 TextClassfier API,该 API 可以使用机器学习技术来协助开发者对文本进行分类:</p>
+
+<pre class="prettyprint">TextClassificationManager tcm =
+ context.getSystemService(TextClassificationManager.class);
+TextClassifier classifier = tcm.getTextClassifier();
+TextSelection selection = classifier.suggestSelection(...);
+TextClassification classification = classifier.classifyText(...);
+</pre>
+<p>
+开发者可以选择设置自定义文本分类程序:</p>
+<p>
+ <code>tcm.setTextClassifier(customTextClassifier);</code>
+</p>
+<p>
+但是,如果应用开发者将文本分类程序设置为 null,则系统会针对 <code>getTextClassifier()</code> 返回系统默认文本分类程序。
+</p>
+<p>
+请参阅:<code>android.view.textclassifier.TextClassifierImpl</code>
+</p>
+<p>
+TextView 和 WebView 会使用 TextClassifier 来实现智能选择和智能文本分享功能:</p>
+
+<img src="/devices/tech/display/images/textclassifier.png"/>
+<p class="img-caption">
+ <b>图 1.</b> TEXTCLASSIFIER 的用法。
+</p>
+
+<h2 id="textclassifier-neural-net-models">TextClassifier 神经网络模型</h2>
+<p>
+Android 开源项目 (AOSP) 具有多个用于文本分类的神经网络模型。每个模型文件都已针对单一语言进行训练。您可以选择安装任何组合的模型。模型会在以下位置进行定义:</p>
+<p>
+<code>external/libtextclassifier/Android.mk</code>
+</p>
+
+<h2 id="pre-installing-language-models-on-devices">在设备上预安装语言模型</h2>
+<p>
+您可以指定一组语言模型并将其安装在设备上:</p>
+
+<pre class="prettyprint"># -----------------------
+# Smart Selection bundles
+# -----------------------
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := textclassifier.smartselection.bundle1
+LOCAL_REQUIRED_MODULES := textclassifier.smartselection.en.model
+LOCAL_REQUIRED_MODULES += textclassifier.smartselection.es.model
+LOCAL_REQUIRED_MODULES += textclassifier.smartselection.de.model
+LOCAL_REQUIRED_MODULES += textclassifier.smartselection.fr.model
+include $(BUILD_STATIC_LIBRARY)
+</pre>
+
+<p>
+例如,安装在 <code>device/google/marlin/device-common.mk</code> 中
+</p>
+
+<pre class="prettyprint"># TextClassifier smart selection model files
+PRODUCT_PACKAGES += \
+ textclassifier.smartselection.bundle1
+</pre>
+
+<h2 id="inspecting-installed-language-modules">检查已安装的语言模块</h2>
+<p>
+使用 ADB 命令列出目录下的文件:</p>
+
+<pre class="prettyprint">$ adb shell ls -l /etc/textclassifier
+-rw-r--r-- 1 root root ... textclassifier.smartselection.de.model
+-rw-r--r-- 1 root root ... textclassifier.smartselection.en.model
+-rw-r--r-- 1 root root ... textclassifier.smartselection.es.model
+-rw-r--r-- 1 root root ... textclassifier.smartselection.fr.model
+</pre>
+
+<h2 id="gservices-model-updates">模型更新</h2>
+
+<p>
+要更新模型,您可以将新模型作为系统映像的一部分来更新,也可以通过使用系统 <code>API ACTION_UPDATE_SMART_SELECTION</code> intent 触发更新的系统组件来进行动态更新。通过广播该系统 API intent,框架得以更新当前所设置语言的语言模型。模型自身包含支持的语言和版本号,因此会使用最新的合适模型。
+</p>
+
+<p>
+因此,您无需预加载所有语言的模型,因为这些模型可以稍后再添加。如果未找到指定语言的模型文件,则文本分类将返回空操作值。
+</p>
+
+<h2 id="compatibility-test-suite-tests">兼容性测试套件测试</h2>
+<p>
+您可以在以下位置找到相关的 Android 兼容性测试套件 (CTS) 测试:</p>
+<p>
+<code>cts/tests/tests/view/src/android/view/textclassifier/cts/TextClassificationManagerTest.java</code>
+</p>
+<p>
+<code>cts/tests/tests/widget/src/android/widget/cts/TextViewTest.java</code>
+</p>
+
+<ul>
+<li><code>testSmartSelection</code></li>
+<li><code>testSmartSelection_dragSelection</code></li>
+<li><code>testSmartSelection_resetSelection</code></li>
+</ul>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/index.html b/zh-cn/devices/tech/index.html
index 3ff8a90..fa1ce83 100644
--- a/zh-cn/devices/tech/index.html
+++ b/zh-cn/devices/tech/index.html
@@ -27,7 +27,7 @@
<p><a href="/devices/tech/dalvik/index.html">» ART 和 Dalvik 信息</a></p>
<h2 id="config">配置</h2>
-<p>要充分利用 Android,需要调整<a href="/devices/tech/config/kernel.html">内核</a>、<a href="/devices/tech/config/renderer.html">OpenGLRenderer</a> 等其它配置。如需了解详情,请参阅本部分的子页面。
+<p>要充分利用 Android,需要调整<a href="/devices/tech/config/kernel.html">内核</a>、<a href="/devices/tech/config/renderer.html">OpenGLRenderer</a> 等其他配置。如需了解详情,请参阅本部分的子页面。
</p><p><a href="/devices/tech/config/index.html">» 配置信息</a></p>
<h2 id="connect">网络连接</h2>
@@ -50,21 +50,33 @@
<p>本部分将介绍各种 Android 显示设置的 AOSP 实现,其中包括应用快捷方式、圆形启动器图标、勿扰 (DND)、多窗口模式(分屏、自由格式和画中画)、高动态范围 (HDR) 视频、夜间模式和零售演示模式。</p>
<p><a href="/devices/tech/display/index.html">» 显示设置信息</a></p>
-<h2 id="HAL-technical-information">HAL 文件参考</h2>
-<p>Android 的硬件抽象层 (HAL) 在软件 API 和硬件驱动程序之间提供了接口。本部分包含了带注释的 HAL 代码文件。</p>
-<p><a href="/reference/hal/">» HAL 参考</a></p>
-
<h2 id="ota-technical-information">OTA 更新</h2>
<p>正常使用的 Android 设备可以接收和安装系统和应用软件的无线 (OTA) 更新。本部分介绍了更新包的结构以及构建更新包时所用的工具,旨在供开发者为新的和已发布的 Android 设备构建 OTA 更新。</p>
<p><a href="/devices/tech/ota/index.html">» OTA 信息</a>
</p>
+<h2 id="performance">性能</h2>
+<p>本部分提供了可用于确保您的 Android 设备最大限度减少资源使用并优化性能的指导,其中包括有关优化启动时间、管理闪存磨损、配置低 RAM 设备等的详细信息。</p>
+<p><a href="/devices/tech/perf/index.html">» 性能信息</a>
+</p>
+
<h2 id="power-technical-information">电源</h2>
<p>Android 框架通过跟踪不同设备组件在不同状态下花费的时间来提供电池使用情况统计信息。本部分介绍了电源管理功能(如低电耗模式),提供了有关如何准确测量设备和组件电量消耗(以及如何确定电量值)的说明,并详细介绍了 <code>batterystats</code> 命令和输出。</p>
<p><a href="/devices/tech/power/index.html">» 电源信息</a></p>
+<h2 id="settings">设置</h2>
+<p>本部分提供了有关在 Android“设置”菜单中实现功能的指导,其中包括有关“设置”应用的模式、组件和架构、如何自定义个性化设置以及如何将设置添加到通用搜索的详细信息。</p>
+<p><a href="/devices/tech/settings/index.html">» 设置信息</a>
+</p>
+
<h2 id="tradefed-test-infrastructure">Trade Federation 测试基础架构</h2>
<p>Trade Federation 是一种连续的测试框架,用于在 Android 设备上运行测试。使用 Trade Federation 的模块化功能可以非常直接地在当前产品的环境中进行测试和基础架构的报告。</p>
-<p><a href="/devices/tech/test_infra/tradefed/index.html">» Trade Federation 测试基础架构概览</a></p>
+<p><a href="/devices/tech/test_infra/tradefed/index.html">
+» Trade Federation 测试基础架构概览</a></p>
+
+<h2 id="vts">供应商测试套件 (VTS)</h2>
+<p>Android 供应商测试套件 (VTS) 提供了大量用于 Android 测试的新功能,对由测试驱动的开发流程起到了促进作用。本部分介绍了有助于 Android 开发社区与测试数据互动的可用测试工具和资源。</p>
+<p><a href="/devices/tech/vts/index.html">» VTS 信息</a>
+</p>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/ota/ab_implement.html b/zh-cn/devices/tech/ota/ab_implement.html
index 2c884a1..55c5789 100644
--- a/zh-cn/devices/tech/ota/ab_implement.html
+++ b/zh-cn/devices/tech/ota/ab_implement.html
@@ -23,7 +23,7 @@
<p>想要实现 A/B 系统更新的原始设备制造商 (OEM) 和 SoC 供应商必须确保其引导加载程序实现 boot_control HAL,并将<a href="#kernel">正确的参数</a>传递到内核。</p>
<h2 id="bootcontrol">实现启动控件 HAL</h2>
-<p>支持 A/B 的引导加载程序必须在 <code><a href="https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/boot_control.h" class="external">hardware/libhardware/include/hardware/boot_control.h</a></code> 实现 <code>boot_control</code> HAL。您可以使用 <code><a href="https://android.googlesource.com/platform/system/extras/+/master/bootctl/" class="external">system/extras/bootctl</a></code> 实用工具和 <code><a href="https://android.googlesource.com/platform/system/extras/+/refs/heads/master/tests/bootloader/" class="external">system/extras/tests/bootloader/</a></code> 来测试实现。
+<p>支持 A/B 更新的引导加载程序必须在 <code>boot_control</code> 实现 <code><a href="https://android.googlesource.com/platform/hardware/libhardware/+/master/include/hardware/boot_control.h" class="external">hardware/libhardware/include/hardware/boot_control.h</a></code> HAL。您可以使用 <code><a href="https://android.googlesource.com/platform/system/extras/+/master/bootctl/" class="external">system/extras/bootctl</a></code> 实用工具和 <code><a href="https://android.googlesource.com/platform/system/extras/+/refs/heads/master/tests/bootloader/" class="external">system/extras/tests/bootloader/</a></code> 来测试实现。
</p>
<p>您还必须实现状态机,如下所示:</p>
@@ -35,8 +35,8 @@
<ol>
<li>择优挑选下列内核补丁程序系列(如果需要):
<ul>
- <li>如果在没有使用 ramdisk 的情况下启动并使用“以恢复方式启动”,请择优挑选 <a href="https://android-review.googlesource.com/#/c/158491/" class="external">android-review.googlesource.com/#/c/158491/</a>。</li>
- <li>要在没有使用 ramdisk 的情况下设置 dm-verity,请择优挑选 <a href="https://android-review.googlesource.com/#/q/status:merged+project:kernel/common+branch:android-3.18+topic:A_B_Changes_3.18" class="external">android-review.googlesource.com/#/q/status:merged+project:kernel/common+branch:android-3.18+topic:A_B_Changes_3.18</a>。</li>
+ <li>如果在没有使用 ramdisk 的情况下启动并使用“以恢复方式启动”,请访问 <a href="https://android-review.googlesource.com/#/c/158491/" class="external">android-review.googlesource.com/#/c/158491/</a> 根据需要进行选择。</li>
+ <li>要在没有使用 ramdisk 的情况下设置 dm-verity,请访问 <a href="https://android-review.googlesource.com/#/q/status:merged+project:kernel/common+branch:android-3.18+topic:A_B_Changes_3.18" class="external">android-review.googlesource.com/#/q/status:merged+project:kernel/common+branch:android-3.18+topic:A_B_Changes_3.18</a> 根据需要进行选择。</li>
</ul>
</li>
<li>确保内核命令行参数包含中以下额外参数:
@@ -49,7 +49,7 @@
<pre class="devsite-terminal devsite-click-to-copy">
openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate></pre>
</li>
- <li>构建 <code>zImage</code> 以将该证书添加为系统密钥环的一部分。要验证,请检查 <code>procfs</code> 条目(需要启用 <code>KEYS_CONFIG_DEBUG_PROC_KEYS</code>):
+ <li>构建 <code>zImage</code> 以将该证书添加为系统密钥环的一部分。要进行验证,请检查 <code>procfs</code> 条目(需要启用 <code>KEYS_CONFIG_DEBUG_PROC_KEYS</code>):
<pre class="devsite-click-to-copy">
angler:/# cat /proc/keys
@@ -57,19 +57,19 @@
Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f []
2d454e3e I------ 1 perm 1f030000 0 0 keyring
.system_keyring: 1/4</pre>
-如果 .X509 证书添加成功,则表示系统密钥环中存在相应公钥(突出显示部分表示公钥 ID)。</li>
+如果 .X509 证书添加成功,则表示系统密钥环中存在相应公钥(突出显示的部分为公钥 ID)。</li>
<li>将空格替换为 <code>#</code>,并将其作为 <code><public-key-id></code> 在内核命令行中传递。例如,传递 <code>Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f</code> 而非 <code><public-key-id></code>。</li>
</ol>
</li>
</ol>
-<h2 id="build-variables">设置构建变量</h2>
+<h2 id="build-variables">设置编译变量</h2>
-<p>支持 A/B 的引导加载程序必须满足以下构建变量条件:</p>
+<p>支持 A/B 更新的引导加载程序必须满足以下编译变量条件:</p>
<table>
<tbody><tr>
-<th>必须针对 A/B 目标定义的变量</th>
+<th>必须针对 A/B 更新目标定义的变量</th>
<td>
<ul>
<li><code>AB_OTA_UPDATER := true</code></li>
@@ -112,18 +112,18 @@
<h3 id="cache">缓存</h3>
-<p>对于非 A/B 更新,缓存分区用于存储下载的 OTA 软件包,并在应用更新时暂时隐藏块。调整缓存分区大小从来没有好办法:其缓存所需的大小取决于您想要应用的更新。最糟糕的情况是缓存分区与系统映像一样大。如果使用 A/B 更新,则无需隐藏块(因为您始终在写入当前未使用的分区);如果流式传输 A/B,则无需在应用之前下载整个 OTA 软件包。</p>
+<p>对于非 A/B 更新,缓存分区用于存储下载的 OTA 软件包,并在应用更新时暂时隐藏块。调整缓存分区大小从来没有好办法:所需的大小取决于您想要应用的更新。最糟糕的情况是缓存分区与系统映像一样大。如果使用 A/B 更新,则无需隐藏块(因为您始终在向当前未使用的分区写入数据);如果流式传输 A/B 更新,则无需在应用之前下载整个 OTA 软件包。</p>
<h3 id="recovery">恢复</h3>
<p>恢复 RAM 磁盘现已包含在 <code>boot.img</code> 文件中。
进入恢复模式时,引导加载程序<strong>无法</strong>在内核命令行中添加 <code>skip_initramfs</code> 选项。</p>
-<p>对于非 A/B更新,恢复分区包含用于应用更新的代码。A/B 更新由在正常启动的系统映像中运行的 <code>update_engine</code> 应用。仍有一种用于实现恢复出厂设置和旁加载更新软件包的恢复模式(“恢复”就由此而来)。恢复模式的代码和数据存储在 ramdisk 的常规启动分区中;为启动进入系统映像,引导加载程序会指示内核跳过 ramdisk(否则,设备会启动进入恢复模式)。恢复模式很小(其中大部分已在启动分区上),所以启动分区的大小不会增加。</p>
+<p>对于非 A/B 更新,恢复分区包含用于应用更新的代码。A/B 更新由在正常启动的系统映像中运行的 <code>update_engine</code> 应用。同时,仍有一种用于实现恢复出厂设置和旁加载更新软件包的恢复模式(“恢复”就由此而来)。恢复模式的代码和数据存储在 ramdisk 的常规启动分区中;为启动进入系统映像,引导加载程序会指示内核跳过 ramdisk(否则,设备会启动进入恢复模式)。恢复模式很小(其中大部分已在启动分区上),所以启动分区的大小不会增加。</p>
<h3 id="fstab">Fstab</h3>
-<p><code>slotselect</code> 参数<strong>必须</strong>位于 A/B 化分区对应的行中。例如:</p>
+<p><code>slotselect</code> 参数<strong>必须</strong>位于进行 A/B 更新的分区对应的行中。例如:</p>
<pre class="devsite-click-to-copy">
<path-to-block-device>/vendor /vendor ext4 ro
@@ -152,7 +152,7 @@
<li><code>slot-count</code>。返回一个表示可用插槽数量的整数。目前支持两个插槽,因此该值为 <code>2</code>。</li>
<li><code>slot-successful:<slot-suffix></code>。如果指定插槽已标记为成功启动,则返回“yes”,否则返回“no”。</li>
<li><code>slot-unbootable:<slot-suffix></code>。如果指定插槽已标记为不可引导,则返回“yes”,否则返回“no”。</li>
-<li><code>slot-retry-count<slot suffix></slot></code>。可以尝试启动指定插槽的剩余重试次数。</li>
+<li><code>slot-retry-count<slot suffix></slot></code>。启动指定插槽的剩余重试次数。</li>
</ul>
<p>要查看所有变量,请运行 <code class="devsite-terminal devsite-click-to-copy">fastboot getvar all</code>。
@@ -160,17 +160,17 @@
<h2 id="ota-package-generation">生成 OTA 软件包</h2>
-<p><a href="/devices/tech/ota/tools.html">OTA 软件包工具</a>遵循用于非 A/B 设备的相同命令。<code>target_files.zip</code> 文件必须通过为 A/B 目标定义构建变量生成。OTA 软件包工具会自动识别并生成格式适用于 A/B 更新程序的软件包。</p>
+<p><a href="/devices/tech/ota/tools.html">OTA 软件包工具</a>遵循的命令与不采取 A/B 更新的设备相同。<code>target_files.zip</code> 文件必须通过为 A/B 更新目标定义编译变量生成。OTA 软件包工具会自动识别并生成格式适用于 A/B 更新程序的软件包。</p>
<p>例如:</p>
<ul>
-<li>要生成完整 OTA:
+<li>生成完整 OTA:
<pre class="devsite-terminal devsite-click-to-copy">
./build/tools/releasetools/ota_from_target_files \
dist_output/tardis-target_files.zip ota_update.zip
</pre>
</li>
-<li>要生成增量 OTA:<pre class="devsite-terminal devsite-click-to-copy">
+<li>生成增量 OTA:<pre class="devsite-terminal devsite-click-to-copy">
./build/tools/releasetools/ota_from_target_files \
-i PREVIOUS-tardis-target_files.zip \
dist_output/tardis-target_files.zip incremental_ota_update.zip
@@ -195,10 +195,10 @@
<h2 id="post-install">配置安装后步骤</h2>
-<p>对于每个已更新的分区,您可以使用一组键值对配置不同的安装后步骤。要在新映像中运行位于 <code>/system/usr/bin/postinst</code> 的程序,请相对于系统分区中的文件系统的根目录来指定路径。</p>
+<p>对于每个已更新的分区,您可以使用一组键值对配置不同的安装后步骤。要在新映像中运行位于 <code>/system/usr/bin/postinst</code> 的程序,请指定相对于系统分区中文件系统的根目录的路径。</p>
<p>例如,<code>usr/bin/postinst</code> 的对应路径为 <code>system/usr/bin/postinst</code>(如果未使用 RAM 磁盘)。此外,请指定要传递到 <code>mount(2)</code> 系统调用的文件系统类型。
-将以下内容添加到产品或设备的 <code>.mk</code> 文件(如果适用):</p>
+请将以下代码添加到产品或设备的 <code>.mk</code> 文件中(如果适用):</p>
<pre class="devsite-click-to-copy">
AB_OTA_POSTINSTALL_CONFIG += \
@@ -219,7 +219,7 @@
# A/B OTA dexopt package
PRODUCT_PACKAGES += otapreopt_script
</pre></li>
-<li>将编译脚本与 <code>update_engine</code> 相关联,以便它可以作为安装后步骤运行。
+<li>将编译脚本与 <code>update_engine</code> 相关联,以便后者可以作为安装后步骤运行。
<pre class="devsite-click-to-copy">
# A/B OTA dexopt update_engine hookup
AB_OTA_POSTINSTALL_CONFIG += \
diff --git a/zh-cn/devices/tech/ota/device_code.html b/zh-cn/devices/tech/ota/device_code.html
index 575b157..bd49223 100644
--- a/zh-cn/devices/tech/ota/device_code.html
+++ b/zh-cn/devices/tech/ota/device_code.html
@@ -230,7 +230,8 @@
<p>由于 <code>HandleMenuKey()</code> 隐含在可见参数中,因此,即使菜单不可见,也会进行调用。与 <code>CheckKey()</code> 不同的是,当恢复系统执行清除数据或安装软件包等操作时,系统不会调用该函数,只有恢复系统处于闲置状态或等待输入时才会调用该函数。<i></i></p>
<h4 id="trackball-mechanism">轨迹球机制</h4>
-<p>如果您的设备采用类似于轨迹球的输入机制(生成类型为 EV_REL、代码为 REL_Y 的输入事件),那么,只要类似于轨迹球的输入设备报告 Y 轴的动作,恢复系统就会合成 KEY_UP 和 KEY_DOWN 按键。您只需将 KEY_UP 和 KEY_DOWN 事件映射到相应的菜单操作即可。无法针对 <code>CheckKey()</code> 实现此映射,因此,您无法将轨迹球动作用作重新启动或切换显示状态的触发器。<i></i></p>
+<p>如果您的设备采用类似于轨迹球的输入机制(生成类型为 EV_REL、代码为 REL_Y 的输入事件),那么,只要类似于轨迹球的输入设备报告 Y 轴的动作,恢复系统就会合成 KEY_UP 和 KEY_DOWN 按键。您只需将 KEY_UP 和 KEY_DOWN 事件映射到相应的菜单操作即可。
+无法针对 <code>CheckKey()</code> 实现此映射,因此,您无法将轨迹球动作用作重新启动或切换显示状态的触发器。<i></i></p>
<h4 id="modifier-keys">辅助键</h4>
<p>要查看作为辅助键按下的键,请调用您自己的界面对象的 <code>IsKeyPressed()
@@ -515,7 +516,8 @@
}
</pre>
-<p><code>ReadValueArgs()</code> 不执行类型检查,因此您必须在这里执行这项检查;使用 <b>if</b> 语句执行这项检查会更方便,不过,这样做也有一个弊端,那就是操作失败时所显示的错误消息会不够具体。不过,如果有任何评估失败,<code>ReadValueArgs()</code> 会处理每个参数的评估操作,并释放之前评估的所有参数(以及设置有用的错误消息)。您可以使用 <code>
+<p><code>ReadValueArgs()</code> 不执行类型检查,因此您必须在这里执行这项检查;使用 <b>if</b> 语句执行这项检查会更方便,不过,这样做也有一个弊端,那就是操作失败时所显示的错误消息会不够具体。
+不过,如果有任何评估失败,<code>ReadValueArgs()</code> 会处理每个参数的评估操作,并释放之前评估的所有参数(以及设置有用的错误消息)。您可以使用 <code>
ReadValueVarArgs()</code> 便捷函数来评估数量不定的参数(它会返回 <code>Value*</code> 的数组)。</p>
<p>对参数进行评估后,执行以下函数:</p>
@@ -554,7 +556,7 @@
}
</pre>
-<p>要将函数挂接到 edify 解释程序中,请提供函数 <code>Register_<i>foo</i></code>(其中 <i>foo</i> 是包含此代码的静态库的名称)。调用 <code>RegisterFunction()</code> 即可注册各个扩展函数。按照惯例,您需要对设备专属函数 <code><i>device</i>.<i>whatever</i></code> 进行命名,以免与将来添加的内置函数发生冲突。</p>
+<p>要将函数挂接到 edify 解释器中,请提供函数 <code>Register_<i>foo</i></code>(其中 <i></i>foo 是包含此代码的静态库的名称)。调用 <code>RegisterFunction()</code> 即可注册各个扩展函数。按照惯例,您需要对设备专属函数 <code><i>device</i>.<i>whatever</i></code> 进行命名,以免与将来添加的内置函数发生冲突。</p>
<pre class="prettyprint">
void Register_librecovery_updater_tardis() {
@@ -574,14 +576,14 @@
LOCAL_C_INCLUDES += bootable/recovery
</pre>
-<p>静态库的名称必须与其中所包含的 <code>Register_<i>libname</i></code> 函数的名称匹配。</p>
+<p>静态库的名称必须与其中包含的 <code>Register_<i>libname</i></code> 函数的名称相匹配。</p>
<pre class="devsite-click-to-copy">
LOCAL_MODULE := librecovery_updater_tardis
include $(BUILD_STATIC_LIBRARY)
</pre>
-<p>最后,配置 recovery 的版本号以拉入您的库。将您的库添加到 TARGET_RECOVERY_UPDATER_LIBS(它可能包含多个库;所有库均已注册)。如果您的代码依赖于本身不是 edify 扩展程序的其他静态库(即,它们没有 <code>Register_<i>libname</i></code> 函数),您可以将其列于 TARGET_RECOVERY_UPDATER_EXTRA_LIBS 中,以将其链接到更新程序,而无需调用其(不存在)的注册函数。例如,如果您的设备专属代码需要使用 zlib 解压缩数据,您可以在此处包含 libz。</p>
+<p>最后,配置 recovery 的版本号以拉入您的库。将您的库添加到 TARGET_RECOVERY_UPDATER_LIBS(它可能包含多个库;所有库均已注册)。如果您的代码依赖于本身不是 edify 扩展程序的其他静态库(即,它们没有 <code>Register_<i>libname</i></code> 函数),您可以将其列于 TARGET_RECOVERY_UPDATER_EXTRA_LIBS 中,以将其链接到更新程序,而无需调用其(不存在的)注册函数。例如,如果您的设备专属代码需要使用 zlib 解压缩数据,您可以在此处包含 libz。</p>
<pre class="devsite-click-to-copy">
device/yoyodyne/tardis/BoardConfig.mk
@@ -695,7 +697,7 @@
</p>
<ul>
<li><b>info.input_zip</b>:(仅限完整 OTA)输入 target-files .zip 的 <code>zipfile.ZipFile</code> 对象。</li>
-<li><b>info.source_zip</b>:(仅限增量 OTA)源 target-files .zip <code>zipfile.ZipFile
+<li><b>info.source_zip</b>:(仅限增量 OTA)源 target-files .zip 的 <code>zipfile.ZipFile
</code> 对象(安装增量包时版本号已在设备上)。</li>
<li><b>info.target_zip</b>:(仅限增量 OTA)目标 target-files .zip 的 <code>zipfile.ZipFile
</code> 对象(增量包置于设备上的版本号)。</li>
@@ -752,7 +754,7 @@
</code> 通常不可用于恢复系统,因为它可能会被加密。恢复界面会显示 <code>/sdcard</code> 中的 .zip 文件菜单,以便用户进行选择。</li>
<li><b>APPLY_CACHE</b>:类似于从 <code>/sdcard</code> 加载更新包,不过使用的是 <code>/cache</code> 目录(一律可用于恢复系统)。<i></i>在常规系统中,<code>/cache
</code> 只能由特权用户写入;如果设备不可启动,则完全无法写入 <code>/cache</code> 目录(这样一来,该机制的效用就会有所限制)。</li>
-<li><b>APPLY_ADB_SIDELOAD</b>:允许用户通过 USB 数据线和 adb 开发工具将软件包发送到设备。调用此机制时,恢复系统将启动自身的迷你版 adbd 守护程序,以便已连接的主机上的 adb 与其进行对话。该迷你版守护程序仅支持一个命令:<code>adb sideload <i>filename</i></code>。已命名的文件会从主机发送到设备,然后对其进行验证和安装(如同文件在本地存储区中一样)。</li>
+<li><b>APPLY_ADB_SIDELOAD</b>:允许用户通过 USB 数据线和 adb 开发工具将软件包发送到设备。调用此机制时,恢复系统将启动自身的迷你版 adbd 守护进程,以便已连接的主机上的 adb 与其进行对话。该迷你版守护进程仅支持一个命令:<code>adb sideload <i>filename</i></code>。已命名的文件会从主机发送到设备,然后对其进行验证和安装(如同文件在本地存储区中一样)。</li>
</ul>
<p>一些注意事项:</p>
diff --git a/zh-cn/devices/tech/ota/inside_packages.html b/zh-cn/devices/tech/ota/inside_packages.html
index c91b7af..51103f8 100644
--- a/zh-cn/devices/tech/ota/inside_packages.html
+++ b/zh-cn/devices/tech/ota/inside_packages.html
@@ -1,5 +1,5 @@
<html devsite><head>
- <title>OTA 软件包内部探秘</title>
+ <title>OTA 软件包内部</title>
<meta name="project_path" value="/_project.yaml"/>
<meta name="book_path" value="/_book.yaml"/>
</head>
@@ -73,14 +73,16 @@
<p>支持特殊语法将 MTD(内存技术设备)分区的内容作为文件处理,以便为引导分区这样的原始分区打补丁。由于 MTD 分区没有文件结束标记,因此要读取该分区,您必须知道您要读取的数据量。您可以使用字符串“MTD:partition:size_1:sha1_1:size_2:sha1_2”作为文件名来读取给定的分区。<i></i><i></i><i></i><i></i><i></i>您必须至少指定一个(size,sha-1)对;如果您希望读取的内容有多种可能,则可以指定多个对。<i></i></p></dd>
<dt><code>apply_patch_check(<i>filename</i>, <i>sha1</i>[, <i>sha1</i>, ...])
</code></dt>
-<dd>如果 filename 的内容或缓存分区中的临时副本(如果存在)中的内容具有与给定的 sha1 值之一相等的 SHA1 校验和,则返回 True。sha1 值指定为 40 位十六进制数字。<i></i><i></i><i></i>该函数不同于 <code>sha1_check(read_file(<i>filename</i>),
+<dd>如果 filename 的内容或缓存分区中的临时副本(如果存在)中的内容具有与给定的 sha1 值之一相等的 SHA1 校验和,则返回 True。sha1 值指定为 40 位十六进制数字。<i></i><i></i><i></i>
+该函数不同于 <code>sha1_check(read_file(<i>filename</i>),
<i>sha1</i> [, ...])</code>,因为它知道要检查缓存分区副本,因此即使文件被中断的 <code>apply_patch() update</code> 损坏,<code>apply_patch_check()</code> 也将成功。</dd>
<dt><code>apply_patch_space(<i>bytes</i>)</code></dt>
<dd>如果至少有 bytes 个字节的暂存空间可用于打二进制补丁程序,则返回 True。<i></i></dd>
<dt><code>concat(<i>expr</i>[, <i>expr</i>, ...])</code></dt>
<dd>评估每个表达式并将它们连接起来。在只有两个参数的特殊情况下,+ 运算符就是该函数的语法糖(但该函数形式可以包含任意数量的表达式)。表达式必须为字符串;该函数不能连接 Blob。</dd>
<dt><code>file_getprop(<i>filename</i>, <i>key</i>)</code></dt>
-<dd>读取给定的 filename,将其解释为属性文件(例如:<code>/system/build.prop</code>),并返回给定 key 的值,如果 key 不存在,则返回空字符串。<i></i><i></i><i></i></dd>
+<dd>读取给定的 filename,将其解释为属性文件(例如:<code>/system/build.prop</code>),并返回给定 key 的值,如果 key 不存在,则返回空字符串。<i></i><i></i>
+<i></i></dd>
<dt><code>format(<i>fs_type</i>, <i>partition_type</i>, <i>location</i>, <i>
fs_size</i>, <i>mount_point</i>)</code></dt>
<dd>重新格式化给定的分区。支持的分区类型如下:
diff --git a/zh-cn/devices/tech/ota/nonab_updates.html b/zh-cn/devices/tech/ota/nonab_updates.html
index 5e773aa..a5bbbbc 100644
--- a/zh-cn/devices/tech/ota/nonab_updates.html
+++ b/zh-cn/devices/tech/ota/nonab_updates.html
@@ -45,7 +45,7 @@
<dt>缓存</dt>
<dd>
- 几个应用使用的临时保留区域(访问此分区需要使用特殊的应用权限),用于存储下载的 OTA 更新包。其他程序也可使用该空间,但是此类文件可能会随时消失。安装某些 OTA 更新包可能会导致此分区被完全擦除。
+ 几个应用使用的临时保留区域(访问此分区需要使用特殊的应用权限),用于存储下载的 OTA 更新包。其他程序也可使用该空间,但是此类文件可能会随时消失。安装某些 OTA 更新包可能会导致此分区被完全擦除。缓存还包含 OTA 更新的更新日志。
</dd>
<dt>恢复</dt>
@@ -94,7 +94,7 @@
</li>
</ol>
- <p>系统更新完成!</p>
+ <p>系统更新完成!更新日志可以在 <code>/cache/recovery/last_log.<var>#</var></code> 中找到。</p>
<h2 id="migrating">从更早版本迁移</h2>
diff --git a/zh-cn/devices/tech/ota/reduce_size.html b/zh-cn/devices/tech/ota/reduce_size.html
index 7d1d453..d2e35db 100644
--- a/zh-cn/devices/tech/ota/reduce_size.html
+++ b/zh-cn/devices/tech/ota/reduce_size.html
@@ -20,119 +20,128 @@
limitations under the License.
-->
-<p>本页介绍了为减少不同构建之间的不必要文件变更,而添加到 AOSP 的构建变更。维护自己的构建系统的设备实现人员,可依照此信息减小无线 (OTA) 更新的大小。</p>
+<p>本页介绍了为减少不同编译之间不必要的文件变更而添加到 AOSP 的编译变更。负责自行维护编译系统的设备实现人员可根据这项信息减小无线下载 (OTA) 更新的大小。
+</p>
-<p>有时 Android OTA 包含的变更文件并非对应于代码变更,而是对应于构建系统的软件工件。在不同时间、不同目录或不同机器上构建相同代码时,会产生大量变更文件,这时便会发生上述情况。这些多余的文件不仅会增加 OTA 的大小,而且会导致难以确定 OTA 中发生变更的代码。</p>
+<p>有时,Android OTA 包含的变更文件并非对应于代码变更,而是对应于编译系统的软件工件。在不同时间、不同目录或不同机器上编译相同的代码时会产生大量变更文件,这时便会发生上述情况。这些多余的文件不仅会增加 OTA 的大小,还会导致难以确定 OTA 中发生变更的代码。</p>
-<p>为了使 OTA 的内容更加透明,AOSP 加入了构建系统变更,旨在通过消除不同构建之间不必要的文件变更来减小 OTA 的大小。这样做是为了减小 OTA 的大小,使其只包括与 OTA 中包含的补丁程序相关的文件。AOSP 还会加入<a href="#the_build_diff_tool">构建 diff 工具</a>,以过滤出常见的构建相关文件变更并提供更加清晰的构建文件 diff。</p>
+<p>为了使 OTA 的内容更加透明,AOSP 纳入了编译系统变更,目的是通过消除不同编译之间不必要的文件变更来减小 OTA 的大小。这样做是为了减小 OTA 的大小,使其只包含与 OTA 中所含补丁程序相关的文件。AOSP 还会加入<a href="#the_build_diff_tool">编译 diff 工具</a>(可过滤出常见的编译相关文件变更,并提供更清晰的编译文件 diff)以及<a href="#block-mapping-tool">块映射工具</a>(协助您确保块分配的一致性)。</p>
-<p>构建系统可能会通过多种方式创建不必要的文件 diff。下文讨论了其中一些问题和解决方案,并尽可能提供了 AOSP 中的修复示例。</p>
+<p>编译系统可能会通过多种方式创建不必要的文件 diff。下文讨论了其中一些问题和解决方案,并尽可能提供了 AOSP 中的修复示例。</p>
<h2 id="file_order">文件顺序</h2>
-<p><strong>问题</strong>:文件系统在请求目录中的文件列表时,并不保证文件顺序,尽管对于同一查询,文件顺序通常是相同的。诸如 <code>ls</code> 之类的工具在默认情况下会对结果进行排序,但 <code>find</code> 和 <code>make</code> 之类的命令使用的通配符函数却不会对结果进行排序。用户在使用此类工具之前,必须对输出进行排序。</p>
+<p><strong>问题</strong>:文件系统在请求目录中的文件列表时,并不保证文件顺序,尽管对于同一项查询,文件顺序通常是相同的。<code>ls</code> 等工具在默认情况下会对结果进行排序,但 <code>find</code> 和 <code>make</code> 等命令使用的通配符函数却不会对结果进行排序。用户在使用这类工具之前,务必要对输出进行排序。
+</p>
-<p><strong>解决方案</strong>:用户在使用带有通配符的 <code>find</code> 和 <code>make</code> 之类的工具之前,必须对这些命令的输出进行排序。要在 Android.mk 文件中使用 <code>$(wildcard )</code> 或 <code>$(shell find )</code>,也应该进行排序。有些工具(例如 Java)确实会对输入进行排序,因此有必要对排序进行验证。</p>
+<p><strong>解决方案</strong>:用户在使用带通配符的 <code>find</code> 和 <code>make</code> 等工具之前,务必要对这些命令的输出进行排序。要在 <code>Android.mk</code> 文件中使用 <code>$(wildcard)</code> 或 <code>$(shell find)</code>,也应该进行排序。有些工具(如 Java)确实会对输入进行排序,因此有必要先对排序进行验证。</p>
-<p><strong>示例</strong>:很多实例使用内建的 <code>all-*-files-under</code> 宏固定在核心构建系统中,其中包括 <code>all-cpp-files-under</code>(一些定义分散在其他 makefile 中)。有关详情,请参阅以下 CL:</p>
+<p><strong>示例</strong>:很多实例使用内建的 <code>all-*-files-under</code> 宏固定在核心编译系统中,其中包括 <code>all-cpp-files-under</code>(一些定义分散在其他 makefile 中)。有关详情,请参阅以下 CL:</p>
<ul>
- <li><a href="https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f">https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f</a>
- </li><li><a href="https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410">https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410</a>
- </li><li><a href="https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653">https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653</a>
- </li><li><a href="https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c">https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c</a>
+ <li><a href="https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f" class="external">https://android.googlesource.com/platform/build/+/4d66adfd0e6d599d8502007e4ea9aaf82e95569f</a>
+ </li><li><a href="https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410" class="external">https://android.googlesource.com/platform/build/+/379f9f9cec4fe1c66b6d60a6c19fecb81b9eb410</a>
+ </li><li><a href="https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653" class="external">https://android.googlesource.com/platform/build/+/7c3e3f8314eec2c053012dd97d2ae649ebeb5653</a>
+ </li><li><a href="https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c" class="external">https://android.googlesource.com/platform/build/+/5c64b4e81c1331cab56d8a8c201f26bb263b630c</a>
</li></ul>
-<h2 id="build_directory">构建目录</h2>
+<h2 id="build_directory">编译目录</h2>
-<p><strong>问题</strong>:变更构建内容所在的目录会导致二进制文件有所变化。Android 构建中的大多数路径是相对路径,因此 C/C ++ 中的 <code>__FILE__</code> 不是问题。不过,默认情况下调试符号会对完整的路径名进行编码,而对预剥离二进制文件进行哈希处理会生成 <code>.note.gnu.build-id</code>,因此调试符号变更会使二进制文件发生变化。</p>
+<p><strong>问题</strong>:变更编译内容所在的目录会导致二进制文件有所不同。Android 编译中的大多数路径都是相对路径,因此 C/C++ 中的 <code>__FILE__</code> 不是问题。不过,默认情况下调试符号会对完整的路径名进行编码,而对预剥离二进制文件进行哈希处理会生成 <code>.note.gnu.build-id</code>,因此调试符号发生变更会致使二进制文件发生变化。</p>
-<p><strong>解决方案</strong>:AOSP 现在会使调试路径变成相对路径。有关详情,请参阅 CL:
-<a href="https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02">https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02</a>。</p>
+<p><strong>解决方案</strong>:AOSP 现在会使调试路径变成相对路径。有关详情,请参阅 CL:<a href="https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02" class="external">https://android.googlesource.com/platform/build/+/6a66a887baadc9eb3d0d60e26f748b8453e27a02</a>。
+</p>
<h2 id="timestamps">时间戳</h2>
-<p><strong>问题</strong>:构建输出中的时间戳会导致不必要的文件变更。这可能发生在以下位置:</p>
+<p><strong>问题</strong>:编译输出中的时间戳会导致不必要的文件变更。这可能发生在以下位置:</p>
<ul>
- <li>C 或 C++ 代码中的<code> __DATE__/__TIME__/__TIMESTAMP__ </code>宏。</li>
+ <li>C 或 C++ 代码中的 <code>__DATE__/__TIME__/__TIMESTAMP__</code> 宏。</li>
<li>基于 ZIP 的归档中嵌入的时间戳。</li>
</ul>
-<p><strong>解决方案/示例</strong>:要从构建输出中移除时间戳,请遵循下文中的说明操作。</p>
+<p><strong>解决方案/示例</strong>:要从编译输出中移除时间戳,请遵循下文中的说明操作。</p>
<h3 id="date_time_timestamp_in_c_c">C/C++ 中的 __DATE__/__TIME__/__TIMESTAMP__</h3>
-<p>这些宏总是会为不同的构建生成不同的输出,因此不应使用。
- 您可选择以下方法来消除这些宏:</p>
+<p>这些宏总是为不同的编译生成不同的输出,因此不建议使用。您可以选择通过以下方法来移除这些宏:</p>
<ul>
- <li>直接移除,这些宏通常并非必需。要查看示例,请参阅:
-<a href="https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f">https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f</a></li>
+ <li>直接将其移除(这些宏通常不是必需的)。要查看示例,请参阅:<a href="https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f" class="external">https://android.googlesource.com/platform/system/core/+/30622bbb209db187f6851e4cf0cdaa147c2fca9f</a>。</li>
<li>要对运行中的二进制文件进行唯一标识,请从 ELF 标头中读取 build-id。</li>
- <li>要了解操作系统的构建时间,请读取 <code>ro.build.date</code>(应该适合除增量构建之外的所有项目,增量构建可能不会更新此日期)。要查看示例,请参阅:
-<a href="https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84">https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84</a></li>
+ <li>要了解操作系统的编译时间,请读取 <code>ro.build.date</code>(应该会对除增量编译之外的所有内容都适用;增量编译可能不会更新此日期)。要查看示例,请参阅:<a href="https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84" class="external">https://android.googlesource.com/platform/external/libchrome/+/8b7977eccc94f6b3a3896cd13b4aeacbfa1e0f84</a>。</li>
</ul>
- <p class="note"><strong>注意</strong>:我们开启了 <code>-Werror=date-time</code>,因此使用时间戳是一种构建错误。</p>
+<aside class="note"><strong>注意</strong>:Android 7.0 开启了 <code>-Werror=date-time</code>,因此使用时间戳是一种编译错误。</aside>
-<h3 id="embedded_timestamps_in_zip-based_archives_zip_jar">归档(zip、jar)中的嵌入时间戳</h3>
+<h3 id="embedded_timestamps_in_zip-based_archives_zip_jar">归档文件(zip、jar)中的嵌入时间戳</h3>
-<p>我们通过将 <code>-X</code> 添加到 <code>zip</code> 命令的所有用例中,解决了嵌入时间戳的问题,因此构建工具的 UID/GID 和扩展的 Unix 时间戳不会嵌入到 ZIP 文件中。</p>
+<p>Android 7.0 通过将 <code>-X</code> 添加到 <code>zip</code> 命令的所有用例中,解决了 zip 归档文件中嵌入时间戳的问题,因此编译工具的 UID/GID 和扩展的 Unix 时间戳不会嵌入到 ZIP 文件中。</p>
-<p>新工具 <code>ziptime</code>(位于 <code>
- <a href="https://android.googlesource.com/platform/build/+/master/tools/ziptime/">/platform/build/+/master/tools/ziptime/</a></code>)会重置 zip 标头中的正常时间戳。有关详情,请参阅 <a href="https://android.googlesource.com/platform/build/+/master/tools/ziptime/README.txt">README 文件</a>。</p>
+<p>新工具 <code>ziptime</code>(位于 <code><a href="https://android.googlesource.com/platform/build/+/master/tools/ziptime/" class="external">/platform/build/+/master/tools/ziptime/</a></code> 下)会重置 zip 标头中的正常时间戳。有关详情,请参阅 <a href="https://android.googlesource.com/platform/build/+/master/tools/ziptime/README.txt" class="external">README 文件</a>。</p>
-<p><code>signapk</code> 工具为 APK 文件设置的时间戳可能因服务器所在的时区而异。有关详情,请参阅 CL:
-<a href="https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028">https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028</a>。</p>
+<p><code>signapk</code> 工具为 APK 文件设置的时间戳可能会因服务器所在的时区而异。有关详情,请参阅 CL:<a href="https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028" class="external">https://android.googlesource.com/platform/build/+/6c41036bcf35fe39162b50d27533f0f3bfab3028</a>。
+</p>
<h2 id="version_strings">版本字符串</h2>
-<p><strong>问题</strong>:APK 版本字符串通常包含附加到硬编码版本的 BUILD_NUMBER。即使 APK 中并未发生任何其他变更,APK 仍然会有所不同。</p>
+<p><strong>问题</strong>:APK 版本字符串通常包含附加到硬编码版本的 <code>BUILD_NUMBER</code>。即使 APK 中并未发生任何其他变更,APK 也仍然会有所不同。</p>
<p><strong>解决方案</strong>:从 APK 版本字符串中移除版本号。</p>
<p><strong>示例:</strong></p>
<ul>
- <li><a href="https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27">https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27</a></li>
- <li><a href="https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c">https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c</a></li>
+ <li><a href="https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27" class="external">https://android.googlesource.com/platform/packages/apps/Camera2/+/5e0f4cf699a4c7c95e2c38ae3babe6f20c258d27</a></li>
+ <li><a href="https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c" class="external">https://android.googlesource.com/platform/build/+/d75d893da8f97a5c7781142aaa7a16cf1dbb669c</a></li>
</ul>
-<h2 id="consistent_build_tools">一致的构建工具</h2>
+<h2 id="consistent_build_tools">一致的编译工具</h2>
-<p><strong>问题</strong>:生成安装文件的工具必须一致(相同的输入应始终产生相同的输出)。</p>
+<p><strong>问题</strong>:生成安装文件的工具必须一致(相同的输入应始终生成相同的输出)。</p>
-<p><strong>解决方案/示例</strong>:以下构建工具需要进行变更:</p>
+<p><strong>解决方案/示例</strong>:以下编译工具需要进行变更:</p>
<ul>
- <li><strong>NOTICE 文件创建工具</strong>。NOTICE 文件创建工具需要变更。请参阅 CL:
-<a href="https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64">https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64</a></li>
- <li><strong>Java Android 编译器套件 (Jack)</strong>。Jack 工具链需要更新,才能处理生成的构造函数排序的偶然性变更。请参阅 CL:
-<a href="https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b">https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b</a></li>
- <li><strong>ART AOT 编译器 (dex2oat)</strong>。ART 编译器二进制文件需要更新才能创建确定性图像。请参阅 CL:
-<a href="https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9">https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9</a></li>
- <li><strong>libpac.so 文件 (V8)</strong>。每个构建会创建不同的 <code>/system/lib/libpac.so</code> 文件,因为 V8 快照会针对每个构建发生变化。解决方案是移除快照。请参阅 CL:
-<a href="https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29">https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29</a></li>
- <li><strong>预先经过 dexopt 处理 (.odex) 的应用文件</strong>。预先经过 dexopt 处理 (.odex) 的文件包含 64 位系统上的未初始化填充。请参阅 CL:
-<a href="https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029">https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029</a></li>
+ <li><strong>NOTICE 文件创建工具</strong>。NOTICE 文件创建工具需要变更。请参阅 CL:<a href="https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64" class="external">https://android.googlesource.com/platform/build/+/8ae4984c2c8009e7a08e2a76b1762c2837ad4f64</a>。
+ </li>
+ <li><strong>Java Android 编译器套件 (Jack)</strong>。Jack 工具链需要更新才能处理生成的构造函数排序的偶然性变更。请参阅 CL:<a href="https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b" class="external">https://android.googlesource.com/toolchain/jack/+/056a5425b3ef57935206c19ecb198a89221ca64b</a>。</li>
+ <li><strong>ART AOT 编译器 (dex2oat)</strong>。ART 编译器二进制文件需要更新才能创建确定性图像。请参阅 CL:<a href="https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9" class="external">https://android.googlesource.com/platform/art/+/ace0dc1dd5480ad458e622085e51583653853fb9</a>。
+ </li>
+ <li><strong>libpac.so 文件 (V8)</strong>。每项编译会创建不同的 <code>/system/lib/libpac.so</code> 文件,因为 V8 快照会针对每项编译发生变更。解决方案是移除快照。请参阅 CL:<a href="https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29" class="external">https://android.googlesource.com/platform/external/v8/+/e537f38c36600fd0f3026adba6b3f4cbcee1fb29</a>。
+ </li>
+ <li><strong>预先经过 dexopt 处理 (.odex) 的应用文件</strong>。预先经过 dexopt 处理 (.odex) 的文件包含 64 位系统上的未初始化填充。请参阅 CL:<a href="https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029" class="external">https://android.googlesource.com/platform/art/+/34ed3afc41820c72a3c0ab9770be66b6668aa029</a>。
+ </li>
</ul>
-<h2 id="the_build_diff_tool">使用构建 diff 工具</h2>
+<h2 id="the_build_diff_tool">使用编译 diff 工具</h2>
-<p>对于无法消除构建相关文件变更的情况,我们提供构建 diff 工具 <code><a href="https://android.googlesource.com/platform/build/+/master/tools/releasetools/target_files_diff.py">target_files_diff.py</a></code> 来比较两个文件包。该工具会在两个构建之间执行递归 diff,从而排除常见的构建相关文件变更,例如:</p>
+<p>对于无法消除编译相关文件变更的情况,AOSP 纳入了编译 diff 工具 <code><a href="https://android.googlesource.com/platform/build/+/master/tools/releasetools/target_files_diff.py" class="external">target_files_diff.py</a></code>,以用于比较两个文件包。该工具会在两个编译之间执行递归 diff,从而排除常见的编译相关文件变更,例如:</p>
<ul>
- <li>构建输出中的预期变更(例如,由于版本号变更所导致)。</li>
- <li>由于当前构建系统中的已知问题所导致的变更。</li>
+ <li>编译输出中的预期变更(例如,由于版本号变更所导致)。</li>
+ <li>由于当前编译系统中的已知问题所导致的变更。</li>
</ul>
-<p>要使用构建 diff 工具,请运行以下命令:</p>
+<p>要使用编译 diff 工具,请运行以下命令:</p>
-<pre class="prettyprint">
-$ target_files_diff.py dir1 dir2
+<pre class="devsite-terminal devsite-click-to-copy">
+target_files_diff.py dir1 dir2
</pre>
-<p><code>dir1</code> 和 <code>dir2</code> 是包含每个构建的提取目标文件的基础目录。</p>
+<p><code>dir1</code> 和 <code>dir2</code> 是包含每个编译的提取目标文件的基础目录。</p>
+
+<h2 id="block-mapping-tool">使块分配保持一致</h2>
+<p>在非 A/B OTA 中,影响时间的因素之一是块移动。对于给定的文件,尽管其内容在两个编译之间会保持不变,但实际持有数据的块可能已发生变化。因此,更新程序会在 OTA 期间执行不必要的 I/O 来四处移动块。</p>
+
+<p>为了解决这个问题,我们在 Android 7.0 中扩展了 <code>make_ext4fs</code> 工具,该工具会尝试使块分配在各编译之间保持一致。<code>make_ext4fs</code> 会接受可选的 <code>-d base_fs</code> 标记,该标记会在生成 <code>ext4</code> 映像时尝试将文件分配给相同的块。您可以从上一个编译的目标文件 zip 文件(<code>IMAGES/system.map</code> 和 <code>IMAGES/vendor.map</code>)中提取块映射文件(即 <code>base_fs</code> 映射文件)。接下来,<code>base_fs</code> 文件便可以通过 <code>PRODUCT_SYSTEM_BASE_FS_PATH</code> 和 <code>PRODUCT_VENDOR_BASE_FS_PATH</code> 进行记录并指定。例如,</p>
+
+<pre class="devsite-click-to-copy">
+ PRODUCT_SYSTEM_BASE_FS_PATH := path/to/base_fs_files/base_system.map
+ PRODUCT_VENDOR_BASE_FS_PATH := path/to/base_fs_files/base_vendor.map
+</pre>
+
+<p>虽然这对减小整体的 OTA 更新包大小来说并无帮助,但它确实可以通过减少 I/O 量来改善 OTA 性能。</p>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/ota/tools.html b/zh-cn/devices/tech/ota/tools.html
index 5943e41..01a3154 100644
--- a/zh-cn/devices/tech/ota/tools.html
+++ b/zh-cn/devices/tech/ota/tools.html
@@ -26,26 +26,18 @@
<p>完整更新是指软件包将对设备的整个最终状态(系统分区、启动分区和恢复分区)进行更新。<i></i>只要设备能够接收软件包并启动恢复系统,软件包就可以安装所需的版本,而不受设备当前状态的影响。</p>
<p>示例:使用发布工具为假设的 <b>tardis</b> 设备构建完整更新:</p>
-<pre>
+<pre class="devsite-click-to-copy">
# first, build the target-files .zip
-% <b>. build/envsetup.sh && lunch tardis-eng</b>
-% <b>mkdir dist_output</b>
-% <b>make dist DIST_DIR=dist_output</b>
- [...]
-% <b>ls -l dist_output/*target_files*</b>
--rw-r----- 1 user eng 69965275 Sep 29 15:51 tardis-target_files.zip
+<code class="devsite-terminal">. build/envsetup.sh && lunch tardis-eng</code>
+<code class="devsite-terminal">mkdir dist_output</code>
+<code class="devsite-terminal">make dist DIST_DIR=dist_output</code>
</pre>
<p>target_files .zip 包含构建 OTA 软件包所需的所有内容。
</p>
-<pre>
-% <b>./build/tools/releasetools/ota_from_target_files \
- dist_output/tardis-target_files.zip ota_update.zip</b>
-unzipping target target-files...
-done.
-% <b>ls -l ota_update.zip</b>
--rw-r----- 1 user eng 62236561 Sep 29 15:58 ota_update.zip
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">./build/tools/releasetools/ota_from_target_files dist_output/tardis-target_files.zip ota_update.zip</code>
</pre>
<p>ota_update.zip 现已准备就绪,可以发送到测试设备(所有内容均使用测试密钥进行签名)。对于用户设备,请生成并使用自己的私钥,有关详情,请参阅<a href="/devices/tech/ota/sign_builds.html">签名版本以供发布</a>。
@@ -57,16 +49,8 @@
<li>更改的文件通常与之前的版本非常相似,因此软件包中只需包含针对两个文件之间的不同之处进行的编码。</li></ul>
<p>只有当设备具有构建相应软件包所使用的旧版本或源版本时,您才能在设备上安装增量更新软件包。要构建增量更新,您需要拥有上一个版本(您要更新的版本)中的 target_files .zip 以及新版本中的 target_files .zip。<i></i></p>
-<pre>
-% <b>./build/tools/releasetools/ota_from_target_files \
- -i PREVIOUS-tardis-target_files.zip \ </b># make incremental from this older version<b>
- dist_output/tardis-target_files.zip incremental_ota_update.zip</b>
-unzipping target target-files...
-unzipping source target-files...
- [...]
-done.
-% <b>ls -l incremental_ota_update.zip</b>
--rw-r----- 1 user eng 1175314 Sep 29 16:10 incremental_ota_update.zip
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">./build/tools/releasetools/ota_from_target_files -i PREVIOUS-tardis-target_files.zip dist_output/tardis-target_files.zip incremental_ota_update.zip # make incremental from the older version</code>
</pre>
<p>该版本与上一个版本非常类似,而且增量更新软件包(约 1 MB)比对应的完整更新软件包 (60 MB) 小得多。</p>
@@ -77,10 +61,10 @@
<p>更新软件包(<code>ota_update.zip</code>、<code>incremental_ota_update.zip</code>)是包含可执行二进制文件 <code>META-INF/com/google/android/update-binary</code> 的 .zip 文件。对软件包上的签名进行验证后,恢复进程会将该二进制文件解压到 <code>/tmp</code> 并运行它,然后传递以下参数:</p>
<ul>
<li><b>更新二进制 API 版本号</b>。如果向更新二进制文件传递的参数发生变化,此数字将递增。</li>
-<li><b>命令管道的文件描述符</b>。<i></i>更新程序可以使用此管道将命令发送回恢复二进制文件(主要用于界面变化,例如向用户指示进度)。</li>
+<li><b>命令管道的文件描述符</b><i></i>。更新程序可以使用此管道将命令发送回恢复二进制文件(主要用于界面变化,例如向用户指示进度)。</li>
<li><b>更新软件包 .zip 文件的文件名</b>。</li>
</ul>
<p>恢复软件包可以使用任何静态链接的二进制文件作为更新二进制文件。OTA 软件包构建工具使用更新程序(<code>bootable/recovery/updater</code> 中的源),该程序提供一种可以执行很多安装任务的简单脚本语言。您可以替换设备上运行的任何其他二进制文件。</p>
-<p>要详细了解更新程序二进制文件、edify 语法和内置函数,请参阅 <a href="/devices/tech/ota/inside_packages.html">OTA 软件包内部</a>。
+<p>要详细了解更新程序二进制文件、edify 语法和内置函数,请参阅 <a href="/devices/tech/ota/inside_packages.html">OTA 软件包内部探秘</a>。
</p></body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/perf/boot-times.html b/zh-cn/devices/tech/perf/boot-times.html
index 8b0baf2..9b07cb3 100644
--- a/zh-cn/devices/tech/perf/boot-times.html
+++ b/zh-cn/devices/tech/perf/boot-times.html
@@ -212,7 +212,7 @@
<h3 id="deferring-initialization">延迟初始化</h3>
<p>
-很多进程都在设备启动期间启动,但只有关键路径 (bootloader > kernel > init > file system mount > zygote > system server) 中的组件才会直接影响启动时间。使用早期内核日志来识别对启动 init 进程不重要的外设/组件,然后将这些外设/组件延迟到启动过程的后期来启动。
+很多进程都在设备启动期间启动,但只有关键路径 (bootloader > kernel > init > file system mount > zygote > system server) 中的组件才会直接影响启动时间。在内核启动期间执行 <strong>initcall</strong> 来识别对启动 init 进程不重要的外设/组件,然后将这些外设/组件延迟到启动过程的后期来启动。
</p>
<h2 id="optimizing-i-o-efficiency">优化 I/O 效率</h2>
@@ -377,6 +377,45 @@
采用文件级加密的设备可以在 zygote-start 触发器的早期阶段启动 zygote(默认情况下,zygote 会在 main 类中启动,比 zygote-start 晚得多)。这样做时,请确保允许 zygote 在所有 CPU 中运行(因为错误的 cpuset 设置可能会强制 zygote 在特定 CPU 中运行)。
</p>
+<h3 id="disable-power-saving">停用节电设置</h3>
+
+<p>
+在设备启动期间,可以停用 UFS 和/或 CPU 调节器等组件的节电设置。
+</p>
+<p class="aside"><strong>请注意</strong>:为了提高效率,应在充电器模式下启用节电设置。</p>
+
+<pre class="prettyprint">
+on init
+ # Disable UFS powersaving
+ write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 0
+ write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 0
+ write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 0
+ write /sys/module/lpm_levels/parameters/sleep_disabled Y
+on property:sys.boot_completed=1
+ # Enable UFS powersaving
+ write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
+ write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
+ write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
+ write /sys/module/lpm_levels/parameters/sleep_disabled N
+on charger
+ # Enable UFS powersaving
+ write /sys/devices/soc/${ro.boot.bootdevice}/clkscale_enable 1
+ write /sys/devices/soc/${ro.boot.bootdevice}/clkgate_enable 1
+ write /sys/devices/soc/${ro.boot.bootdevice}/hibern8_on_idle_enable 1
+ write /sys/class/typec/port0/port_type sink
+ write /sys/module/lpm_levels/parameters/sleep_disabled N</pre>
+
+<h3 id="defer-non-critical-initialization">推迟非关键初始化</h3>
+
+<p>
+非关键初始化(如 ZRAM)可以推迟到 boot_complete。
+</p>
+
+<pre class="prettyprint">
+on property:sys.boot_completed=1
+ # Enable ZRAM on boot_complete
+ swapon_all /vendor/etc/fstab.${ro.hardware}</pre>
+
<h2 id="optimizing-boot-animation">优化启动动画</h2>
<p>
@@ -415,7 +454,8 @@
</p>
<ul>
-<li><strong>使用简洁的正则表达式 (regex)</strong>。在为 <code>file_contexts</code> 中的 <code>sys/devices</code> 匹配 SELinux 政策时,格式糟糕的正则表达式可能会导致大量开销。例如,正则表达式 <code>/sys/devices/.*abc.*(/.*)?</code> 错误地强制扫描包含“abc”的所有 <code>/sys/devices</code> 子目录,导致 <code>/sys/devices/abc</code> 和 <code>/sys/devices/xyz/abc</code> 都成为匹配项。如果将此正则表达式修正为 <code>/sys/devices/[^/]*abc[^/]*(/.*)?</code> ,则只有 <code>/sys/devices/abc</code> 会成为匹配项。
+<li><strong>使用简洁的正则表达式 (regex)</strong>。在为 <code>file_contexts</code> 中的 <code>sys/devices</code> 匹配 SELinux 政策时,格式糟糕的正则表达式可能会导致大量开销。例如,正则表达式 <code>/sys/devices/.*abc.*(/.*)?</code> 错误地强制扫描包含“abc”的所有 <code>/sys/devices</code> 子目录,导致 <code>/sys/devices/abc</code> 和 <code>/sys/devices/xyz/abc</code> 都成为匹配项。
+如果将此正则表达式修正为 <code>/sys/devices/[^/]*abc[^/]*(/.*)?</code> ,则只有 <code>/sys/devices/abc</code> 会成为匹配项。
</li><li><strong>将标签移动到 </strong><a href="https://selinuxproject.org/page/FileStatements#genfscon">genfscon</a>。这一现有的 SELinux 功能会将文件匹配前缀传递到 SELinux 二进制文件的内核中,而内核会将这些前缀应用于内核生成的文件系统。这也有助于修复错误标记的内核创建的文件,从而防止用户空间进程之间可能出现的争用情况(试图在重新标记之前访问这些文件)。</li>
</ul>
diff --git a/zh-cn/devices/tech/perf/flash-wear.html b/zh-cn/devices/tech/perf/flash-wear.html
new file mode 100644
index 0000000..8635010
--- /dev/null
+++ b/zh-cn/devices/tech/perf/flash-wear.html
@@ -0,0 +1,113 @@
+<html devsite><head>
+ <title>Android Automotive 中的闪存磨损管理</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 Automotive 内部存储设备使用了支持上千次清空/写入周期的嵌入式多媒体卡 (eMMC);如果 eMMC 发生故障,系统可能会变得无法使用。由于汽车的使用寿命较长(通常为 10 年以上),因此 eMMC 必须非常稳定可靠。本页面介绍了 eMMC 行为,以及 OEM 如何降低 eMMC 发生故障的风险(从而避免 Android Automotive 系统发生故障)。
+</p>
+
+<h2 id="emmc-behavior">eMMC 行为</h2>
+
+<p>
+eMMC 设备使用耗损均衡技术来解决清空/写入限制的问题,具体方法是在整个系统内均匀地放置数据和分配写入操作(避免单个块因密集写入而发生故障)。eMMC 的预计使用寿命取决于以下因素:</p>
+
+<ul>
+<li><strong>写入量</strong>。在手机上,每天写入内部存储设备的数据量可能会超过 10GB。在 Android Automotive 实现中,由于应用数量有限,我们无法提供有关会有多少数据写入的真实数据。不过,据我们观察,当用户流式传输高品质音乐和使用导航时,每分钟写入 eMMC 的数据有 50MB。未来,可能会出现其他类型的写入密集型应用,例如持续录制和存储视频的中控台摄像头应用。另外,有些汽车是每天都会有几个小时处于行使状态的共享车辆。由于这些原因及其他原因,我们预计 Android Automotive 实现会面临比手机更多的 eMMC 写入量。</li>
+<li><strong>写入模式</strong>。写入和清空操作是在块中进行的。
+与不太频繁地在较大的区块中写入数据相比,在较小的区块中频繁地写入相同的数据量会更快地磨损 eMMC。</li>
+<li><strong>eMMC 的可用空间</strong>。较大的存储空间意味着耗损均衡算法可以将写入分摊到较多的块中。
+</li><li>耗损均衡技术。</li>
+<li><strong>环境因素</strong>。例如:工作温度范围通常介于 -20 和 85 摄氏度之间;如果温度超出此范围,eMMC 的使用寿命会进一步缩短。</li>
+</ul>
+
+<p>
+对于具有 16GB 可用空间和 3000 次清空/写入周期的 eMMC,我们估算的数据如下:</p>
+<table>
+ <tbody><tr>
+ <th>日写入量</th>
+ <td>16GB</td>
+ <td>32GB</td>
+ </tr>
+ <tr>
+ <th>预计使用寿命</th>
+ <td>10 年</td>
+ <td>5 年</td>
+ </tr>
+</tbody></table>
+
+<p>
+不过,随着可用存储空间的减少,系统可能会早在 eMMc 彻底磨损之前就停止正常运行,并且根据所使用的均衡技术和写入模式,eMMC 的使用寿命甚至可能会更短。此外,这方面的估算并没有将行为异常的应用或恶意应用的影响考虑在内,这些应用可能会在没有特殊权限的情况下将大量垃圾数据写入 eMMC 来攻击 Automotive 系统。
+</p>
+
+<p>
+要在潜在的 eMMC 故障实际发生之前就检测出来,应将适当的存储设备运行状况监控功能整合到整体系统运行状况监控功能中。
+</p>
+
+<h2 id="implementation">实现</h2>
+
+<p>
+借助 Android O 支持的功能,OEM 可以保护和监控 Android Automotive 的内部存储设备,并延长其使用寿命。
+</p>
+
+<h3 id="restricting-third-party-apps">限制第三方应用</h3>
+
+<p>
+为了保护 Android Automotive 系统的内部存储设备,Android O 支持 OEM 配置是否允许第三方应用安装在内部存储设备中(应用只能向其安装所在的分区写入数据)。要进行配置,请在资源叠加层中设置以下配置:
+</p>
+
+<pre class="prettyprint notranslate"><bool name="config_allow3rdPartyAppOnInternal">false</bool>
+</pre>
+
+<h3 id="reducing-flash-wear">减少闪存磨损</h3>
+
+<p>
+如果 OEM 担心内部存储设备上的闪存磨损问题,也可以增加 SD 卡,SD 卡支持足够快的数据写入速度,可用作合并存储设备。SD 卡具有以下行为:
+</p>
+
+<ul>
+<li>合并时,SD 卡会被加密,可以安全存储应用数据。</li>
+<li>SD 卡槽必须位于安全的位置(不要让用户频繁移除 SD 卡)。</li>
+<li>SD 卡不能用于在 Automotive 系统和计算机之间传输数据。</li>
+<li>弹出 SD 卡不会影响正在运行的系统。不过,除非需要更换,否则不应移除 SD 卡。</li>
+</ul>
+
+<p>
+要确保第二方应用(由汽车应用开发者构建的应用)可以安装在 SD 卡上(如果汽车提供授权的话),汽车应用开发者必须将 <code>android:<a href="https://developer.android.com/guide/topics/manifest/manifest-element.html#install">installLocation</a>=["auto"
+| "preferExternal"] </code> 纳入应用的清单文件中。
+</p>
+
+<p>
+如果汽车禁止将第三方应用安装在内部存储设备上(如<a href="#restricting-third-party-apps">限制第三方应用</a>中所述),则在没有上述标记(或者如果配置了 <code><a href="https://developer.android.com/guide/topics/manifest/manifest-element.html#install">installLocation</a>=internalOnly</code> 设置)的情况下,应用安装将会失败。
+</p>
+
+<h3 id="getting-disk-metrics-with-storaged">使用 storaged 获取磁盘指标</h3>
+
+<p>
+Android O 中引入了 storaged,这是一个新的系统服务,会对磁盘指标和 eMMc 指标进行采样并发布,例如有关总体磁盘使用情况、估算的 eMMC 使用寿命和磁盘 I/O 统计数据(按应用统计)的信息。<em></em>当内部存储设备开始出现故障或特定应用执行的磁盘 I/O 过多时,OEM 可以使用这些信息来向用户发出警告。有关详情,请参阅<a href="/devices/tech/debug/storaged">实现 storaged</a>。
+</p>
+
+<h2 id="validation">验证</h2>
+
+<p>
+此功能在 <code>PackageManager</code> 测试中进行测试。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/power/component.html b/zh-cn/devices/tech/power/component.html
index 8ae1344..7ce7842 100644
--- a/zh-cn/devices/tech/power/component.html
+++ b/zh-cn/devices/tech/power/component.html
@@ -57,16 +57,16 @@
<p>系统挂起可能会给功率测量造成不必要的误差,并使系统组件处于低功耗状态,而在这种状态下不适合测量活跃状态的功耗。要防止系统在屏幕关闭时进入挂起状态,请暂时使用部分唤醒锁。使用 USB 电缆将设备连接到开发主机,然后发出以下命令:</p>
-<pre>
-$ adb shell "echo temporary > /sys/power/wake_lock"
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell "echo temporary > /sys/power/wake_lock"
</pre>
<p>当使用 <code>wake_lock</code> 时,屏幕进入关闭状态不会触发系统挂起。(请记得在测量功耗之前先断开 USB 电缆与设备的连接。)</p>
<p>要移除唤醒锁,请使用以下命令:</p>
-<pre>
-$ adb shell "echo temporary > /sys/power/wake_unlock"
+<pre class="devsite-terminal devsite-click-to-copy">
+adb shell "echo temporary > /sys/power/wake_unlock"
</pre>
<h3 id="measure-suspend">测量系统挂起状态下的功耗</h3>
@@ -90,7 +90,7 @@
<p>您必须在电源配置文件的 <code>cpu.speeds</code> 条目中指定设备的可用 CPU 速率。要获取可用 CPU 速率列表,请运行以下命令:</p>
-<pre>
+<pre class="devsite-terminal devsite-click-to-copy">
adb shell cat /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state
</pre>
@@ -98,12 +98,12 @@
<p>如果某个平台的在线内核数量对功耗有很大的影响,您可能需要修改该平台的 cpufreq 驱动程序或调节器。大多数平台支持使用用户空间 cpufreq 调节器控制 CPU 速率以及使用 sysfs 接口来设置速率。例如,要在只有 1 个 CPU 的系统上或者所有 CPU 共享一个公共 cpufreq 策略的系统上将速率设为 200MHz,请使用系统控制台或 adb shell 运行以下命令:</p>
-<pre>
-echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
-echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
-echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq
-echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
-cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">echo userspace > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor</code>
+<code class="devsite-terminal">echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq</code>
+<code class="devsite-terminal">echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq</code>
+<code class="devsite-terminal">echo 200000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed</code>
+<code class="devsite-terminal">cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq</code>
</pre>
<p class="note">
@@ -113,7 +113,7 @@
<p>这些命令可确保新的速率不超出允许的范围,并设置新的速率,然后输出 CPU 实际运行的速率(用于验证)。如果执行前的当前最小速率高于 200000,则可能需要交换前两行的顺序,或者再次执行第一行,以在设置最大速率之前降低最小速率。</p>
<p>要测量 CPU 在不同速率下运行时所消耗的电流,请使用以下命令通过系统控制台将 CPU 置于 CPU 限制循环中:</p>
-<pre>
+<pre class="devsite-click-to-copy">
# while true; do true; done
</pre>
@@ -146,7 +146,7 @@
<p><code>wifi.on</code> 值测量 Wi-Fi 在启用但未主动发送或接收数据的状态下的功耗。该值通常是测量系统挂起(休眠)状态下启用/禁用 Wi-Fi 之间产生的电流增量。</p>
-<p><code>wifi.scan</code> 值测量接入点 Wi-Fi 扫描时的功耗。应用可以使用 WifiManager 类 <a href="http://developer.android.com/reference/android/net/wifi/WifiManager.html"><code>startScan()</code> API</a> 来触发 Wi-Fi 扫描。您也可以依次打开“设置”>“Wi-Fi”,这样 Wi-Fi 每隔几秒执行一次接入点扫描,扫描时功耗会明显上升,但必须从这些测量值中减去屏幕功率。</p>
+<p><code>wifi.scan</code> 值可测量接入点 WLAN 扫描时的功耗。应用可以使用 WifiManager 类 <a href="http://developer.android.com/reference/android/net/wifi/WifiManager.html"><code>startScan()</code></a> API 来触发 WLAN 扫描。您也可以依次打开“设置”>“WLAN”,这样 WLAN 每隔几秒执行一次接入点扫描,扫描时功耗会明显上升,但必须从这些测量值中减去屏幕功率。</p>
<p class="note">
<strong>注意</strong>:请使用受控设置(如 <a href="http://en.wikipedia.org/wiki/Iperf">iperf</a>)来生成网络收发流量。</p>
diff --git a/zh-cn/devices/tech/power/index.html b/zh-cn/devices/tech/power/index.html
index 1fea242..bdfe9be 100644
--- a/zh-cn/devices/tech/power/index.html
+++ b/zh-cn/devices/tech/power/index.html
@@ -47,6 +47,6 @@
<p>例如,显示屏电源配置文件列出了当显示屏开启状态下保持最低亮度和最高亮度时需消耗的电流量 (mA)。为了确定显示屏常亮时所需的电源成本(即由显示屏组件所消耗的电池量),框架会跟踪在各个亮度级别下维持的时间,然后将这些时间间隔乘以通过插值算法计算的显示亮度成本。</p>
-<p>该框架还会将每个应用的 CPU 时间乘以在特定速度运行 CPU 所需的毫安量。通过该计算方法可以创建一个应用电池消耗量(通过执行 CPU 代码)的相对排名(应用在前台的时间和包括后台活动在内的总时间将分别进行报告)。</p>
+<p>该框架还会将每个应用的 CPU 时间乘以在特定速度运行 CPU 所需的毫安量。通过该计算方法可以创建一个应用电池消耗量(通过执行 CPU 代码)的相对排名(应用在前台的时间和包括后台活动在内的总时间将分开报告)。</p>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/power/values.html b/zh-cn/devices/tech/power/values.html
index 9e1385c..1f82da0 100644
--- a/zh-cn/devices/tech/power/values.html
+++ b/zh-cn/devices/tech/power/values.html
@@ -47,7 +47,7 @@
</p><p>集群中激活的 CPU 以及速率示例:</p>
-<pre>
+<pre class="devsite-click-to-copy">
<array name="cpu.active.cluster0">
<value>200</value>
<value>300</value>
@@ -291,7 +291,7 @@
<tr>
<td>电池容量</td>
- <td>总电池容量 (以毫安时为单位)。</td>
+ <td>总电池容量(以毫安时为单位)。</td>
<td>3000 毫安时</td>
<td></td>
</tr>
diff --git a/zh-cn/devices/tech/settings/info-architecture.html b/zh-cn/devices/tech/settings/info-architecture.html
new file mode 100644
index 0000000..6deb57e
--- /dev/null
+++ b/zh-cn/devices/tech/settings/info-architecture.html
@@ -0,0 +1,224 @@
+<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>
+Android 8.0 为“设置”应用引入了全新的信息架构。新信息架构的目标是简化设置的整理方式,便于用户快速查找自定义 Android 设备所需的设置。
+</p>
+
+<h2 id="examples-and-source">示例和源代码</h2>
+
+<p>
+“设置”中的大多数页面目前都是使用新框架实现的。一个很好的例子是 DisplaySettings:<code>packages/apps/Settings/src/com/android/settings/DisplaySettings.java</code>
+</p>
+
+<p>
+重要组件的文件路径如下所示:
+</p>
+
+<h3 id="categorykey">CategoryKey</h3>
+
+<code>packages/SettingsLib/src/com/android/settingslib/drawer/CategoryKey.java</code>
+
+<h3 id="dashboardfragmentregistry">DashboardFragmentRegistry</h3>
+
+<code>packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragmentRegistry.java</code>
+
+<h3 id="dashboardfragment">DashboardFragment</h3>
+
+<code>packages/apps/Settings/src/com/android/settings/dashboard/DashboardFragment.java</code>
+
+<h3 id="preferencecontrollers">AbstractPreferenceController 和 PreferenceController</h3>
+
+<code>frameworks/base/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java</code>
+
+<code>packages/apps/Settings/src/com/android/settings/core/PreferenceController.java</code>
+
+<h2 id="implementation">实现</h2>
+
+<p>
+建议设备制造商调整现有的“设置”信息架构,并根据需要插入其他设置页面以适应合作伙伴的特定功能。将偏好设置从旧页面(实现为 SettingsPreferencePage)移到新页面(使用 DashboardFragment 实现)可能很复杂。旧页面的偏好设置在实现时可能没有创建 PreferenceController。
+</p>
+
+<p>
+因此将偏好设置移到 DashboardFragment 中时,合作伙伴需要创建一个 PreferenceController,并且先将代码移到控制器中,然后在新的 DashboardFragment 中对偏好设置实例化。重构过程相当简单,因为大部分操作只是移动现有代码。
+</p>
+
+<p>
+完成重构后,原始设备制造商 (OEM) 应提交带有测试的补丁程序 CL 以将其更改合并到上游。
+</p>
+
+<h3 id="plugin">插件样式信息架构</h3>
+
+<p>
+每个设置项都作为偏好设置进行实现。可以轻松地将偏好设置从一个页面移到另一个页面。
+</p>
+
+<p>
+为了方便移动多个设置,Android O 引入了包含设置项的插件样式托管方片段。设置项被建模为插件样式控制器。因此,设置页面由单个托管方片段和多个设置控制器构成。
+</p>
+
+<h3 id="dashboard-fragment">DashboardFragment</h3>
+
+<p>
+这是插件样式偏好设置控制器的托管方。该片段继承自 PreferenceFragment,并具有用于放大和更新静态偏好设置列表与动态偏好设置列表的钩子。
+</p>
+
+<h3 id="static-preferences">静态偏好设置</h3>
+
+<p>
+静态偏好设置列表在 XML 中使用<preference>
+标记定义。DashboardFragment 实现使用 getPreferenceScreenResId() 方法来定义哪个 XML 文件包含要显示的偏好设置静态列表。
+</preference></p>
+
+<h3 id="dynamic-preferences">动态偏好设置</h3>
+
+<p>
+动态项表示具有 intent 的图块,会引向外部或内部 Activity。通常,intent 会引向不同的设置页面。例如,“设置”首页中的“Google”设置项就是一个动态项。动态项在 AndroidManifest 中定义(参见下文),并通过 FeatureProvider(定义为 DashboardFeatureProvider)加载。
+</p>
+
+<p>
+请注意,动态设置的负载高于静态配置的设置,因此通常开发者应将设置实现为静态设置。但是,在以下任一情况下,动态设置非常有用:
+</p>
+
+<ul>
+<li>设置未在“设置”应用中直接实现(例如,注入由 OEM/运营商应用实现的设置)。</li>
+<li>设置应显示在“设置”首页上。</li>
+<li>您已具有设置的 Activity,不想要实现额外的静态配置。</li>
+</ul>
+
+<p>
+要将 Activity 配置为动态设置,您需要执行以下操作:
+</p>
+
+<ul>
+<li>将该 Activity 标记为动态设置。为此,只需将 intent 过滤器添加到该 Activity 即可。</li>
+<li>告诉“设置”应用其所属的类别。该类别是在 <strong>CategoryKey</strong> 中定义的常量。</li>
+<li>可选:显示设置时,添加总结文本。</li>
+</ul>
+
+<p>
+以下是从“设置”应用的 DisplaySettings 中摘取的示例。
+</p>
+
+<pre class="prettyprint">
+<activity android:name="Settings$DisplaySettingsActivity"
+ android:label="@string/display_settings"
+ android:icon="@drawable/ic_settings_display">
+ <!-- Mark the activity as a dynamic setting -->
+ <intent-filter>
+ <action android:name="com.android.settings.action.IA_SETTINGS" />
+ </intent-filter>
+ <!-- Tell Settings app which category it belongs to -->
+ <meta-data android:name="com.android.settings.category"
+ android:value="com.android.settings.category.ia.homepage" />
+ <!-- Add a summary text when the setting is displayed -->
+ <meta-data android:name="com.android.settings.summary"
+ android:resource="@string/display_dashboard_summary"/>
+ </activity>
+</pre>
+
+<p>
+在呈现时,片段将请求在 AndroidManifest 中定义的静态 XML 和动态设置偏好设置列表。无论在哪个来源中加载设置,DashboardFragment 都通过 PreferenceController 管理每个设置的处理逻辑(参见下文)。<strong></strong>然后,它们将以混合列表的形式显示在界面上。
+</p>
+
+<h3 id="preference-controller">PreferenceController</h3>
+
+<p>
+PreferenceController 包含与偏好设置互动的所有逻辑,包括显示/更新/编入搜索索引等。
+</p>
+
+<p>
+相应地,PreferenceController 的接口具有 isAvailable()、displayPreference()、handlePreferenceTreeClicked() 等的 API。有关每个 API 的详细文档可以在相应接口类中找到。
+</p>
+
+<p>
+在为片段安装偏好设置时,信息中心会提供一种在显示之前附加 PreferenceController 的方法。在安装时,控制器将连接到片段,以便将来的所有相关事件均发送到控制器。
+</p>
+
+<p>
+DashboardFragment 将在屏幕中保留 PreferenceController 的列表。在片段的 onCreate() 中,将为 isAvailable() 方法调用所有控制器,如果其返回 true,将调用 displayPreference() 来处理显示逻辑。
+</p>
+
+<h2 id="using-dashboardfragment">使用 DashboardFragment</h2>
+
+<h3 id="moving-preference">将偏好设置从页面 A 移到页面 B</h3>
+
+<p>
+如果偏好设置静态地列在原始页面的偏好设置 XML 文件中,请遵循下面的<strong>静态</strong>路径。否则,请遵循<strong>动态</strong>路径。
+</p>
+
+<h4 id="static-move">静态</h4>
+
+<ol>
+<li>查找原始页面和目标页面的偏好设置 XML 文件。</li>您可以从页面的 getPreferenceScreenResId() 方法中找到此信息。
+<li>移除原始页面的 XML 中的偏好设置。</li>
+<li>将偏好设置添加到目标页面的 XML 中。</li>
+<li>在原始页面的 Java 实现中移除此偏好设置的 PreferenceController。通常它在 getPreferenceController() 中。</li>
+<strong>注意</strong>:偏好设置可能没有 PreferenceController。
+<li>在目标页面的 getPreferenceController() 中实例化 PreferenceController。</li>
+</ol>
+
+<h4 id="dynamic-move">动态</h4>
+
+<ol>
+<li>查找原始页面和目标页面托管的类别。您可以在 <code>DashboardFragmentRegistry</code> 中找到此信息。</li>
+<li>打开包含您需要移动的设置的 <code>AndroidManifest.xml</code> 文件,并找到表示此设置的 Activity 条目。</li>
+<li>更改该 Activity 的“com.android.settings.category”元数据值,将值设置为新页面的类别键。</li>
+</ol>
+
+<h3 id="creating-a-new-preference">在页面中创建新的偏好设置</h3>
+
+<p>
+如果偏好设置静态地列在原始页面的偏好设置 XML 文件中,请遵循下面的<strong>静态</strong>路径。否则,请遵循<strong>动态</strong>路径。
+</p>
+
+<h4 id="static-create">静态</h4>
+
+<ol>
+<li>找到页面的偏好设置 XML 文件。您可以从页面的 getPreferenceScreenResId() 方法中找到此信息。</li>
+<li>在 XML 中添加一个新的偏好设置项。确保其具有独特的 android:key。</li>
+<li>在页面的 getPreferenceControllers() 方法中为此偏好设置实例化一个 PreferenceController。</li>如果该偏好设置已存在于其他地方,则表示其可能已具有 PreferenceController。您可以重新使用该 PreferenceController,无需构建新的 PreferenceController。
+</ol>
+
+<h4 id="dynamic-create">动态</h4>
+
+<ol>
+<li>查找原始页面和目标页面托管的类别。您可以在 <code>DashboardFragmentRegistry</code> 中找到此信息。</li>
+<li>在 AndroidManifest 中创建一个新的 Activity,并添加必要的元数据来定义设置。将“com.android.settings.category”的元数据值设置为与第 1 步中定义的值相同。</li>
+</ol>
+
+<h3 id="create-new-page">新建页面</h3>
+<ol>
+<li>创建一个继承自 DashboardFragment 的新片段。</li>
+<li>在 <code>DashboardFragmentRegistry</code> 中定义其类别。
+<p class="note"><strong>注意</strong>:此步骤是可选的。如果您在此页面中不需要任何动态偏好设置,则不需要提供类别键。</p></li>
+<li>遵循添加此页面所需设置的步骤进行操作。</li>
+</ol>
+
+<h2 id="validation">验证</h2>
+
+<ul>
+<li>在“设置”中运行 robolectric 测试,所有现有测试和新测试都应通过。
+</li><li>编译并安装“设置”,手动打开正在被修改的页面;该页面应立即更新。</li>
+</ul>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/settings/patterns-components.html b/zh-cn/devices/tech/settings/patterns-components.html
new file mode 100644
index 0000000..c57937a
--- /dev/null
+++ b/zh-cn/devices/tech/settings/patterns-components.html
@@ -0,0 +1,131 @@
+<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>
+在 Android 8.0 中,“设置”菜单中增加了一些能够涵盖常见使用情况的组件和微件。我们鼓励设备制造商和开发者在扩展“设置”应用时使用常用组件,以便新界面与现有的“设置”界面保持一致。
+</p>
+
+<p>
+以下是改进摘要:
+</p>
+
+<ul>
+<li>支持库偏好设置框架中的分隔线行为变化。现在,分隔线绘制在类别之间。</li>
+<li>ActionBar 主题背景变化。现在,ActionBar 使用浅色主题背景,且带有强调色文本。</li>
+<li>新的偏好设置布局。图标空间仍然存在,即使偏好设置没有图标时也是如此。</li>
+</ul>
+
+<p>
+新的微件:
+</p>
+
+<ul>
+<li>应用详细信息的标头微件。显示应用图标、应用标签等信息。</li>
+<li>某些页面上具有展开按钮。页面在打开时可以是收起形式,隐藏不太重要的项目,直到用户点击展开按钮。</li>
+<li>默认应用选择器界面:
+ <ul>
+ <li>该界面用于选择默认浏览器、默认手机应用等。</li>
+ <li>以前是一个对话框,现在是一个基于单选按钮的全屏界面。</li>
+ </ul>
+</li><li>“MasterSwitch”样式偏好设置。这是具有两个点击目标的偏好设置。左侧目标会导致子集化的片段或 intent。右侧目标是一个切换开关,针对整个页面控制开启/关闭。</li>
+</ul>
+
+<h2 id="examples-and-source">示例和源代码</h2>
+<ul>
+<li>分隔线行为
+ <ul>
+ <li>“设置”中的所有页面均经过修改以使用新的分隔线行为。</li>
+ <li>分隔线行为在以下文件中定义为一个 ThemeOverlay:<br />
+<code>packages/apps/Settings/res/values/styles_preference.xml</code></li>
+ </ul>
+</li>
+<li>ActionBar 主题背景变化
+ <ul>
+ <li>“设置”中的所有页面均经过修改以使用新的 ActionBar 主题背景。</li>
+ <li>主题背景在 Theme.DeviceDefault.Settings 中进行定义</li>
+ </ul>
+</li>
+<li>新的偏好设置布局
+ <ul>
+ <li>现在,“设置”中的许多页面都使用新的偏好设置布局。</li>
+ <li>您可以在以下位置找到代码:<br />
+<code>packages/apps/Settings/res/values/styles_preference.xml</code></li>
+ </ul>
+</li>
+<li>应用标头微件
+ <ul>
+ <li>“设置”中的大多数应用信息页面都已实现新的应用标头。</li>
+ <li>相关示例和代码可以在以下位置找到:<br />
+<code>packages/apps/Settings/src/com/android/settings/applications/AppHeaderController.java</code></li>
+ </ul>
+</li>
+<li>展开按钮
+ <ul>
+ <li>相关示例和代码可以在以下位置找到:<br />
+<code>packages/apps/Settings/src/com/android/settings/dashboard/ProgressiveDisclosureMixin.java</code>
+<p class="note"><strong>注意</strong>:此组件必须与 DashboardFragment 一起使用。(请在<a href="information-architecture.html">已更新的信息架构</a>中查看有关 DashboardFragment 的更多详情。)</p>
+ </li>
+ </ul>
+</li><li>默认应用选择器
+ <ul>
+ <li>您可以在以下位置找到基类的代码:<br />
+<code>packages/apps/Settings/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragment.java</code> </li>
+ <li>DefaultAppPickerFragment 有多个子类,每个子类均实现一个选择器用于不同的 intent。</li>
+ </ul>
+</li>
+<li>MasterSwitch 样式偏好设置<em></em>
+ <ul>
+ <li>代码位于以下位置:<code>packages/apps/Settings/src/com/android/settings/widget/MasterSwitchPreference.java</code></li>
+ <li>WLAN 主开关就是一个示例用例。您可以在以下位置找到示例:<code>packages/apps/Settings/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java</code></li>
+ </ul>
+</li>
+</ul>
+
+<h2 id="implementation">实现</h2>
+
+<p>
+设备制造商可以开始使用所有新的组件,无需额外设置。如果原始设备制造商 (OEM) 决定实现新的“MasterSwitch”样式偏好设置或默认应用选择器,则应查看本文档中的示例以及为每个组件编写的参考文件 (Javadoc),以获取更多详细信息。
+</p>
+
+<h2 id="customizing">自定义</h2>
+
+<ul>
+<li>分隔线行为。要更改分隔线的绘制方式,请更新“设置”分隔线的样式并更改以下各项的值:
+ <ul>
+ <li>allowDividerAbove</li>
+ <li>allowDividerBelow</li>
+ <li>allowDividerAfterLastItem</li>
+ </ul>
+</li>
+<li>ActionBar 主题背景颜色。Activity 应使用 <code>Theme.DeviceDefault.Settings</code> 作为其主题背景,或使用 <code>Theme.DeviceDefault.Settings</code> 作为父级来创建自定义主题背景。
+</li>
+<li>应用标头微件。在 AppHeaderController 中使用设置器来自定义每个字段,并在设置所有字段后调用 build()。
+</li>
+<li>展开按钮:
+ <ul>
+ <li>要完全停用该功能,请替换 ProgressiveDisclosureMixin 的构造函数,并将 keepExpanded 设为 true。</li>
+ <li>要自定义最初显示的项目数量,请在片段的 <code>onAttach(Context)</code> 方法中调用 <code>ProgressiveDisclosureMixin.setTileLimit()</code> 方法。</li>
+ </ul>
+</li>
+</ul>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/settings/personalized.html b/zh-cn/devices/tech/settings/personalized.html
new file mode 100644
index 0000000..5bf32e4
--- /dev/null
+++ b/zh-cn/devices/tech/settings/personalized.html
@@ -0,0 +1,54 @@
+<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>
+Android 的“设置”应用为 Android 8.0 用户提供了一系列建议。
+这些建议通常有助于改进手机功能,而且可以自定义(例如“设置‘勿扰’时间安排”或“开启 WLAN 通话功能”)。该功能会对建议进行排名(基于任何上下文信号或用户以往的建议采用情况)。
+</p>
+
+<p>
+当前的默认 Android 开放源代码项目 (AOSP) 排名模型基于用户以往的建议采用情况;这是一个简单的线性模型,它通过逻辑回归进行训练,从而正确地对互动信号进行加权。默认实现会使用显示、点击或拒绝的建议作为指标,同时根据这些事件的新近度对建议进行排名,并提高正确预测用户对这些建议的采用情况的概率。该模型是利用有限的已记录用户数据构建而成的。设备制造商 (OEM) 可以根据收集的任何数据开发自己的排名模型,并可能会在后期根据上下文信号校准排名。
+</p>
+
+<h2 id="implementation">实现</h2>
+
+<p>
+在 AOSP 中查找默认 <code>packages/apps/Settings/src/com/android/settings/dashboard/suggestions/SuggestionRanker.java</code> 实现。
+</p>
+
+<p>
+此功能由标记 <code>isSmartSuggestionEnabled</code> 进行保护,该标记默认情况下设置为 false。如果启用该功能(设置为 true),则该功能可使用默认 AOSP 实现运行,无需进行其他修改。原始设备制造商 (OEM) 可以使用默认实现或引入自己的实现来启用此功能。
+</p>
+
+<p>
+原始设备制造商 (OEM) 可以通过实现 <code>platform/packages/apps/Settings/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java
+</code> 功能并替换文件的 <code>rankSuggestions</code> 方法来自定义该功能。
+该方法会获得两个列表,其中包含建议图块及相应的 suggestionId。该方法应仅根据所需排名得分重新排列相应列表中图块的顺序。suggestionId 可以用于唯一标识建议,并根据排名实现(例如,与此特定建议的互动新近度)提取关于该建议的所需过往信息。
+</p>
+
+<h2 id="validation">验证</h2>
+
+<p>
+实现人员可以自行编写类似于 <code>packages/apps/Settings/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionRankerTest.java</code> 的单元测试以验证排名,从而确保其功能版本能够按预期运行。
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/settings/universal-search.html b/zh-cn/devices/tech/settings/universal-search.html
new file mode 100644
index 0000000..da7c78b
--- /dev/null
+++ b/zh-cn/devices/tech/settings/universal-search.html
@@ -0,0 +1,175 @@
+<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>
+Android 8.0 为“设置”菜单添加了经过扩展的搜索功能。<em></em>本文档介绍了如何添加设置,以及如何确保正确地将其加入“设置”搜索的索引中。
+</p>
+
+<h2 id="indexable-settings">创建可编入索引的设置</h2>
+
+<p>
+需要编入索引的每个“设置”片段都会实现 <code>Indexable</code> 接口,并且需要静态字段:
+
+</p><pre class="prettyprint">public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER
+</pre>
+
+<p>
+为您的片段进行设置以编入索引后,将其添加到以下位置中的 <code>SearchIndexableResources</code>:<br />
+<code>packages/apps/Settings/src/com/android/settings/search/SearchIndexableResources.java
+</code>
+</p>
+
+<h2 id="optional-methods">可选方法</h2>
+
+<p>该 <code>SearchIndexProvider</code> 接口有四种可选方法。</p>
+
+<h3 id="getXmlResourcesToIndex">getXmlResourcesToIndex</h3>
+ <ul>
+ <li>如果您的片段内容来自 <code>preference xml</code>,则替换此方法</li>
+ <li>以要编入索引的列表形式返回 XML 偏好设置。</li>
+ </ul>
+
+ <p>XML 资源示例:</p>
+
+<pre class="prettyprint">public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled) {
+ ArrayList<SearchIndexableResource> result = new ArrayList<SearchIndexableResource>();
+SearchIndexableResource sir = new SearchIndexableResource(context);
+ sir.xmlResId = R.xml.display_settings;
+ result.add(sir);
+
+ return result;
+}</pre>
+
+<h3 id="getRawDataToIndex">getRawDataToIndex</h3>
+ <ul>
+ <li>如果您的片段内容并非来自 <code>preference
+xml</code>,则替换此方法</li>
+ <li>返回要编入索引的原始数据 (<code>SearchIndexableRaw</code>) 的列表。</li>
+ </ul>
+
+<p>原始数据示例:</p>
+
+<pre class="prettyprint">
+public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+ final List<SearchIndexableRaw> result = new ArrayList<>();
+ final Resources res = context.getResources();
+
+ // Add fragment title
+ SearchIndexableRaw data = new SearchIndexableRaw(context);
+ data.title = res.getString(R.string.wifi_settings);
+ data.screenTitle = res.getString(R.string.wifi_settings);
+ data.keywords = res.getString(R.string.keywords_wifi);
+ data.key = DATA_KEY_REFERENCE;
+ result.add(data);
+
+ return result;
+}
+</pre>
+
+<h3 id="getRawDataToIndex">getNonIndexableKeys</h3>
+ <ul>
+ <li>如果您的片段为 <code>DashboardFragment</code>,则很少需要替换该方法。</li>
+ <li>返回不应针对给定用户、设备、配置等显示的结果相对应的键列表。此处提供的键应与 <code>SearchIndexableResource</code> 和 <code>SearchIndexableRaw</code> 中的 KEY 字段匹配。<em></em></li>
+ <li>例如:不应向从未在其设备中使用 SIM 卡的用户显示“流量消耗”。</li>
+ </ul>
+
+<p>不可编入索引的键示例:</p>
+
+<pre class="prettyprint">
+public List<String> getNonIndexableKeys(Context context) {
+ final List<String> keys = super.getNonIndexableKeys(context);
+ if (!checkIntentAction(context, "android.settings.TERMS")) {
+ keys.add(KEY_TERMS);
+ }
+ if (!checkIntentAction(context, "android.settings.LICENSE")) {
+ keys.add(KEY_LICENSE);
+ }
+ if (!checkIntentAction(context, "android.settings.COPYRIGHT")) {
+ keys.add(KEY_COPYRIGHT);
+ }
+ if (!checkIntentAction(context, "android.settings.WEBVIEW_LICENSE")) {
+ keys.add(KEY_WEBVIEW_LICENSE);
+ }
+ return keys;
+}</pre>
+
+<h3 id="getPreferenceControllers">getPreferenceControllers</h3>
+
+<p>
+返回与此片段相关联的偏好设置控制器列表。此列表用于形成内嵌结果、更新不可编入索引的内容等。
+</p>
+
+<p>
+因此,您希望在搜索中显示的所有内容都必须包含在 <code>getXmlResourcesToIndex</code> 或 <code>getRawDataToIndex</code> 中。
+</p>
+
+<h2 id="keywords">为您的设置添加关键字</h2>
+
+<p>
+为确保设置易于搜索,请添加与设置相关、用户可能用来搜索该设置的关键字。
+</p>
+
+<p>
+添加关键字时请注意以下事项:
+</p>
+ <ul>
+ <li>关键字是具有以下特征的词语的列表:用户不一定会看到,但可能属于在脑中构想相应设置的工作原理时会用到的字词。</li>
+ <li>关键字是用户可能会输入以访问您的设置的字词。</li>
+ <li>关键字可以是同义词,或者与设置相关联的任何字词。</li>
+ <li>例如,可以使用“静音”来查找“音量”设置。</li>
+ </ul>
+
+<h2 id="duplication">避免重复内容</h2>
+
+<p>
+如果您要无条件地排除某个设置页面,请移除原始页面的索引,以避免出现重复的结果。
+</p>
+
+ <ol>
+ <li>找到您要排除的页面的 <code>PreferenceFragment</code>。</li>
+ <li>移除 <code>SearchIndexProvider</code>。</li>
+ </ol>
+
+<h2 id="validation">验证</h2>
+
+<p>
+要测试新设置的可搜索性,请执行以下操作:
+</p>
+
+ <ol>
+ <li>在设备上安装最新版本的 Android O。</li>
+ <li>通过依次选择以下各项让数据库重新编制索引:</li>
+<em>设置 > 应用和通知 > 应用信息 > 设置 > 存储 > <strong>清除数据</strong></em>
+ <li>验证目标设置是否显示在搜索结果中。<br />
+ 搜索设置的标题前缀将与该设置匹配。</li>
+ </ol>
+
+<p>
+可以运行以下 robolectric 测试来验证此功能的实现:<br />
+<code>packages/apps/Settings/tests/robotests/src/com/android/settings/search</code>
+</p>
+
+<p>
+编译目标为:<code>RunSettingsRoboTests</code>
+</p>
+
+</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/lifecycle.html b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/lifecycle.html
index df07502..8b0c1ec 100644
--- a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/lifecycle.html
+++ b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/lifecycle.html
@@ -32,7 +32,8 @@
<p>对测试生命周期进行独立分段的目的是方便重复使用。使用该设计,开发者可以创建一次测试,然后集成者可以创建不同的配置,以便在不同环境中运行该测试。例如,他们可以创建一项配置,该配置可以在本地计算机上运行测试并将测试结果转储到 stdout。然后,他们可以创建执行相同测试的第二个配置,但使用不同的测试调用监听器将测试结果存储在数据库中。他们还可能设计第三个配置,用于从某处的测试实验室进行连续测试。</p>
-<p>这里顺便说明一下,一个配置加上相关命令行参数(由测试运行者提供)一起称为<b>命令</b>。当 TF 将 <code>ITestDevice</code> 与命令配对并执行该命令时,后续对象称为<b>调用</b>。简而言之,调用包含贯穿整个生命周期的完整 TF 测试执行过程。</p>
+<p>这里顺便说明一下,一个配置加上相关命令行参数(由测试运行者提供)一起称为<b>命令</b>。当 TF 将某个命令与 <code>ITestDevice</code> 配对并执行该命令时,后续对象称为<b>调用</b>。
+简而言之,调用包含贯穿整个生命周期的完整 TF 测试执行过程。</p>
<h3>配置的附加组件</h3>
<ul>
diff --git a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/machine_setup.html b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/machine_setup.html
index 780ee22..4b7c460 100644
--- a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/machine_setup.html
+++ b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/machine_setup.html
@@ -26,7 +26,7 @@
<h2>创建 TradeFed</h2>
<p>在 Android 源代码树的根目录处:</p>
-<pre>
+<pre class="devsite-click-to-copy">
<code class="devsite-terminal">source ./build/make/envsetup.sh</code>
<code class="devsite-terminal">lunch <device-target></code>
<code class="devsite-terminal">make tradefed-all -j8</code>
@@ -35,12 +35,12 @@
<h2>使用命令行运行</h2>
<p>TradeFed 要求使用 <code>$PATH</code> 中的实用工具 <code>adb</code>:</p>
-<pre class="devsite-terminal">
+<pre class="devsite-terminal devsite-click-to-copy">
export PATH=$PATH:<path/to/adb>
</pre>
<p>创建 TradeFed 后,<code>tradefed.sh</code> 启动器脚本便可供从您的路径进行访问。要启动 Trade Federation 控制台:</p>
-<pre class="devsite-terminal">
+<pre class="devsite-terminal devsite-click-to-copy">
tradefed.sh
</pre>
<p>现在,您的 Trade Federation 环境即已搭建完毕。
diff --git a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/options.html b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/options.html
index 88277ff..6e8ecde 100644
--- a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/options.html
+++ b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/options.html
@@ -22,13 +22,14 @@
<p>选项处理是 Trade Federation 模块化方法的核心。具体而言,选项是一种机制,让开发者、集成者和测试运行者通过该机制可以共同协作,而不会重复相互的工作。简单地说,实现选项处理后,开发者可将 Java 类成员标记为可配置,届时该成员的值可被集成者增强或覆盖,并且随后可被测试运行者增强或覆盖。该机制适用于所有 Java 固有类型,以及固有类型的任何 <code>Map</code> 或 <code>Collection</code>。</p>
-<p class="note"><strong>注意</strong>:选项处理机制仅适用于实现<a href="lifecycle.html">测试生命周期</a>内包含的接口之一的类,并且仅当该类由生命周期机制实例化时才适用。<em></em></p>
+<p class="note"><strong>注意</strong>:选项处理机制仅适用于实现<a href="lifecycle.html">测试生命周期</a>中包含的接口之一的类,并且仅当该类由生命周期系统实例化后才适用。<em></em></p>
<h2 id="developer">开发者</h2>
-<p>要开始使用,开发者需要为成员添加 <code><a href="https://android.googlesource.com/platform/tools/tradefederation/+/master/src/com/android/tradefed/config/Option.java">@Option</a></code> 注释。<!-- note: javadoc for the Option class is broken -->开发者需要至少指定 <code>name</code> 和 <code>description</code> 值,这两个值指定与该选项关联的参数名称和说明(后者在命令使用 <code>--help</code> 或 <code>--help-all</code> 运行时在 TF 控制台中显示)。</p>
+<p>要开始使用,开发者需要为成员添加 <code><a href="https://android.googlesource.com/platform/tools/tradefederation/+/master/src/com/android/tradefed/config/Option.java">@Option</a></code> 注释。<!-- note: javadoc for the Option class is broken -->开发者需要至少指定 <code>name</code> 和 <code>description</code> 值,这两个值指定了与该选项关联的参数名称和说明(后者在命令使用 -<code>--help</code> 或 <code>--help-all</code> 运行时会在 TF 控制台中显示)。</p>
<p>举例来说,假设我们要构建一个功能完善的电话测试,我们会在测试中拨打各种电话号码,并预期在每个号码连接后收到一系列 DTMF 音。</p>
-<code><pre>public class PhoneCallFuncTest extends IRemoteTest {
+<pre class="prettyprint">
+public class PhoneCallFuncTest extends IRemoteTest {
@Option(name = "timeout", description = "How long to wait for connection, in millis")
private long mWaitTime = 30 * 1000; // 30 seconds
@@ -38,36 +39,43 @@
public PhoneCallFuncTest() {
mCalls.add("123-456-7890", "01134"); // default
- }</pre></code>
+ }
+</pre>
<p>以上就是开发者为该测试设置两个配置点的所有要求。开发者随后可以正常离开并使用 <code>mWaitTime</code> 和 <code>mCalls</code>,无需特别留意它们可进行配置这一事实。由于 <code>@Option</code> 字段在类实例化之后、<code>run</code> 方法调用之前设置,因此实现人员可以轻松为 <code>Map</code> 和 <code>Collection</code> 字段设置默认值或执行某类筛选操作,否则只能附加这些字段。</p>
<h2 id="integrator">集成者</h2>
<p>集成者的工作重心是编写 XML 格式的配置。该配置格式允许集成者为任何 <code>@Option</code> 字段设置(或附加)值。例如,假设集成者想要定义调用默认数值的低延迟测试,以及调用各种数值的运行时间较长的测试。集成者可以创建一对配置,可能如下所示:</p>
-<code><pre><?xml version="1.0" encoding="utf-8"?>
+<pre class="prettyprint">
+<?xml version="1.0" encoding="utf-8"?>
<configuration description="low-latency default test; low-latency.xml">
<test class="com.example.PhoneCallFuncTest">
<option name="timeout" value="5000" />
</test>
-</configuration></pre></code>
+</configuration></pre>
-<code><pre><?xml version="1.0" encoding="utf-8"?>
+<pre class="prettyprint">
+<?xml version="1.0" encoding="utf-8"?>
<configuration description="call a bunch of numbers; many-numbers.xml">
<test class="com.example.PhoneCallFuncTest">
<option name="call" key="111-111-1111" value="#*#*TEST1*#*#" />
<option name="call" key="222-222-2222" value="#*#*TEST2*#*#" />
<!-- ... -->
</test>
-</configuration></pre></code>
+</configuration>
+</pre>
<h2 id="testrunner">测试运行者</h2>
<p>测试运行者也可以通过 Trade Federation 控制台访问这些配置点。首先也是最重要的是,他们要使用 <code>run command <name></code>(简称 <code>run <name></code>)指令运行一个命令(即一个配置及其所有参数)。除此之外,他们可以指定任何参数列表作为命令的一部分,这可能替换或附加到各个配置内的生命周期对象指定的字段。</p>
<p>要使用 <code>many-numbers</code> 电话号码运行低延迟测试,测试运行者可以执行:</p>
-<code><pre>tf >run low-latency.xml --call 111-111-1111 #*#*TEST1*#*# --call 222-222-2222 #*#*TEST2*#*#</pre></code>
+<pre class="devsite-click-to-copy">
+tf> run low-latency.xml --call 111-111-1111 #*#*TEST1*#*# --call 222-222-2222 #*#*TEST2*#*#
+</pre>
<p>或者,要从相反方向获得类似的效果,测试运行者可以减少 <code>many-numbers</code> 测试的等待时间:</p>
-<code></code><pre><code>tf >run many-numbers.xml --timeout 5000</code></pre>
+<pre class="devsite-click-to-copy">
+tf> run many-numbers.xml --timeout 5000</pre>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/vts.html b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/vts.html
index ef2a501..cf8a9df 100644
--- a/zh-cn/devices/tech/test_infra/tradefed/fundamentals/vts.html
+++ b/zh-cn/devices/tech/test_infra/tradefed/fundamentals/vts.html
@@ -26,27 +26,41 @@
<p>要设置测试环境,请按以下步骤操作:</p>
<ol>
<li>安装 Python 开发工具包:
-<pre><code>$ sudo apt-get install python-dev</code></pre></li>
+<pre class="devsite-terminal devsite-click-to-copy">
+sudo apt-get install python-dev
+</pre>
+</li>
<li>安装协议缓冲区工具(适用于 Python):
-<pre><code>$ sudo apt-get install python-protobuf<br />
-$ sudo apt-get install protobuf-compiler
-</code></pre></li>
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">sudo apt-get install python-protobuf</code>
+<code class="devsite-terminal">sudo apt-get install protobuf-compiler</code>
+</pre>
+</li>
<li>安装 Python 虚拟环境相关工具:
-<pre><code>$ sudo apt-get install python-virtualenv<br />
-$ sudo apt-get install python-pip
-</code></pre></li></ol>
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">sudo apt-get install python-virtualenv</code>
+<code class="devsite-terminal">sudo apt-get install python-pip</code>
+</pre>
+</li>
+</ol>
<h2 id="test">测试补丁</h2>
<p>要测试补丁,请按以下步骤操作:</p>
<ol>
<li>构建 VTS 主机端软件包:
-<pre><code>$ . build/envsetup.sh
-$ lunch aosp_arm64-userdebug
-$ make vts -j</code></pre></li>
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">. build/envsetup.sh</code>
+<code class="devsite-terminal">lunch aosp_arm64-userdebug</code>
+<code class="devsite-terminal">make vts -j</code>
+</pre>
+</li>
<li>运行默认的 VTS 测试:
-<pre><code>$ vts-tradefed<br />
-> run vts // where vts is the test plan name
-</code></pre></li></ol>
+<pre class="devsite-click-to-copy">
+<code class="devsite-terminal">vts-tradefed</code>
+tf> run vts // where vts is the test plan name
+</pre>
+</li>
+</ol>
<h2 id="plans">VTS 计划</h2>
<p>可用的 VTS 测试计划包括:</p>
@@ -77,6 +91,6 @@
<p>要查看所有计划的列表,请参阅 <code><a href="https://android.googlesource.com/platform/test/vts/+/master/tools/vts-tradefed/res/config/plans.md">/test/vts/tools/vts-tradefed/res/config.md</a></code>。</p>
<h2 id="support">支持</h2>
-<p>您可以在 <code><a href=" https://android.googlesource.com/platform/test/vts/+/master/README.md">/test/vts/doc</a></code> 中查看用户手册。有关 VTS 的问题,请加入 <a href="https://groups.google.com/forum/#!forum/android-vts">[email protected]</a> 网上论坛。</p>
+<p>您可以在 <code><a href=" https://android.googlesource.com/platform/test/vts/+/master/README.md">/test/vts/doc</a></code> 下查看用户手册。有关 VTS 的问题,请加入 <a href="https://groups.google.com/forum/#!forum/android-vts">[email protected]</a> 网上论坛。</p>
</body></html>
\ No newline at end of file
diff --git a/zh-cn/devices/tech/vts/performance.html b/zh-cn/devices/tech/vts/performance.html
index a2c14dc..31eaa4e 100644
--- a/zh-cn/devices/tech/vts/performance.html
+++ b/zh-cn/devices/tech/vts/performance.html
@@ -117,8 +117,8 @@
<p>吞吐量测试是针对 binder/hwbinder 事务吞吐量而运行的。在未过载的系统中,延迟气泡很少,而且只要迭代的次数足够多,就可以消除其影响。</p>
<ul>
-<li><strong>binder</strong> 吞吐量测试位于 <code>system/libhwbinder/vts/performance/Benchmark_binder.cpp</code> 下。</li>
-<li><strong>hwbinder</strong> 吞吐量测试位于 <code>system/libhwbinder/vts/performance/Benchmark.cpp</code> 下。</li>
+<li><strong>binder</strong> 吞吐量测试位于 <code>system/libhwbinder/vts/performance/Benchmark_binder.cpp</code> 中。</li>
+<li><strong>hwbinder</strong> 吞吐量测试位于 <code>system/libhwbinder/vts/performance/Benchmark.cpp</code> 中。</li>
</ul>
<h3 id="throughput-results">测试结果</h3>
@@ -289,7 +289,7 @@
</dl>
-<p class="note"><strong>注意</strong>:后台负荷可能会影响延迟测试中的吞吐量结果和 <code>other_ms</code> 元组。只要后台负荷的优先级低于 <code>fifo_ms</code>,就可能只有 <code>RT-fifo</code> 会显示类似的结果。</p>
+<p class="note"><strong>注意</strong>:后台负荷可能会影响延迟测试中的吞吐量结果和 <code>other_ms</code> 元组。只要后台负荷的优先级低于 <code>RT-fifo</code>,就可能只有 <code>fifo_ms</code> 会显示类似的结果。</p>
<h4 id="pair-values">指定对值</h4>
<p>每个客户端进程都会与其专用的服务器进程配对,且每一对都可能会独立调度到任何 CPU。不过,只要同步标记是 <code>honor</code>,事务期间应该就不会出现 CPU 迁移的情况。</p>
@@ -301,7 +301,7 @@
<p>经过大量用户场景测试(在合格产品上运行延迟测试),我们决定将 2.5 毫秒定为需要满足的截止时间要求。对于具有更高要求的新应用(如每秒 1000 张照片),此截止时间值将发生变化。</p>
<h4 id="verbose">指定详细输出</h4>
-<p>使用 <code>-v</code> 选项显示详细输出。示例:</p>
+<p>使用 <code>-v</code> 选项显示详细输出。例如:</p>
<pre class="devsite-click-to-copy">
<code class="devsite-terminal">libhwbinder_latency -i 1 -v</code>
@@ -334,13 +334,13 @@
<ul>
<li><font style="color:orange">服务线程</font>使用 <code>SCHED_OTHER</code> 优先级创建,且与 <code>pid
-8674</code> 要一起在 <code>CPU:1</code> 中运行。</li>
-<li>随后,<font style="color:blue">第一个事务</font>由 <code>fifo-caller</code> 启动。为处理该事务,hwbinder 会将服务器 (<code>pid: 8674 tid: 8676</code>) 的优先级升级到 99,并使用瞬态调度类别(输出为 <code>???</code>)对其进行标记。接下来,调度程序会将服务器进程置于 <code>CPU:0</code> 中,以运行该进程并将它与其客户端使用的同一 CPU 进行同步。</li>
+8674</code> 一起在 <code>CPU:1</code> 中运行。</li>
+<li>随后,由 <code>fifo-caller</code> 启动<font style="color:blue">第一个事务</font>。为处理该事务,hwbinder 会将服务器 (<code>pid: 8674 tid: 8676</code>) 的优先级升级到 99,并使用瞬态调度类别(输出为 <code>???</code>)对其进行标记。接下来,调度程序会将服务器进程置于 <code>CPU:0</code> 中,以运行该进程并将它与其客户端使用的同一 CPU 进行同步。</li>
<li><font style="color:green">第二个事务</font>调用程序的优先级为 <code>SCHED_OTHER</code>。服务器自行降级并为优先级为 <code>SCHED_OTHER</code> 的调用程序提供服务。</li>
</ul>
<h4 id="trace">使用跟踪记录进行调试</h4>
-<p>您可以指定 <code>-trace</code> 选项来调试延迟问题。使用该选项时,延迟测试会在检测到不良延迟时停止跟踪日志记录。示例:</p>
+<p>您可以指定 <code>-trace</code> 选项来调试延迟问题。使用该选项时,延迟测试会在检测到不良延迟时停止跟踪日志记录。例如:</p>
<pre class="prettyprint">
<code class="devsite-terminal">atrace --async_start -b 8000 -c sched idle workq binder_driver sync freq</code>