Ab Android 10: Neural Networks API (NNAPI)
Funktionen zur Unterstützung der
Caching von Kompilierungsartefakten, wodurch die für die Kompilierung benötigte Zeit reduziert wird
wenn eine App gestartet wird. Mit dieser Caching-Funktion kann der Treiber
die im Cache gespeicherten Dateien
verwalten oder bereinigen müssen. Dies ist eine optionale Funktion, die
kann mit NN HAL 1.2 implementiert werden. Weitere Informationen zu dieser Funktion
Siehe
ANeuralNetworksCompilation_setCaching
Der Treiber kann auch das Kompilierungs-Caching unabhängig von der NNAPI implementieren. Dieses kann implementiert werden, unabhängig davon, ob die NNAPI NDK- und HAL-Caching-Funktionen verwendet werden oder nicht. AOSP bietet eine Low-Level-Dienstprogrammbibliothek (eine Caching-Engine). Weitere Informationen finden Sie unter Caching-Engine implementieren.
Workflowübersicht
In diesem Abschnitt werden allgemeine Workflows mit der Funktion für das Kompilierungs-Caching beschrieben. implementiert.
Cache-Informationen und Cache-Treffer
- Die Anwendung übergibt ein Caching-Verzeichnis und eine für das Modell eindeutige Prüfsumme.
- Die NNAPI-Laufzeit sucht anhand der Prüfsumme nach den Cache-Dateien, der Ausführungspräferenz, Partitionierungsergebnis und findet die Dateien.
- Die NNAPI öffnet die Cache-Dateien und übergibt die Handles an den Treiber
mit
prepareModelFromCache
- Der Treiber bereitet das Modell direkt aus den Cache-Dateien vor und gibt das vorbereitete Modell.
Cache-Informationen und Cache-Fehler
- Die Anwendung übergibt eine für das Modell eindeutige Prüfsumme sowie ein Caching. -Verzeichnis.
- Die NNAPI-Laufzeit sucht anhand der Prüfsumme nach den Caching-Dateien, der Ausführungspräferenz und das Partitionierungsergebnis Cache-Dateien.
- Die NNAPI erstellt leere Cache-Dateien basierend auf der Prüfsumme, der Ausführung
und die Partitionierung,
öffnet die Cache-Dateien und übergibt
und das Modell mit den
prepareModel_1_2
- Der Treiber kompiliert das Modell und schreibt Caching-Informationen in den Cache. und gibt das vorbereitete Modell zurück.
Cache-Informationen nicht angegeben
- Die Anwendung ruft die Kompilierung auf, ohne Caching-Informationen bereitzustellen.
- Die Anwendung übergibt nichts im Zusammenhang mit Caching.
- Die NNAPI-Laufzeit übergibt das Modell mit
prepareModel_1_2
- Der Treiber kompiliert das Modell und gibt das vorbereitete Modell zurück.
Cache-Informationen
Die Caching-Informationen, die einem Treiber bereitgestellt werden, bestehen aus einem Token und Cache-Datei-Handles.
Token
Die
Token
ist ein Caching-Token der Länge
Constant::BYTE_SIZE_OF_CACHE_TOKEN
der das vorbereitete Modell identifiziert. Dasselbe Token wird beim Speichern des
Dateien mit prepareModel_1_2
im Cache speichern und das vorbereitete Modell mit
prepareModelFromCache
. Der Client des Treibers sollte ein Token mit einem
eine niedrige Kollisionsrate. Der Treiber kann keine Tokenkollision erkennen. Eine Kollision
führt zu einer fehlgeschlagenen Ausführung oder zu einer erfolgreichen Ausführung, die
Falsche Ausgabewerte.
Handles für Cache-Dateien (zwei Arten von Cache-Dateien)
Die beiden Arten von Cache-Dateien sind der Daten-Cache und der Modell-Cache.
- Daten-Cache: Wird zum Caching konstanter Daten verwendet, einschließlich vorverarbeiteter und transformierten Tensor-Zwischenspeichern. Eine Änderung am Daten-Cache sollte zu einer schlechteren Auswirkung führen als die Erzeugung ungültiger Ausgabewerte bei der Ausführung. .
- Modell-Cache:Wird zum Caching sicherheitsrelevanter Daten verwendet, z. B. kompilierte den ausführbaren Maschinencode im nativen Binärformat des Geräts vor. A Änderungen am Modell-Cache können sich auf die Ausführung des Treibers auswirken. und ein bösartiger Client diese Möglichkeit nutzen, die erteilte Berechtigung hat. Daher muss der Treiber prüfen, ob der Modell-Cache ist beschädigt, bevor das Modell aus dem Cache vorbereitet wird. Weitere Informationen Siehe Sicherheit.
Der Treiber muss entscheiden, wie Cache-Informationen zwischen den beiden verteilt werden sollen
und geben an, wie viele Cache-Dateien jeweils benötigt werden.
mit
getNumberOfCacheFilesNeeded
Die NNAPI-Laufzeit öffnet Cache-Datei-Handles sowohl mit Lese- als auch Schreibvorgängen Berechtigung.
Sicherheit
Beim Kompilierungs-Caching kann der Modell-Cache sicherheitsrelevante Daten wie als kompilierter ausführbarer Maschinencode im nativen Binärformat des Geräts. Falls nicht nicht ordnungsgemäß geschützt ist, kann sich eine Änderung am Modell-Cache auf den Treiber des Ausführungsverhaltens. Weil der Cache-Inhalt in der App gespeichert wird können die Cache-Dateien vom Client geändert werden. Ein fehlerhafter Client kann den Cache versehentlich beschädigen und ein bösartiger Client absichtlich um nicht verifizierten Code auf dem Gerät auszuführen. Je nach Merkmale des Geräts haben, könnte es sich um ein Sicherheitsproblem handeln. Das heißt, die Der Fahrer muss in der Lage sein, potenzielle Beschädigung des Modell-Cache, bevor das Modell aus dem Cache vorbereitet wird.
Eine Möglichkeit, dies zu tun, besteht darin, dass der Fahrer eine Karte vom Token zu einem
kryptografischer Hash des Modell-Cache. Der Treiber kann das Token und den
Hash des Modell-Cache gespeichert, wenn die Kompilierung im Cache gespeichert wird. Der Fahrer prüft
den neuen Hash des Modell-Cache mit dem aufgezeichneten Token und Hash-Paar, wenn
das Abrufen der Kompilierung aus dem Cache. Diese Zuordnung sollte für alle
das System neu gestartet wird. Der Fahrer kann die
Android Keystore Service, die Dienstprogrammbibliothek in
framework/ml/nn/driver/cache
,
oder einen anderen geeigneten Mechanismus zur Implementierung eines Kartenmanagers implementieren. Beim Fahren
aktualisieren, muss dieser Zuordnungsmanager neu initialisiert werden, um zu verhindern, dass der Cache vorbereitet wird
aus einer früheren Version.
Um dies zu verhindern, von der Prüfung bis zur Nutzungszeit (TOCTOU)-Angriffen nutzen, muss der Fahrer den aufgezeichneten Hashwert berechnen, bevor er unter und berechnen den neuen Hash nach dem Kopieren des Dateiinhalts in ein internes Puffer.
Dieser Beispielcode zeigt, wie diese Logik implementiert wird.
bool saveToCache(const sp<V1_2::IPreparedModel> preparedModel,
const hidl_vec<hidl_handle>& modelFds, const hidl_vec<hidl_handle>& dataFds,
const HidlToken& token) {
// Serialize the prepared model to internal buffers.
auto buffers = serialize(preparedModel);
// This implementation detail is important: the cache hash must be computed from internal
// buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
auto hash = computeHash(buffers);
// Store the {token, hash} pair to a mapping manager that is persistent across reboots.
CacheManager::get()->store(token, hash);
// Write the cache contents from internal buffers to cache files.
return writeToFds(buffers, modelFds, dataFds);
}
sp<V1_2::IPreparedModel> prepareFromCache(const hidl_vec<hidl_handle>& modelFds,
const hidl_vec<hidl_handle>& dataFds,
const HidlToken& token) {
// Copy the cache contents from cache files to internal buffers.
auto buffers = readFromFds(modelFds, dataFds);
// This implementation detail is important: the cache hash must be computed from internal
// buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
auto hash = computeHash(buffers);
// Validate the {token, hash} pair by a mapping manager that is persistent across reboots.
if (CacheManager::get()->validate(token, hash)) {
// Retrieve the prepared model from internal buffers.
return deserialize<V1_2::IPreparedModel>(buffers);
} else {
return nullptr;
}
}
Erweiterte Anwendungsfälle
In bestimmten erweiterten Anwendungsfällen benötigt ein Treiber Zugriff auf den Cache-Inhalt (Lesen oder Schreiben) nach dem Kompilierungsaufruf. Beispiele für Anwendungsfälle:
- Just-in-Time-Kompilierung:Die Kompilierung wird bis zum bei der ersten Ausführung.
- Kompilierung mit mehreren Phasen:Zu Beginn wird eine schnelle Kompilierung ausgeführt. und zu einem späteren Zeitpunkt wird eine optionale, optimierte Kompilierung durchgeführt. je nach Nutzungshäufigkeit.
Um nach dem Kompilierungsaufruf auf den Cache-Inhalt zugreifen zu können (Lese- oder Schreibzugriff), dass der Fahrer:
- Dupliziert die Datei-Handles während des Aufrufs von
prepareModel_1_2
oderprepareModelFromCache
und liest/aktualisiert den Cache zu einem späteren Zeitpunkt wieder aufnehmen. - Implementiert Dateisperrlogik außerhalb des normalen Kompilierungsaufrufs um einen Schreibvorgang zu verhindern, der gleichzeitig mit einem Lese- oder einem anderen Schreibvorgang ausgeführt wird.
Caching-Engine implementieren
Neben der NN HAL 1.2-Schnittstelle für das Kompilierungs-Caching finden Sie auch einen
Caching-Dienstprogrammbibliothek in der
frameworks/ml/nn/driver/cache
-Verzeichnis. Die
nnCache
Das Unterverzeichnis enthält permanenten Speichercode für den zu implementierenden Treiber.
Kompilierungs-Caching ohne die NNAPI-Caching-Funktionen. Diese Form von
Kompilierungs-Caching kann mit jeder Version von NN HAL implementiert werden. Wenn die
um ein von der HAL-Schnittstelle getrenntes Caching zu implementieren,
der Fahrer
ist dafür verantwortlich, im Cache gespeicherte Artefakte freizugeben, wenn sie nicht mehr benötigt werden.