Die On-Device-Personalisierung (ODP) dient dazu, die Daten von Endnutzern vor Anwendungen zu schützen. Mit ODP können Anwendungen ihre Produkte und Dienste für Endnutzer anpassen. Die genauen Anpassungen für den Nutzer sind jedoch nicht sichtbar, es sei denn, es gibt direkte Interaktionen außerhalb von ODP zwischen der Anwendung und dem Endnutzer. Für Anwendungen mit Modellen für maschinelles Lernen oder statistischen Analysen bietet ODP eine Reihe von Diensten und Algorithmen, mit denen dafür gesorgt wird, dass sie mithilfe der entsprechenden Mechanismen zur Differential Privacy ordnungsgemäß anonymisiert werden. Weitere Informationen finden Sie in der Erläuterung zur personalisierten Werbung auf dem Gerät.
ODP führt Entwicklercode in einer IsolatedProcess
aus, die keinen direkten Zugriff auf das Netzwerk, lokale Laufwerke oder andere Dienste hat, die auf dem Gerät ausgeführt werden. Sie hat jedoch Zugriff auf die folgenden lokal gespeicherten Datenquellen:
RemoteData
– Unveränderliche Schlüssel/Wert-Daten, die gegebenenfalls von Remote-Backends heruntergeladen wurden, die von Entwicklern betrieben werden.LocalData
: Veränderliche Schlüssel/Wert-Paare, die gegebenenfalls lokal vom Entwickler gespeichert werdenUserData
– Von der Plattform bereitgestellte Nutzerdaten.
Die folgenden Ausgabeformate werden unterstützt:
- Persistente Ausgabe: Diese Ausgabe kann für die zukünftige lokale Verarbeitung verwendet werden, um angezeigte Ausgaben, durch föderiertes Lernen unterstütztes Modelltraining oder durch föderierte Analysen unterstützte geräteübergreifende statistische Analysen zu erstellen.
- Angezeigte Ausgabe:
- Entwickler können HTML-Code zurückgeben, der von ODP in einem
WebView
innerhalb einerSurfaceView
gerendert wird. Die dort gerenderten Inhalte sind für die aufrufende App nicht sichtbar. - Entwickler können von ODP bereitgestellte Ereignis-URLs in die HTML-Ausgabe einbetten, um die Protokollierung und Verarbeitung von Nutzerinteraktionen mit dem gerenderten HTML-Code auszulösen. ODP fängt Anfragen an diese URLs ab und ruft Code auf, um Daten zu generieren, die in die Tabelle
EVENTS
geschrieben werden.
- Entwickler können HTML-Code zurückgeben, der von ODP in einem
Client-Apps und SDKs können ODP aufrufen, um HTML-Inhalte in einem SurfaceView
mithilfe von ODP APIs anzuzeigen. In einer SurfaceView
gerenderte Inhalte sind für die aufrufende App nicht sichtbar. Die Client-App oder das SDK kann eine andere Entität sein als die, die mit ODP entwickelt wird.
Der ODP-Dienst verwaltet die Client-App, die ODP aufrufen möchte, um personalisierte Inhalte auf der Benutzeroberfläche anzuzeigen. Es lädt Inhalte von von Entwicklern bereitgestellten Endpunkten herunter und ruft Logik für die Nachverarbeitung der heruntergeladenen Daten auf. Sie vermittelt auch die gesamte Kommunikation zwischen der IsolatedProcess
und anderen Diensten und Apps.
Client-Apps verwenden Methoden der Klasse OnDevicePersonalizationManager
, um mit dem Code des Entwicklers zu interagieren, der in einem IsolatedProcess
ausgeführt wird. Der in einem IsolatedProcess
ausgeführte Code des Entwicklers erweitert die Klasse IsolatedService
und implementiert die IsolatedWorker
-Schnittstelle. Die IsolatedService
muss für jede Anfrage eine Instanz von IsolatedWorker
erstellen.
Das folgende Diagramm zeigt die Beziehung zwischen den Methoden in OnDevicePersonalizationManager
und IsolatedWorker
.
OnDevicePersonalizationManager
und IsolatedWorker
.Eine Client-App ruft ODP mit der Methode execute
mit einem benannten IsolatedService
auf. Der ODP-Dienst leitet den Aufruf an die onExecute
-Methode des IsolatedWorker
weiter. Die IsolatedWorker
gibt Datensätze zurück, die gespeichert werden sollen, und Inhalte, die angezeigt werden sollen. Der ODP-Dienst schreibt die persistente Ausgabe in die Tabelle REQUESTS
oder EVENTS
und gibt einen intransparenten Verweis auf die angezeigte Ausgabe an die Client-App zurück. Die Client-App kann diesen undurchsichtigen Verweis in einem zukünftigen requestSurfacePackage
-Aufruf verwenden, um beliebige Anzeigeinhalte auf der Benutzeroberfläche anzuzeigen.
Dauerhafte Ausgabe
Der ODP-Dienst speichert einen Eintrag in der Tabelle REQUESTS
, nachdem die Implementierung von onExecute
durch den Entwickler zurückgegeben wurde. Jeder Eintrag in der Tabelle REQUESTS
enthält einige allgemeine anfragebezogene Daten, die vom ODP-Dienst generiert wurden, und eine Liste der zurückgegebenen Rows
. Jedes Row
enthält eine Liste von (key, value)
-Paaren. Jeder Wert ist ein Skalar, String oder Blob. Die numerischen Werte können nach der Aggregation gemeldet werden, die String- oder Blob-Daten können nach Anwendung des lokalen oder zentralen Differential Privacy gemeldet werden. Entwickler können auch nachfolgende Nutzerinteraktionsereignisse in die Tabelle EVENTS
schreiben. Jeder Datensatz in der Tabelle EVENTS
ist einer Zeile in der Tabelle REQUESTS
zugeordnet. Der ODP-Dienst protokolliert transparent einen Zeitstempel und den Paketnamen der aufrufenden App sowie das APK des ODP-Entwicklers mit jedem Eintrag.
Hinweis
Bevor Sie mit der ODP-Entwicklung beginnen, müssen Sie Ihr Paketmanifest einrichten und den Entwicklermodus aktivieren.
Einstellungen für das Paketmanifest
Für die Verwendung von ODP sind folgende Voraussetzungen erforderlich:
- Ein
<property>
-Tag inAndroidManifest.xml
, das auf eine XML-Ressource im Paket verweist, die ODP-Konfigurationsinformationen enthält. - Ein
<service>
-Tag inAndroidManifest.xml
, das die Klasse identifiziert, dieIsolatedService
erweitert, wie im folgenden Beispiel gezeigt. Für den Dienst im<service>
-Tag müssen die Attributeexported
undisolatedProcess
auftrue
festgelegt sein. - Ein
<service>
-Tag in der in Schritt 1 angegebenen XML-Ressource, die die Dienstklasse aus Schritt 2 identifiziert. Das<service>
-Tag muss außerdem zusätzliche ODP-spezifische Einstellungen im Tag selbst enthalten, wie im zweiten Beispiel gezeigt.
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-spezifisches Manifest in XML-Ressource
In der XML-Ressourcendatei, die im <property>
-Tag angegeben ist, muss außerdem die Dienstklasse in einem <service>
-Tag deklariert werden. Außerdem muss der URL-Endpunkt angegeben werden, von dem aus ODP Inhalte zum Füllen der Tabelle RemoteData
herunterlädt, wie im folgenden Beispiel gezeigt. Wenn Sie die Features für föderiertes Computing verwenden, müssen Sie auch den URL-Endpunkt des föderierten Computing-Servers angeben, zu dem der Client für föderiertes Computing eine Verbindung herstellt.
<!-- 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>
Entwicklermodus aktivieren
Aktivieren Sie den Entwicklermodus, indem Sie der Anleitung im Abschnitt Enable Developer Options (Entwickleroptionen aktivieren) in der Android Studio-Dokumentation folgen.
Schalter- und Meldeeinstellungen
ODP bietet eine Reihe von Schaltern und Flags, mit denen bestimmte Funktionen gesteuert werden:
- _global_killswitch: Der globale Schalter für alle ODP-Funktionen; auf „false“ gesetzt, um ODP zu verwenden
- _federated_compute_kill_switch: _Der Schalter, der alle Trainingsfunktionen (föderiertes Lernen) von ODP steuert. Stellen Sie ihn auf „false“, um das Training zu verwenden.
- _caller_app_allowlist: Hier wird festgelegt, wer ODP aufrufen darf. Apps (Paketname, [optional] Zertifikat) können hier hinzugefügt werden oder als * festgelegt werden, um alle zuzulassen.
- _isolated_service_allowlist: Damit wird festgelegt, welche Dienste im isolierten Dienstprozess ausgeführt werden können.
Mit den folgenden Befehlen können Sie alle Schalter und Flags so konfigurieren, dass ODP ohne Einschränkungen verwendet wird:
# 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 \"*\"
Geräteseitige APIs
Weitere Informationen finden Sie in der Referenzdokumentation zur Android API zu ODP.
Interaktionen mit IsolatedService
Die Klasse IsolatedService
ist eine abstrakte Basisklasse, die alle Entwickler, die mit ODP entwickeln möchten, erweitern und in ihrem Paketmanifest als in einem isolierten Prozess ausgeführt deklarieren müssen. Der ODP-Dienst startet diesen Dienst in einem isolierten Prozess und stellt Anfragen an ihn. Der IsolatedService
empfängt Anfragen vom ODP-Dienst und erstellt einen IsolatedWorker
, um die Anfrage zu bearbeiten.
Entwickler müssen die Methoden der IsolatedWorker
-Benutzeroberfläche implementieren, um Client-App-Anfragen, Downloadabschlüsse und Ereignisse zu verarbeiten, die durch die gerenderte HTML-Seite ausgelöst werden. Alle diese Methoden haben standardmäßige No-Op-Implementierungen, sodass Entwickler die Implementierung der Methoden überspringen können, die sie nicht benötigen.
Die Klasse OnDevicePersonalizationManager
bietet eine API für Apps und SDKs, um mit einem vom Entwickler implementierten IsolatedService
zu interagieren, der in einem isolierten Prozess ausgeführt wird. Im Folgenden finden Sie einige vorgesehene Anwendungsfälle:
HTML-Inhalte für die Anzeige in einer SurfaceView generieren
Um Inhalte für die Anzeige zu generieren, kann die aufrufende App mit OnDevicePersonalizationManager#execute
das zurückgegebene SurfacePackageToken
-Objekt in einem nachfolgenden requestSurfacePackage
-Aufruf verwenden, um das Ergebnis in einem SurfaceView
zu rendern.
Bei Erfolg wird der Empfänger mit einem SurfacePackage
für eine Ansicht aufgerufen, die vom ODP-Dienst gerendert wird. Clientanwendungen müssen das SurfacePackage
in eine SurfaceView
innerhalb ihrer Ansichtshierarchie einfügen.
Wenn eine App einen requestSurfacePackage
-Aufruf mit einem SurfacePackageToken
aus einem vorherigen OnDevicePersonalizationManager#execute
-Aufruf ausführt, ruft der ODP-Dienst IsolatedWorker#onRender
auf, um das HTML-Snippet abzurufen, das in einem eingegrenzten Frame gerendert werden soll. Ein Entwickler hat in dieser Phase keinen Zugriff auf LocalData
oder UserData
. Dadurch wird verhindert, dass der Entwickler eine potenziell vertrauliche UserData
in die URLs zum Abrufen von Assets im generierten HTML-Code einbettet. Entwickler können mit IsolatedService#getEventUrlProvider
Tracking-URLs generieren, die in den generierten HTML-Code eingefügt werden. Wenn der HTML-Code gerendert wird, fängt der ODP-Dienst Anfragen an diese URLs ab und ruft IsolatedWorker#onEvent
auf. Bei der Implementierung von onRender()
kann getRemoteData()
aufgerufen werden.
Ereignisse in HTML-Inhalten erfassen
Die EventUrlProvider
-Klasse stellt APIs zum Generieren von Ereignis-Tracking-URLs bereit, die Entwickler in ihre HTML-Ausgabe einfügen können. Wenn der HTML-Code gerendert wird, ruft ODP IsolatedWorker#onEvent
mit der Nutzlast der Ereignis-URL auf.
Der ODP-Dienst fängt Anfragen an über ODP generierte Ereignis-URLs im gerenderten HTML-Code ab, ruft IsolatedWorker#onEvent
auf und protokolliert die zurückgegebenen EventLogRecord
in die Tabelle EVENTS
.
Dauerhafte Ergebnisse schreiben
Mit OnDevicePersonalizationManager#execute
kann der Dienst Daten im dauerhaften Speicher (REQUESTS
- und EVENTS
-Tabellen) schreiben. In diese Tabellen können folgende Einträge geschrieben werden:
RequestLogRecord
, die der TabelleREQUESTS
hinzugefügt werden soll.- Eine Liste von
EventLogRecord
-Objekten, die der TabelleEVENTS
hinzugefügt werden sollen und jeweils einen Verweis auf eine zuvor geschriebeneRequestLogRecord
enthalten .
Dauerhafte Ergebnisse im Gerätespeicher können für das Modelltraining mithilfe von föderiertem Lernen verwendet werden.
On-Device-Trainingsaufgaben verwalten
Der ODP-Dienst ruft IsolatedWorker#onTrainingExample
auf, wenn ein federated-compute-Trainingsjob gestartet wird und Trainingsbeispiele von Entwicklern abgerufen werden sollen, die ODP verwenden. Sie können bei der Implementierung von onTrainingExample()
getRemoteData()
, getLocalData()
, getUserData()
und getLogReader()
aufrufen.
Zum Planen oder Abbrechen von Jobs für die verbundbasierte Datenverarbeitung können Sie die Klasse FederatedComputeScheduler
verwenden, die APIs für alle ODP IsolatedService
bereitstellt. Jeder föderierte Rechenjob kann anhand seines Populationsnamens identifiziert werden.
Bevor Sie einen neuen Job für die föderierte Datenverarbeitung planen, müssen Sie Folgendes tun:
- Auf dem Remote-föderierten Compute-Server sollte bereits eine Aufgabe mit diesem Populationsnamen erstellt worden sein.
- Der URL-Endpunkt des föderierten Compute-Servers sollte bereits in den Einstellungen des Paketmanifests mit dem
federated-compute-settings
-Tag angegeben sein.
Interaktionen mit dauerhafter Ausgabe
Im folgenden Abschnitt wird beschrieben, wie Sie mit persistenter Ausgabe in ODP interagieren.
Lokale Tabellen lesen
Die Klasse LogReader
stellt APIs zum Lesen der Tabellen REQUESTS
und EVENTS
bereit. Diese Tabellen enthalten Daten, die von IsolatedService
während onExecute()
- oder onEvent()
-Aufrufen geschrieben wurden. Die Daten in diesen Tabellen können für das föderierte Lernen oder für die geräteübergreifende statistische Analyse verwendet werden, die durch föderiertes Lernen unterstützt wird.
Interaktionen mit heruntergeladenen Inhalten
Im folgenden Abschnitt wird beschrieben, wie Sie in ODP mit heruntergeladenen Inhalten interagieren können.
Inhalte von Servern herunterladen
Der ODP-Dienst lädt regelmäßig Inhalte von der URL herunter, die im Paketmanifest von IsolatedService
angegeben ist, und ruft onDownloadCompleted
auf, nachdem der Download abgeschlossen ist. Der Download ist eine JSON-Datei mit Schlüssel/Wert-Paaren.
Entwickler, die ODP verwenden, können auswählen, welcher Teil der heruntergeladenen Inhalte der Tabelle RemoteData
hinzugefügt und welcher gelöscht werden soll. Entwickler können die heruntergeladenen Inhalte nicht ändern. So wird sichergestellt, dass die Tabelle RemoteData
keine Nutzerdaten enthält. Außerdem können Entwickler die Tabelle LocalData
nach Belieben füllen. Sie können beispielsweise einige vorab berechnete Ergebnisse im Cache speichern.
Format der Downloadanfrage
ODP fragt regelmäßig den im Paketmanifest des Entwicklers deklarierten URL-Endpunkt ab, um Inhalte abzurufen und in die Tabelle RemoteData
zu übertragen.
Der Endpunkt sollte eine JSON-Antwort zurückgeben, wie unten beschrieben. Die JSON-Antwort muss ein syncToken
enthalten, das die Version der gesendeten Daten identifiziert, sowie eine Liste der zu befüllenden Schlüssel/Wert-Paare. Der Wert syncToken
muss ein Zeitstempel in Sekunden sein, der an eine UTC-Stundengrenze gebunden ist. Im Rahmen der Downloadanfrage gibt ODP die syncToken
des zuvor abgeschlossenen Downloads und das Land des Geräts als „syncToken“- und „country“-Parameter in der Download-URL an. Der Server kann die vorherige syncToken
verwenden, um inkrementelle Downloads zu implementieren.
Dateiformat herunterladen
Die heruntergeladene Datei ist eine JSON-Datei mit der folgenden Struktur. Die JSON-Datei muss ein „syncToken“ enthalten, um die Version der heruntergeladenen Daten zu identifizieren. Das syncToken muss ein UTC-Zeitstempel sein, der auf eine Stundengrenze beschränkt ist, und muss das syncToken des vorherigen Downloads überschreiten. Wenn das syncToken beide Anforderungen nicht erfüllt, wird der heruntergeladene Inhalt ohne Verarbeitung verworfen.
Das Feld „Inhalt“ ist eine Liste von Tupeln vom Typ (Schlüssel, Daten, Codierung). key
muss ein UTF-8-String sein. Das Feld encoding
ist ein optionaler Parameter, der angibt, wie das Feld data
codiert wird. Es kann entweder auf „utf8“ oder „base64“ festgelegt werden und ist standardmäßig „utf8“. Das Feld key
wird in ein String
-Objekt und das Feld data
in ein Byte-Array konvertiert, bevor onDownloadCompleted().
aufgerufen wird.
{
// 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"
},
// ...
]
}
Serverseitige APIs
In diesem Abschnitt wird die Interaktion mit den APIs des föderierten Computing-Servers beschrieben.
Föderierte Compute Server-APIs
Zum Planen eines föderierten Computing-Jobs auf der Clientseite benötigen Sie eine Aufgabe mit einem Populationsnamen, der auf dem Remote-Server für föderierte Rechenvorgänge erstellt wurde. In diesem Abschnitt erfahren Sie, wie Sie eine solche Aufgabe auf dem föderierten Compute-Server erstellen.
Beim Erstellen einer neuen Aufgabe für den Task Builder sollten ODP-Entwickler zwei Dateien bereitstellen:
- Ein gespeichertes tff.learning.models.FunctionalModel-Modell, das über den API-Aufruf tff.learning.models.save_functional_model aufgerufen wurde. Ein Beispiel finden Sie in unserem GitHub-Repository.
- fcp_server_config.json mit Richtlinien, Einrichtung für föderiertes Lernen und Differential Privacy. Das folgende Beispiel zeigt eine 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
}
}
Weitere Beispiele finden Sie in unserem GitHub-Repository.
Nachdem Sie diese beiden Eingaben vorbereitet haben, rufen Sie den Task Builder auf, um Artefakte zu erstellen und neue Aufgaben zu generieren. Ausführlichere Anleitungen finden Sie in unserem GitHub-Repository.