Zur Verbesserung der Gerätesicherheit wird der monolithische mediaserver
-Prozess in Android 7.0 in mehrere Prozesse aufgeteilt, deren Berechtigungen und Funktionen auf die für jeden Prozess erforderlichen beschränkt sind. Durch diese Änderungen werden Sicherheitslücken im Media Framework minimiert:
- Die Komponenten der Antiviren-Pipeline in appspezifische Prozesse in einer Sandbox aufteilen.
- Aktivieren von aktualisierbaren Medienkomponenten (Extractor, Codecs usw.)
Diese Änderungen verbessern auch die Sicherheit für Endnutzer, da die meisten medienbezogenen Sicherheitslücken erheblich reduziert werden und so die Geräte und Daten der Endnutzer geschützt werden.
OEMs und SoC-Anbieter müssen ihre HAL- und Framework-Änderungen aktualisieren, damit sie mit der neuen Architektur kompatibel sind. Da der von Anbietern bereitgestellte Android-Code häufig davon ausgeht, dass alles im selben Prozess ausgeführt wird, müssen Anbieter ihren Code aktualisieren, um native Handles (native_handle
) zu übergeben, die für alle Prozesse relevant sind. Eine Referenzimplementierung der Änderungen im Zusammenhang mit der Medienhärtung findest du unter frameworks/av
und frameworks/native
.
Architekturänderungen
In früheren Android-Versionen wurde ein einzelner monolithischer mediaserver
-Prozess mit sehr vielen Berechtigungen verwendet (z. B. Kamerazugriff, Audiozugriff, Videotreiberzugriff, Dateizugriff, Netzwerkzugriff). Unter Android 7.0 wird der mediaserver
-Prozess in mehrere neue Prozesse aufgeteilt, für die jeweils deutlich weniger Berechtigungen erforderlich sind:
Abbildung 1: Architekturänderungen zur Medienserver-Härtung
Diese neue Architektur sorgt dafür, dass schädlicher Code auch dann nicht auf die gesamten Berechtigungen zugreifen kann, die zuvor von mediaserver
gehalten wurden, wenn ein Prozess manipuliert wird. Prozesse werden durch SELinux- und Seccomp-Richtlinien eingeschränkt.
Hinweis:Aufgrund von Anbieterabhängigkeiten werden einige Codecs weiterhin im mediaserver
ausgeführt und gewähren ihm daher mehr Berechtigungen als erforderlich.mediaserver
Insbesondere wird Widevine Classic weiterhin in der mediaserver
für Android 7.0 ausgeführt.
Änderungen am MediaServer
In Android 7.0 gibt es den Prozess mediaserver
, der die Wiedergabe und Aufzeichnung steuert, z.B. das Übergeben und Synchronisieren von Puffern zwischen Komponenten und Prozessen. Prozesse kommunizieren über den standardmäßigen Binder-Mechanismus.
Bei einer Standardwiedergabesitzung lokaler Dateien übergibt die App einen Dateideskriptor (File Descriptor, FD) an mediaserver
(in der Regel über die MediaPlayer Java API). mediaserver
:
- Umschließt den Dateideskriptor in ein Binder-Datenquellenobjekt, das an den Extraktionsprozess übergeben wird, der damit Daten über Binder IPC aus der Datei liest. (Der mediaextractor ruft die FD nicht ab, sondern sendet Binderaufrufe an die
mediaserver
, um die Daten abzurufen.) - Prüft die Datei, erstellt den entsprechenden Extractor für den Dateityp (z.B. MP3Extractor oder MPEG4Extractor) und gibt eine Binder-Oberfläche für den Extractor an den
mediaserver
-Prozess zurück. - Er führt Binder-IPC-Aufrufe an den Extractor aus, um den Datentyp in der Datei zu ermitteln (z.B. MP3- oder H.264-Daten).
- Ruft den
mediacodec
-Prozess auf, um Codecs des erforderlichen Typs zu erstellen, und empfängt Binder-Schnittstellen für diese Codecs. - Führt wiederholte Binder-IPC-Aufrufe an den Extractor aus, um codierte Samples zu lesen, und verwendet den Binder-IPC, um codierte Daten zur Dekodierung an den
mediacodec
-Prozess zu senden. Außerdem werden decodierte Daten empfangen.
In einigen Anwendungsfällen kommt kein Codec zum Einsatz (z. B. bei einer ausgelagerten Wiedergabe, bei der codierte Daten direkt an das Ausgabegerät gesendet werden). Der Codec kann die decodierten Daten auch direkt rendern, anstatt einen Puffer mit decodierten Daten zurückzugeben (Videowiedergabe).
Änderungen am MediaCodecService
Der Codec-Dienst ist der Ort, an dem Encoder und Decoder zu finden sind. Aufgrund von Anbieterabhängigkeiten sind noch nicht alle Codecs im Codec-Prozess verfügbar. Unter Android 7.0:
- Nicht sichere Decoder und Software-Encoder werden im Codec-Prozess ausgeführt.
- Sichere Dekoder und Hardware-Encoder befinden sich in der
mediaserver
(unverändert).
Eine App (oder mediaserver
) ruft den Codec-Prozess auf, um einen Codec des erforderlichen Typs zu erstellen, und ruft dann diesen Codec auf, um codierte Daten einzugeben und decodierte Daten abzurufen (für die Dekodierung) oder decodierte Daten einzugeben und codierte Daten abzurufen (für die Codierung). Für die Datenübertragung zu und von Codecs wird bereits gemeinsam genutzter Arbeitsspeicher verwendet. Dieser Vorgang bleibt also unverändert.
Änderungen bei MediaDrmServer
Der DRM-Server wird beim Abspielen von DRM-geschützten Inhalten wie Filmen in Google Play Filme & Serien verwendet. Es sorgt für eine sichere Entschlüsselung der verschlüsselten Daten und hat daher Zugriff auf Zertifikats- und Schlüsselspeicher sowie andere sensible Komponenten. Aufgrund von Anbieterabhängigkeiten wird der DRM-Prozess noch nicht in allen Fällen verwendet.
Änderungen am AudioServer
Der AudioServer-Prozess beherbergt audiobezogene Komponenten wie Audioeingabe und ‑ausgabe, den PolicyManager-Dienst, der die Audio-Routing-Funktion bestimmt, und den FM-Radiodienst. Weitere Informationen zu den Änderungen am Audio und zur Implementierung finden Sie unter Audio implementieren.
Änderungen am CameraServer
Der CameraServer steuert die Kamera und wird bei der Videoaufzeichnung verwendet, um Videoframes von der Kamera abzurufen und dann zur weiteren Verarbeitung an mediaserver
weiterzuleiten. Weitere Informationen zu den Änderungen und Implementierungsanleitungen für CameraServer-Änderungen finden Sie unter Camera Framework-Härtung.
Änderungen an ExtractorService
Der Extractor-Dienst beherbergt die Extractor, Komponenten, die die verschiedenen vom Media-Framework unterstützten Dateiformate parsen. Der Extractor-Dienst hat die geringsten Berechtigungen aller Dienste. Er kann keine FDs lesen und ruft stattdessen eine Binder-Schnittstelle auf, die ihm von der mediaserver for
für jede Wiedergabesitzung zur Verfügung gestellt wird, um auf Dateien zuzugreifen.
Eine App (oder mediaserver
) ruft den Extraktionsprozess auf, um eine IMediaExtractor
abzurufen, ruft diese IMediaExtractor
auf, um IMediaSources
für den in der Datei enthaltenen Titel abzurufen, und ruft dann IMediaSources
auf, um Daten daraus zu lesen.
Um die Daten zwischen Prozessen zu übertragen, fügt die App (oder mediaserver
) die Daten als Teil der Binder-Transaktion in das Antwort-Parcel ein oder verwendet gemeinsamen Speicher:
- Die Verwendung von freigegebenem Arbeitsspeicher erfordert einen zusätzlichen Binder-Aufruf, um den freigegebenen Arbeitsspeicher freizugeben. Sie ist jedoch schneller und verbraucht bei großen Puffern weniger Strom.
- Die Verwendung von In-Parcel erfordert zusätzliches Kopieren, ist aber schneller und verbraucht bei Puffern unter 64 KB weniger Strom.
Implementierung
Um die Migration von MediaDrm
- und MediaCrypto
-Komponenten in den neuen mediadrmserver
-Prozess zu unterstützen, müssen Anbieter die Zuweisungsmethode für sichere Puffer ändern, damit Puffer zwischen Prozessen freigegeben werden können.
In früheren Android-Releases werden sichere Buffers in mediaserver
durch OMX::allocateBuffer
zugewiesen und während der Entschlüsselung im selben Prozess verwendet, wie unten dargestellt:
Abbildung 2: Pufferzuweisung im Mediaserver unter Android 6.0
In Android 7.0 wurde der Pufferzuweisungsprozess in einen neuen Mechanismus geändert, der Flexibilität bietet und gleichzeitig die Auswirkungen auf vorhandene Implementierungen minimiert. Bei MediaDrm
- und MediaCrypto
-Stacks im neuen mediadrmserver
-Prozess werden Puffer unterschiedlich zugewiesen und Anbieter müssen die sicheren Puffer-Handles aktualisieren, damit sie über den Binder übertragen werden können, wenn MediaCodec
einen Entschlüsselungsvorgang auf MediaCrypto
auslöst.
Abbildung 3: Pufferzuweisung im Mediaserver unter Android 7.0 und höher
Native Aliasse verwenden
OMX::allocateBuffer
muss einen Verweis auf ein native_handle
-Struktur zurückgeben, das Dateideskriptoren (FDs) und zusätzliche Ganzzahldaten enthält. Ein native_handle
bietet alle Vorteile der Verwendung von FDs, einschließlich der vorhandenen Binderunterstützung für die Serialisierung/Deserialisierung, und bietet gleichzeitig mehr Flexibilität für Anbieter, die derzeit keine FDs verwenden.
Verwenden Sie native_handle_create()
, um den nativen Handle zuzuweisen.
Der Framework-Code übernimmt die Inhaberschaft für das zugewiesene native_handle
-Objekt und ist dafür verantwortlich, Ressourcen sowohl im Prozess, in dem native_handle
ursprünglich zugewiesen wird, als auch im Prozess, in dem es deserialisiert wird, freizugeben. Das Framework gibt native Handles mit native_handle_close()
gefolgt von native_handle_delete()
frei und serialisiert/deserialisiert die native_handle
mit Parcel::writeNativeHandle()/readNativeHandle()
.
SoC-Anbieter, die FDs zum Darstellen sicherer Puffer verwenden, können den FD in der native_handle
mit ihrem FD ausfüllen. Anbieter, die keine FDs verwenden, können sichere Puffer mithilfe zusätzlicher Felder in der native_buffer
darstellen.
Ort der Entschlüsselung festlegen
Anbieter müssen die OEMCrypto-Entschlüsselungsmethode aktualisieren, die auf der native_handle
ausgeführt wird, um alle anbieterspezifischen Vorgänge auszuführen, die erforderlich sind, um die native_handle
im neuen Prozessbereich nutzbar zu machen. Zu den Änderungen gehören in der Regel Aktualisierungen der OEMCrypto-Bibliotheken.
Da allocateBuffer
eine Standard-OMX-Operation ist, enthält Android 7.0 eine neue OMX-Erweiterung (OMX.google.android.index.allocateNativeHandle
), um nach dieser Unterstützung zu fragen, und einen OMX_SetParameter
-Aufruf, der die OMX-Implementierung darüber informiert, dass native Handles verwendet werden sollen.