Modifications de l'ABI avec ION

Les appareils qui expédient le noyau 4.14 ou version ultérieure sont affectés par une refactorisation majeure du module du noyau ION, que de nombreux fournisseurs d'allocations de mémoire graphique (Gralloc) appellent des couches d'abstraction matérielle (HAL) pour allouer des tampons de mémoire partagée. Cette page explique comment migrer le code de l'ancien fournisseur vers la nouvelle version d'ION et aborde d'éventuelles défaillances d'interface binaires (ABI) d'application.

À propos d'ION

ION fait partie de l'arbre de préproduction en cours de développement du kernel en amont. En phase de préproduction, l'ABI de l'espace utilisateur vers le noyau d'ION peut se briser entre les versions majeures du noyau. Bien que les ruptures de l'ABI ION n'affectent pas directement les applications ordinaires ni les appareils déjà lancés, les fournisseurs qui migrent vers de nouvelles versions majeures du kernel peuvent rencontrer des modifications qui affectent le code du fournisseur qui appelle ION. De plus, des ruptures ABI peuvent se produire à l'avenir, car l'équipe des systèmes Android travaille en amont pour déplacer ION hors de l'arborescence de préproduction.

Modifications apportées à android-4.14

Le noyau 4.12 a fortement refactorisé le code du noyau ION, en nettoyant et en supprimant les parties d'ION qui chevauchaient le code d'autres frameworks du noyau. Par conséquent, de nombreux anciens ioctls ION ne sont plus pertinents et ont été supprimés.

Suppression des comptes et des clients ION

Avant le kernel 4.12, l'ouverture de /dev/ion allouait un client ION. L'ioctl ION_IOC_ALLOC a alloué un nouveau tampon et l'a renvoyé dans l'espace utilisateur en tant que handle ION (un entier opaque qui n'a de sens que pour le client ION qui l'a alloué). Pour mapper les tampons dans l'espace utilisateur ou les partager avec d'autres processus, les poignées ION ont été réexportées sous forme de fds dma-buf à l'aide de l'ioctl ION_IOC_SHARE.

Dans le kernel 4.12, l'ioctl ION_IOC_ALLOC génère directement des fds dma-buf. L'état d'un handle ION intermédiaire a été supprimé, ainsi que tous les ioctls qui consomment ou produisent des handles ION. Étant donné que les fds dma-buf ne sont pas associés à des clients ION spécifiques, l'ioctl ION_IOC_SHARE n'est plus nécessaire et toute l'infrastructure client ION a été supprimée.

Ajout d'ioctls de cohérence de cache

Avant le kernel 4.12, ION fournissait un ioctl ION_IOC_SYNC pour synchroniser le descripteur de fichier avec la mémoire. Cet ioctl était mal documenté et rigide. Par conséquent, de nombreux fournisseurs ont implémenté des ioctls personnalisés pour effectuer la maintenance du cache.

Le kernel 4.12 a remplacé ION_IOC_SYNC par DMA_BUF_IOCTL_SYNC ioctl défini dans linux/dma-buf.h. Appelez DMA_BUF_IOCTL_SYNC au début et à la fin de chaque accès au processeur, avec des options spécifiant si ces accès sont des lectures et/ou des écritures. Bien que DMA_BUF_IOCTL_SYNC soit plus détaillé que ION_IOC_SYNC, il permet à l'espace utilisateur de mieux contrôler les opérations de maintenance du cache sous-jacents.

DMA_BUF_IOCTL_SYNC fait partie de l'ABI stable du kernel et est utilisable avec tous les fds dma-buf, qu'ils aient été alloués par ION ou non.

Migrer le code du fournisseur vers Android 4.12 (et versions ultérieures)

Pour les clients de l'espace utilisateur, l'équipe des systèmes Android recommande vivement d'utiliser libion plutôt que de coder en mode ouvert les appels ioctl(). À partir d'Android 9, libion détecte automatiquement l'ABI ION au moment de l'exécution et tente de masquer les différences entre les noyaux. Toutefois, les fonctions libion qui produisaient ou consommaient des poignées ion_user_handle_t ne fonctionnent plus après le kernel 4.12. Vous pouvez remplacer ces fonctions par les opérations équivalentes suivantes sur les fds dma-buf, qui fonctionnent sur toutes les versions du noyau à ce jour.

Ancienne méthode d'appel ion_user_handle_t Appel de fd dma-buf équivalent
ion_alloc(ion_fd, …, &buf_handle) ion_alloc_fd(ion_fd, ..., &buf_fd)
ion_share(ion_fd, buf_handle, &buf_fd) N/A (cet appel n'est pas nécessaire avec les fds dma-buf)
ion_map(ion_fd, buf_handle, ...) mmap(buf_fd, ...)
ion_free(ion_fd, buf_handle) close(buf_fd)
ion_import(ion_fd, buf_fd, &buf_handle) N/A (cet appel n'est pas nécessaire avec les fds dma-buf)
ion_sync_fd(ion_fd, buf_fd)
If (ion_is_legacy(ion_fd))
    ion_sync_fd(ion_fd, buf_fd);
else
    ioctl(buf_fd, DMA_BUF_IOCTL_SYNC, ...);

Pour les clients dans le noyau, comme ION n'exporte plus d'API orientées noyau, les pilotes qui utilisaient auparavant l'API du noyau ION dans le noyau avec ion_import_dma_buf_fd() doivent être convertis pour utiliser l'API dma-buf dans le noyau avec dma_buf_get().

Futures coupures de l'ABI ION

Avant qu'ION ne puisse être supprimé de l'arborescence de préproduction, les futures versions du kernel devront peut-être à nouveau interrompre l'ABI ION. L'équipe des systèmes Android ne s'attend pas à ce que ces modifications affectent les appareils lancés avec la prochaine version d'Android, mais elles peuvent affecter les appareils lancés avec les versions d'Android suivantes.

Par exemple, la communauté en amont a proposé de diviser le nœud /dev/ion en plusieurs nœuds par tas de mémoire (par exemple, /dev/ion/heap0) pour permettre aux appareils d'appliquer différentes règles SELinux à chaque tas de mémoire. Si ce changement est implémenté dans une prochaine version du kernel, il cassera l'ABI ION.