设备端个性化 (ODP) 旨在保护最终用户的信息,不让应用获取用户的确切信息。应用使用 ODP 为最终用户自定义其产品和服务,但无法查看为用户做出的确切自定义设置(除非应用与最终用户之间存在 ODP 之外的直接互动)。对于包含机器学习模型或统计分析的应用,ODP 提供了一组服务和算法,以确保使用适当的差分隐私机制对这些模型和分析进行适当的匿名化处理。如需了解详情,请参阅设备端个性化说明。
ODP 在 IsolatedProcess 中运行开发者代码,该 IsolatedProcess 无法直接访问网络、本地磁盘或设备上运行的其他服务,但可以访问以下本地持久性数据源:
RemoteData- 从远程开发者运营的后端下载的不可变键值对数据(如果适用)。LocalData- 开发者本地持久保存的可变键值对数据(如果适用)。UserData- 平台提供的用户数据。
支持以下输出:
- 持久性输出:这些输出可用于未来的本地处理,生成显示输出、联邦学习辅助的模型训练或联邦分析辅助的跨设备统计分析。
- 显示的输出:
- 开发者可以返回由 ODP 在
SurfaceView内的WebView中呈现的 HTML。呈现的内容不会对调用应用可见。 - 开发者可以在 HTML 输出中嵌入 ODP 提供的事件网址,以触发对用户与呈现的 HTML 的互动进行记录和处理。ODP 会拦截对这些网址的请求,并调用代码来生成写入
EVENTS表的数据。
- 开发者可以返回由 ODP 在
客户端应用和 SDK 可以调用 ODP,以使用 ODP API 在 SurfaceView 中显示 HTML 内容。在 SurfaceView 中呈现的内容对调用方应用不可见。客户端应用或 SDK 可以是与使用 ODP 进行开发的实体不同的实体。
ODP 服务管理希望调用 ODP 以在其界面中显示个性化内容的客户端应用。它会从开发者提供的端点下载内容,并调用逻辑来对下载的数据进行后处理。它还负责协调 IsolatedProcess 与其他服务和应用之间的所有通信。
客户端应用使用 OnDevicePersonalizationManager 类中的方法与在 IsolatedProcess 中运行的开发者代码进行交互。在 IsolatedProcess 中运行的开发者代码会扩展 IsolatedService 类并实现 IsolatedWorker 接口。IsolatedService 需要为每个请求创建一个 IsolatedWorker 实例。
下图显示了 OnDevicePersonalizationManager 和 IsolatedWorker 中各方法之间的关系。
OnDevicePersonalizationManager 与 IsolatedWorker 之间关系的示意图。客户端应用使用 execute 方法(包含名为 IsolatedService 的参数)调用 ODP。ODP 服务将调用转发到 IsolatedWorker 的 onExecute 方法。IsolatedWorker 会返回要持久保存的记录和要显示的内容。ODP 服务将持久性输出写入 REQUESTS 或 EVENTS 表,并向客户端应用返回显示输出的不透明引用。客户端应用可以在未来的 requestSurfacePackage 调用中使用此不透明引用,以在其界面中显示任何显示内容。
持久性输出
在开发者实现的 onExecute 返回后,ODP 服务会在 REQUESTS 表中保留一条记录。REQUESTS 表中的每条记录都包含 ODP 服务生成的一些常见请求级数据,以及返回的 Rows 列表。每个 Row 都包含一个 (key, value) 对列表。每个值都是标量、字符串或 blob。数值可以在汇总后报告,而字符串或 blob 数据可以在应用本地或中央差分隐私后报告。开发者还可以将后续用户互动事件写入 EVENTS 表中,EVENTS 表中的每条记录都与 REQUESTS 表中的一行相关联。ODP 服务会透明地记录每个记录的时间戳、调用应用的软件包名称和 ODP 开发者的 APK。
准备工作
在开始使用 ODP 进行开发之前,您需要设置软件包清单并启用开发者模式。
软件包清单设置
如需使用 ODP,您需要满足以下条件:
AndroidManifest.xml中的<property>标记,指向软件包中包含 ODP 配置信息的 XML 资源。AndroidManifest.xml中的<service>标记,用于标识扩展IsolatedService的类,如以下示例所示。<service>标记中的服务必须将属性exported和isolatedProcess设置为true。- 在第 1 步中指定的 XML 资源中,用于标识第 2 步中的服务类的
<service>标记。<service>标记还必须在标记本身内包含其他特定于 ODP 的设置,如第二个示例所示。
AndroidManifest.xml
<!-- Contents of AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.odpsample" >
<application android:label="OdpSample">
<!-- XML resource that contains other ODP settings. -->
<property android:name="android.ondevicepersonalization.ON_DEVICE_PERSONALIZATION_CONFIG"
android:resource="@xml/OdpSettings"></property>
<!-- The service that ODP binds to. -->
<service android:name="com.example.odpsample.SampleService"
android:exported="true" android:isolatedProcess="true" />
</application>
</manifest>
XML 资源中的 ODP 特定清单
<property> 标记中指定的 XML 资源文件还必须在 <service> 标记中声明服务类,并指定 ODP 将从中下载内容以填充 RemoteData 表的网址端点,如以下示例所示。如果您使用的是联邦计算功能,还需要指定联邦计算客户端将连接到的联邦计算服务器网址端点。
<!-- Contents of res/xml/OdpSettings.xml -->
<on-device-personalization>
<!-- Name of the service subclass -->
<service name="com.example.odpsample.SampleService">
<!-- If this tag is present, ODP will periodically poll this URL and
download content to populate REMOTE_DATA. Developers that do not need to
download content from their servers can skip this tag. -->
<download-settings url="https://example.com/get" />
<!-- If you want to use federated compute feature to train a model, you
need to specify this tag. -->
<federated-compute-settings url="https://fcpserver.example.com/" />
</service>
</on-device-personalization>
启用开发者模式
按照 Android Studio 文档的启用开发者选项部分中的说明启用开发者模式。
开关和标志设置
ODP 具有一组用于控制特定功能的开关和标志:
- _global_killswitch:所有 ODP 功能的全局开关;设置为 false 可使用 ODP
- _federated_compute_kill_switch: _用于控制 ODP 的所有训练(联邦学习)功能的开关;设置为 false 可使用训练功能
- _caller_app_allowlist:控制哪些应用可以调用 ODP,应用(软件包名称,[可选] 证书)可以添加到此处,也可以将其设置为 * 以允许所有应用调用
- _isolated_service_allowlist:控制哪些服务可以在隔离的服务进程中运行。
您可以运行以下命令,将所有开关和标志配置为不受限制地使用 ODP:
# Set flags and killswitches
adb shell device_config set_sync_disabled_for_tests persistent
adb shell device_config put on_device_personalization global_kill_switch false
adb shell device_config put on_device_personalization federated_compute_kill_switch false
adb shell device_config put on_device_personalization caller_app_allow_list \"*\"
adb shell device_config put on_device_personalization isolated_service_allow_list \"*\"
设备端 API
请参阅 ODP 的 Android API 参考文档。
与 IsolatedService 的互动
IsolatedService 类是一个抽象基类,所有打算针对 ODP 进行开发的开发者都必须扩展该类,并在其软件包清单中声明该类在隔离进程中运行。ODP 服务会在隔离进程中启动此服务,并向其发出请求。IsolatedService 从 ODP 服务接收请求,并创建 IsolatedWorker 来处理该请求。
开发者需要实现 IsolatedWorker 接口中的方法,以处理客户端应用请求、下载完成情况以及由渲染的 HTML 触发的事件。所有这些方法都有默认的空操作实现,因此开发者可以跳过他们不感兴趣的方法的实现。
OnDevicePersonalizationManager 类提供了一个 API,供应用和 SDK 与在独立进程中运行的开发者实现的 IsolatedService 进行交互。以下是一些预期用例:
生成要在 SurfaceView 中显示的 HTML 内容
如需生成要显示的内容,调用应用可以使用返回的 SurfacePackageToken 对象在后续的 requestSurfacePackage 调用中请求在 SurfaceView 中呈现结果。OnDevicePersonalizationManager#execute
成功后,系统会使用由 ODP 服务渲染的视图的 SurfacePackage 调用接收器。客户端应用需要在其视图层次结构中将 SurfacePackage 插入到 SurfaceView 中。
当应用使用先前 OnDevicePersonalizationManager#execute 调用返回的 SurfacePackageToken 进行 requestSurfacePackage 调用时,ODP 服务会调用 IsolatedWorker#onRender 来获取要在受限框架内呈现的 HTML 代码段。在此阶段,开发者无法访问 LocalData 或 UserData。这样可以防止开发者在生成的 HTML 中将可能敏感的 UserData 嵌入到资源提取网址中。开发者可以使用 IsolatedService#getEventUrlProvider 生成跟踪网址,以包含在生成的 HTML 中。呈现 HTML 时,ODP 服务会拦截对这些网址的请求并调用 IsolatedWorker#onEvent。在实现 onRender() 时,可以调用 getRemoteData()。
跟踪 HTML 内容中的事件
EventUrlProvider 类提供了一些 API,用于生成开发者可包含在 HTML 输出中的事件跟踪网址。呈现 HTML 时,ODP 将使用事件网址的载荷调用 IsolatedWorker#onEvent。
ODP 服务会拦截对呈现的 HTML 中 ODP 生成的事件网址的请求,调用 IsolatedWorker#onEvent 并将返回的 EventLogRecord 记录到 EVENTS 表中。
写入持久性结果
借助 OnDevicePersonalizationManager#execute,服务可以选择将数据写入持久性存储空间(REQUESTS 和 EVENTS 表)。以下是可写入这些表的条目:
- 要添加到
REQUESTS表中的RequestLogRecord。 - 要添加到
EVENTS表中的EventLogRecord对象列表,每个对象都包含指向之前写入的RequestLogRecord的指针。
设备端存储空间中的持久性结果可供联邦学习用于模型训练。
管理设备端训练任务
当联邦计算训练作业开始运行并想要获取采用 ODP 的开发者提供的训练示例时,ODP 服务会调用 IsolatedWorker#onTrainingExample。在实现 onTrainingExample() 时,您可以调用 getRemoteData()、getLocalData()、getUserData() 和 getLogReader()。
如需安排或取消联邦计算作业,您可以使用 FederatedComputeScheduler 类,该类可为所有 ODP IsolatedService 提供 API。每个联邦计算作业都可以通过其群体名称进行标识。
在安排新的联邦计算作业之前:
- 远程联邦计算服务器上应已创建具有相应群体名称的任务。
- 联合计算服务器网址端点应已在软件包清单设置中通过
federated-compute-settings标记指定。
与持久输出的互动
以下部分介绍了如何在 ODP 中与持久性输出进行交互。
读取本地表
LogReader 类提供用于读取 REQUESTS 和 EVENTS 表的 API。这些表包含由 IsolatedService 在 onExecute() 或 onEvent() 调用期间写入的数据。这些表中的数据可用于“联邦学习协助的模型训练”或“联邦分析协助的跨设备统计分析”。
与已下载内容的互动
以下部分介绍了如何在 ODP 中与下载的内容互动。
从服务器下载内容
ODP 服务会定期从 IsolatedService 的软件包清单中声明的网址下载内容,并在下载完成后调用 onDownloadCompleted。下载内容是包含键值对的 JSON 文件。
采用 ODP 的开发者可以选择将下载内容的哪个子集添加到 RemoteData 表中,以及应舍弃哪个子集。开发者无法修改下载的内容,这可确保 RemoteData 表不包含任何用户数据。此外,开发者可以根据自己的选择随意填充 LocalData 表;例如,他们可以缓存一些预先计算的结果。
下载请求格式
ODP 会定期轮询开发者软件包清单中声明的网址端点,以提取内容来填充 RemoteData 表。
该端点应返回 JSON 响应,如后文所述。JSON 响应必须包含一个用于标识所发送数据版本的 syncToken,以及一个要填充的键值对列表。syncToken 值必须是时间戳(以秒为单位),并限定在 UTC 小时边界内。在下载请求中,ODP 会在下载网址中提供之前完成的下载的 syncToken 和设备国家/地区作为 syncToken 和 country 参数。服务器可以使用之前的 syncToken 来实现增量下载。
下载文件格式
下载的文件是一个具有以下结构的 JSON 文件。JSON 文件应包含一个 syncToken,用于标识正在下载的数据的版本。syncToken 必须是限制在小时边界的 UTC 时间戳,并且必须超过上一次下载的 syncToken。如果 syncToken 不满足这两个要求,系统会舍弃下载的内容而不进行处理。
contents 字段是一个 (key, data, encoding) 元组列表。key 预计为 UTF-8 字符串。encoding 字段是一个可选参数,用于指定 data 字段的编码方式 - 可以设置为“utf8”或“base64”,默认情况下假定为“utf8”。在调用 onDownloadCompleted(). 之前,key 字段会转换为 String 对象,data 字段会转换为字节数组
{
// syncToken must be a UTC timestamp clamped to an hour boundary, and must be
// greater than the syncToken of the previously completed download.
"syncToken": <timeStampInSecRoundedToUtcHour>,
"contents": [
// List of { key, data } pairs.
{ "key": "key1",
"data": "data1"
},
{ "key": "key2",
"data": "data2",
"encoding": "base64"
},
// ...
]
}
服务器端 API
本部分介绍了如何与联邦计算服务器 API 进行交互。
Federated Compute Server API
如需在客户端安排联邦计算作业,您需要在远程联邦计算服务器上创建一个具有人口名称的任务。在本部分中,我们将介绍如何在联邦计算服务器上创建此类任务。
为任务构建器创建新任务时,ODP 开发者应提供两组文件:
- 通过调用 tff.learning.models.save_functional_model API 调用保存的 tff.learning.models.FunctionalModel 模型。您可以在我们的 GitHub 代码库中找到一个示例。
- 一个 fcp_server_config.json 文件,其中包含政策、联邦学习设置和差分隐私设置。以下是 fcp_server_config.json 的示例:
{
# Task execution mode.
mode: TRAINING_AND_EVAL
# Identifies the set of client devices that participate.
population_name: "mnist_cnn_task"
policies {
# Policy for sampling on-device examples. It is checked every
# time a device is attempting to start a new training.
min_separation_policy {
# The minimum separation required between two successful
# consective task executions. If a client successfully contributes
# to a task at index `x`, the earliest they can contribute again
# is at index `(x + minimum_separation)`. This is required by
# DP.
minimum_separation: 1
}
data_availability_policy {
# The minimum number of examples on a device to be considered
# eligible for training.
min_example_count: 1
}
# Policy for releasing training results to developers adopting ODP.
model_release_policy {
# The maximum number of training rounds.
num_max_training_rounds: 512
}
}
# Federated learning setups. They are applied inside Task Builder.
federated_learning {
# Use federated averaging to build federated learning process.
# Options you can choose:
# * FED_AVG: Federated Averaging algorithm
# (https://arxiv.org/abs/2003.00295)
# * FED_SGD: Federated SGD algorithm
# (https://arxiv.org/abs/1602.05629)
type: FED_AVG
learning_process {
# Optimizer used at client side training. Options you can choose:
# * ADAM
# * SGD
client_optimizer: SGD
# Learning rate used at client side training.
client_learning_rate: 0.02
# Optimizer used at server side training. Options you can choose:
# * ADAM
# * SGD
server_optimizer: SGD
# Learning rate used at server side training.
server_learning_rate: 1.0
runtime_config {
# Number of participating devices for each round of training.
report_goal: 2
}
metrics {
name: "sparse_categorical_accuracy"
}
}
evaluation {
# A checkpoint selector controls how checkpoints are chosen for
# evaluation. One evaluation task typically runs per training
# task, and on each round of execution, the eval task
# randomly picks one checkpoint from the past 24 hours that has
# been selected for evaluation by these rules.
# Every_k_round and every_k_hour are definitions of quantization
# buckets which each checkpoint is placed in for selection.
checkpoint_selector: "every_1_round"
# The percentage of a populate that should delicate to this
# evaluation task.
evaluation_traffic: 0.2
# Number of participating devices for each round of evaluation.
report_goal: 2
}
}
# Differential Privacy setups. They are enforced inside the Task
# Builder.
differential_privacy {
# * fixed_gaussian: DP-SGD with fixed clipping norm described in
# "Learning Differentially Private Recurrent
# Language Models"
# (https://arxiv.org/abs/1710.06963).
type: FIXED_GAUSSIAN
# The value of the clipping norm.
clip_norm: 0.1
# Noise multiplier for the Gaussian noise.
noise_multiplier: 0.1
}
}
您可以在我们的 GitHub 代码库中找到更多示例。
准备好这两个输入后,调用任务构建器来构建制品并生成新任务。如需查看更详细的说明,请访问我们的 GitHub 代码库。