On-Device Personalization (ODP) is designed to protect end users' information from applications. Applications use ODP to customize their products and services for end users, but they won't be able to see the exact customizations made for the user (unless there are direct interactions outside of ODP between the application and the end user). For applications with machine learning models or statistical analyses, ODP provides a set of services and algorithms to ensure that they are properly anonymized using the appropriate Differential Privacy mechanisms. For further details, see the explainer on On-Device Personalization .
ODP runs developer code in an IsolatedProcess
which has no direct access to the network, local disks or other services running on the device but has access to the following locally persisted data sources:
-
RemoteData
- Immutable key-value data downloaded from remote, developer operated backends, if applicable. -
LocalData
- Mutable key-value data locally persisted by the developer, if applicable. -
UserData
- User data provided by the platform.
The following outputs are supported:
- Persistent output: These outputs can be used in future local processing, producing displayed outputs, Federated Learning facilitated model training, or Federated Analytics facilitated cross-device statistical analysis.
- Displayed output:
- Developers can return HTML that is rendered by ODP in a
WebView
inside aSurfaceView
. The content rendered there won't be visible to the invoking app. - Developers can embed ODP-provided Event URLs within the HTML output to trigger the logging and processing of user interactions with the rendered HTML. ODP intercepts requests to those URLs and invokes code to generate data that gets written to the
EVENTS
table.
- Developers can return HTML that is rendered by ODP in a
Client apps and SDKs can invoke ODP to display HTML content in a SurfaceView
using ODP APIs. Content rendered in a SurfaceView
is not visible to the calling app. The client app or SDK can be a different entity than the one developing with ODP.
The ODP service manages the client app that wishes to invoke ODP to show personalized content within its UI. It downloads content from developer provided endpoints and invokes logic for postprocessing of the downloaded data. It also mediates all communications between the IsolatedProcess
and other services and apps.
Client apps use methods in the OnDevicePersonalizationManager
class to interact with the developer's code running in an IsolatedProcess
. Developer's code running in an IsolatedProcess
extends the IsolatedService
class and implements the IsolatedWorker
interface. The IsolatedService
needs to create an instance of IsolatedWorker
for each request.
The following diagram shows the relationship between the methods in OnDevicePersonalizationManager
and IsolatedWorker
.
OnDevicePersonalizationManager
and IsolatedWorker
.A client app calls ODP using the execute
method with a named IsolatedService
. The ODP service forwards the call to the onExecute
method of the IsolatedWorker
. The IsolatedWorker
returns records to be persisted and content to be displayed. The ODP service writes the persistent output to the REQUESTS
or EVENTS
table, and returns an opaque reference to the displayed output to the client app. The client app can use this opaque reference in a future requestSurfacePackage
call to display any of the display content within its UI.
Persistent output
The ODP service persists a record in the REQUESTS
table after the developer's implementation of onExecute
returns. Each record in the REQUESTS
table contains some common per-request data generated by the ODP service, and a list of Rows
returned. Each Row
contains a list of (key, value)
pairs. Each value is a scalar, String or blob. The numeric values can be reported after aggregation, and the string or blob data can be reported after applying local or central Differential Privacy. Developers can also write subsequent user interaction events to the EVENTS
table—each record in the EVENTS
table is associated with a row in the REQUESTS
table. The ODP service transparently logs a timestamp and the package name of the calling app and the ODP developer's APK with each record.
Before you begin
Before you begin developing with ODP, you need to set up your package manifest and enable developer mode.
Package manifest settings
To use ODP the following is required:
- A
<property>
tag inAndroidManifest.xml
that points to an XML resource in the package that contains ODP configuration information. - A
<service>
tag inAndroidManifest.xml
that identifies the class that extendsIsolatedService
, as shown in the following example. The service in the<service>
tag must have the attributesexported
andisolatedProcess
set totrue
. - A
<service>
tag in the XML resource specified in Step 1 that identifies the service class from Step 2. The<service>
tag must also include additional ODP-specific settings inside the tag itself, as shown in the second example.
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>
ODP-Specific Manifest in XML Resource
The XML resource file specified in the <property>
tag must also declare the service class in a <service>
tag, and specify the URL endpoint from which ODP will download content to populate the RemoteData
table, as shown in the following example. If you are using the federated compute features, you also need to specify the federated compute server URL endpoint to which the federated compute Client will connect.
<!--
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>
Enable Developer Mode
Enable developer mode by following the instructions in the Enable Developer Options section of the Android Studio documentation.
Switch and Flag settings
ODP has a set of switches and flags that are used to control certain functionalities:
- _global_kill switch : the global switch for all ODP features; set to false to use ODP
- _federated_compute_kill_switch: _the switch controlling all training (federated learning) functionalities of ODP; set to false to use training
- _caller_app_allow list : controls who is allowed to call ODP, apps (pkg name, [optional] certificate) can be added here or set it as * to allow all
- _isolated_service_allow list : controls which services can run in the Isolated Service process.
You can run the following commands to configure all switches and flags to use ODP without restrictions:
# 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
\"
* \"
Device-side APIs
Check out the Android API reference documentation for ODP.
Interactions with IsolatedService
The IsolatedService
class is an abstract base class that all developers intending to develop against ODP must extend, and declare in their package manifest
as running in an isolated process. The ODP service starts this service in an isolated process and makes requests to it. The IsolatedService
receives requests from the ODP service and creates an IsolatedWorker
to handle the request.
Developers need to implement the methods from the IsolatedWorker
interface to handle client app requests, download completions, and events triggered by the rendered HTML. All these methods have default no-op implementations, so developers can skip implementing the methods that they are not interested in.
The OnDevicePersonalizationManager
class provides an API for apps and SDKs to interact with a developer-implemented IsolatedService
running in an isolated process. The following are some intended use cases:
Generate HTML content to display in a SurfaceView
To generate content to display, with OnDevicePersonalizationManager#execute
, the calling app can use the returned SurfacePackageToken
object in a subsequent requestSurfacePackage
call to request the result to be rendered in a SurfaceView
.
On success, the receiver is called with a SurfacePackage
for a View rendered by the ODP service. Client applications need to insert the SurfacePackage
into a SurfaceView
within their View hierarchy.
When an app makes a requestSurfacePackage
call with a SurfacePackageToken
returned by a prior OnDevicePersonalizationManager#execute
call the ODP service calls IsolatedWorker#onRender
to fetch the HTML snippet to be rendered within a fenced frame. A developer does not have access to LocalData
or UserData
during this phase. This prevents the developer from embedding potentially sensitive UserData
within asset fetch URLs in the generated HTML. Developers can use IsolatedService#getEventUrlProvider
to generate tracking URLs to include in the generated HTML. When the HTML is rendered, the ODP service will intercept requests to these URLs and call IsolatedWorker#onEvent
. One can invoke getRemoteData()
when implementing onRender()
.
Track events within HTML content
The EventUrlProvider
class provides APIs to generate event tracking URLs that developers may include in their HTML output. When the HTML is rendered, ODP will invoke IsolatedWorker#onEvent
with the payload of the event URL.
The ODP service intercepts requests to ODP generated event URLs within the rendered HTML, calls IsolatedWorker#onEvent
and logs the returned EventLogRecord
into the EVENTS
table.
Write persistent results
With OnDevicePersonalizationManager#execute
, the service has the option to write data to persistent storage ( REQUESTS
and EVENTS
tables). Here are the entries one can write into these tables:
- a
RequestLogRecord
to be added to theREQUESTS
table. - a list of
EventLogRecord
objects to be added to theEVENTS
table, each containing a pointer to a previously writtenRequestLogRecord
.
Persistent results in on-device storage can be consumed by Federated Learning for model training.
Manage on-device training tasks
The ODP service calls IsolatedWorker#onTrainingExample
when a federated compute training job starts and wants to get training examples provided by developers adopting ODP. You can invoke getRemoteData()
, getLocalData()
, getUserData()
and getLogReader()
when implementing onTrainingExample()
.
To schedule or cancel federated compute jobs, you can use the FederatedComputeScheduler
class which provides APIs for all ODP IsolatedService
. Each federated compute job can be identified by its population name.
Before you schedule a new federated compute job:
- A task with this population name should already be created on the remote federated compute server.
- federated compute server URL endpoint should already be specified in the package manifest settings
with the
federated-compute-settings
tag.
Interactions with persistent output
The following section describes how to interact with persistent output in ODP.
Read local tables
The LogReader
class provides APIs to read the REQUESTS
and EVENTS
tables. These tables contain data that was written by IsolatedService
during onExecute()
or onEvent()
calls. The data in these tables can be used for Federated Learning facilitated model training, or Federated Analytics facilitated cross-device statistical analysis.
Interactions with downloaded content
The following section describes how to interact with downloaded content in ODP.
Download content from servers
The ODP service periodically downloads content from the URL declared in the package manifest of the IsolatedService
, and calls onDownloadCompleted
after the download is finished. The download is a JSON-file containing key-value pairs.
Developers adopting ODP can choose which subset of the downloaded content should be added to the RemoteData
table and which should be dropped. Developers cannot modify the downloaded contents - this ensures that the RemoteData
table does not contain any user data. In addition, developers are free to populate the LocalData
table as they choose; for example, they can cache some precomputed results.
Download request format
ODP periodically polls the URL endpoint declared in the developer package manifest
to fetch content to populate the RemoteData
table.
The endpoint is expected to return a JSON response as described later. The JSON response must contain a syncToken
that identifies the version of the data being sent, along with a list of key-value pairs to be populated. The syncToken
value must be a timestamp in seconds, clamped to a UTC hour boundary. As part of the download request, ODP provides the syncToken
of the previously completed download and the device country as the syncToken and country parameters in the download URL. The server can use the previous syncToken
to implement incremental downloads.
Download file format
The downloaded file is a JSON file with the following structure. The JSON file is expected to contain a syncToken to identify the version of the data that is being downloaded. The syncToken must be a UTC timestamp clamped to an hour boundary, and must exceed the syncToken of the previous download. If the syncToken does not meet both requirements, the downloaded content is discarded without processing.
The contents field is a list of (key, data, encoding) tuples. The key
is expected to be a UTF-8 string. The encoding
field is an optional parameter that specifies how the data
field is encoded - it can be set to either "utf8" or "base64", and is assumed to be "utf8" by default. The key
field is converted to a String
object and the data
field is converted to a byte array before calling onDownloadCompleted().
{
// syncToken must be a UTC timestamp clamped to an hour boundary, and must be
// greater than the syncToken of the previously completed download.
"syncToken"
:
< t
imeS
ta
mpI
n
SecRou
n
dedToU
t
cHour
> ,
"contents"
:
[
// List of { key, data } pairs.
{
"key"
:
"key1"
,
"data"
:
"data1"
},
{
"key"
:
"key2"
,
"data"
:
"data2"
,
"encoding"
:
"base64"
},
// ...
]
}
Server-side APIs
This section describes how to interact with the federated compute server APIs.
Federated Compute Server APIs
To schedule a federated compute job on the client side, you need a task with a population name created on the remote federated compute server. In this section, we cover how to create such a task on the federated compute server.
When creating a new task for the Task Builder, ODP developers should provide two sets of files:
- A saved tff.learning.models.FunctionalModel model through calling tff.learning.models.save_functional_model API call. You can find one sample in our GitHub repository.
- A fcp_server_config.json which includes policies, federated learning setup and differential privacy setup. The following is an example of a fcp_server_config.json:
{
#
Task
execu
t
io
n
mode.
mode
:
TRAINING_AND_EVAL
#
Ide
nt
i
f
ies
t
he
se
t
o
f
clie
nt
devices
t
ha
t
par
t
icipa
te
.
popula
t
io
n
_
na
me
:
"mnist_cnn_task"
policies
{
#
Policy
f
or
sampli
n
g
o
n
-
device
examples.
I
t
is
checked
every
#
t
ime
a
device
is
a
tte
mp
t
i
n
g
t
o
s
tart
a
ne
w
tra
i
n
i
n
g.
mi
n
_separa
t
io
n
_policy
{
#
The
mi
n
imum
separa
t
io
n
required
be
t
wee
n
t
wo
success
ful
#
co
nse
c
t
ive
tas
k
execu
t
io
ns
.
I
f
a
clie
nt
success
full
y
co
ntr
ibu
tes
#
t
o
a
tas
k
a
t
i
n
dex
`x`
,
t
he
earlies
t
t
hey
ca
n
co
ntr
ibu
te
agai
n
#
is
a
t
i
n
dex
`(x
+
mi
n
imum_separa
t
io
n
)`.
This
is
required
by
#
DP.
mi
n
imum_separa
t
io
n
:
1
}
da
ta
_availabili
t
y_policy
{
#
The
mi
n
imum
nu
mber
o
f
examples
o
n
a
device
t
o
be
co
ns
idered
#
eligible
f
or
tra
i
n
i
n
g.
mi
n
_example_cou
nt
:
1
}
#
Policy
f
or
releasi
n
g
tra
i
n
i
n
g
resul
ts
t
o
developers
adop
t
i
n
g
ODP.
model_release_policy
{
#
The
maximum
nu
mber
o
f
tra
i
n
i
n
g
rou
n
ds.
nu
m_max_
tra
i
n
i
n
g_rou
n
ds
:
512
}
}
#
Federa
te
d
lear
n
i
n
g
se
tu
ps.
They
are
applied
i
ns
ide
Task
Builder.
fe
dera
te
d_lear
n
i
n
g
{
#
Use
fe
dera
te
d
averagi
n
g
t
o
build
fe
dera
te
d
lear
n
i
n
g
process.
#
Op
t
io
ns
you
ca
n
choose
:
#
*
FED_AVG
:
Federa
te
d
Averagi
n
g
algori
t
hm
#
(h
tt
ps
:
//arxiv.org/abs/2003.00295)
#
*
FED_SGD
:
Federa
te
d
SGD
algori
t
hm
#
(h
tt
ps
:
//arxiv.org/abs/1602.05629)
t
ype
:
FED_AVG
lear
n
i
n
g_process
{
#
Op
t
imizer
used
a
t
clie
nt
side
tra
i
n
i
n
g.
Op
t
io
ns
you
ca
n
choose
:
#
*
ADAM
#
*
SGD
clie
nt
_op
t
imizer
:
SGD
#
Lear
n
i
n
g
ra
te
used
a
t
clie
nt
side
tra
i
n
i
n
g.
clie
nt
_lear
n
i
n
g_ra
te
:
0.02
#
Op
t
imizer
used
a
t
server
side
tra
i
n
i
n
g.
Op
t
io
ns
you
ca
n
choose
:
#
*
ADAM
#
*
SGD
server_op
t
imizer
:
SGD
#
Lear
n
i
n
g
ra
te
used
a
t
server
side
tra
i
n
i
n
g.
server_lear
n
i
n
g_ra
te
:
1.0
ru
nt
ime_co
nf
ig
{
#
Number
o
f
par
t
icipa
t
i
n
g
devices
f
or
each
rou
n
d
o
f
tra
i
n
i
n
g.
repor
t
_goal
:
2
}
me
tr
ics
{
na
me
:
"sparse_categorical_accuracy"
}
}
evalua
t
io
n
{
#
A
checkpoi
nt
selec
t
or
co
ntr
ols
how
checkpoi
nts
are
chose
n
f
or
#
evalua
t
io
n
.
O
ne
evalua
t
io
n
tas
k
t
ypically
ru
ns
per
tra
i
n
i
n
g
#
tas
k
,
a
n
d
o
n
each
rou
n
d
o
f
execu
t
io
n
,
t
he
eval
tas
k
#
ra
n
domly
picks
o
ne
checkpoi
nt
fr
om
t
he
pas
t
24
hours
t
ha
t
has
#
bee
n
selec
te
d
f
or
evalua
t
io
n
by
t
hese
rules.
#
Every_k_rou
n
d
a
n
d
every_k_hour
are
de
f
i
n
i
t
io
ns
o
f
qua
nt
iza
t
io
n
#
bucke
ts
which
each
checkpoi
nt
is
placed
i
n
f
or
selec
t
io
n
.
checkpoi
nt
_selec
t
or
:
"every_1_round"
#
The
perce
nta
ge
o
f
a
popula
te
t
ha
t
should
delica
te
t
o
t
his
#
evalua
t
io
n
tas
k.
evalua
t
io
n
_
traff
ic
:
0.2
#
Number
o
f
par
t
icipa
t
i
n
g
devices
f
or
each
rou
n
d
o
f
evalua
t
io
n
.
repor
t
_goal
:
2
}
}
#
Di
fferent
ial
Privacy
se
tu
ps.
They
are
e
nf
orced
i
ns
ide
t
he
Task
#
Builder.
di
fferent
ial_privacy
{
#
*
f
ixed_gaussia
n
:
DP
-
SGD
wi
t
h
f
ixed
clippi
n
g
n
orm
described
i
n
#
"Learning Differentially Private Recurrent
# Language Models"
#
(h
tt
ps
:
//arxiv.org/abs/1710.06963).
t
ype
:
FIXED_GAUSSIAN
#
The
value
o
f
t
he
clippi
n
g
n
orm.
clip_
n
orm
:
0.1
#
Noise
mul
t
iplier
f
or
t
he
Gaussia
n
n
oise.
n
oise_mul
t
iplier
:
0.1
}
}
You can find more samples in our GitHub repository.
After preparing these two inputs, invoke the Task Builder to construct artifacts and generate new tasks. More detailed instructions are available in our GitHub repository.