ION ABI の変更

カーネル 4.14 以上を搭載したデバイスでは、ION カーネル モジュールが大幅にリファクタリングされています。多くのベンダーで、共有メモリバッファを割り当てる際に呼び出すグラフィックス メモリ アロケータ(gralloc)のハードウェア抽象化レイヤ(HAL)での実装に同モジュールが利用されており、リファクタリングによる影響がおよびます。このページでは、従来のベンダーコードを ION の新しいバージョンに移行する方法を紹介し、将来起こる可能性があるアプリケーション バイナリ インターフェース(ABI)の互換性の問題について説明します。

ION について

ION は、アップストリーム カーネルで開発中のステージング ツリーの一部です。ステージングに際し、カーネルのメジャー バージョンが異なると、ION のユーザー空間とカーネルの間に位置する ABI に互換性の問題が生じる可能性があります。ION ABI で問題が生じたとしても、通常のアプリやリリース済みのデバイスに直接の影響が生じることはありません。しかし、ベンダーがカーネルを新しいメジャー バージョンに移行する際には、変更された内容が ION を呼び出すベンダーコードに影響する可能性があります。また、Android システムチームが ION をステージング ツリーから移行してアップストリームで扱う際にも、ABI の互換性の問題が起こる可能性があります。

Android-4.14 における変更

カーネル 4.12 では、ION カーネルコードが大幅にリファクタリングされ、他のカーネル フレームワークと重複していた部分のクリーンアップと削除が行われました。その結果、従来の ION ioctl の多くが不要となり、削除されました。

ION client と ION handle の削除

カーネル 4.12 より前のバージョンでは、/dev/ion を open することで ION client が割り当てられていました。ION_IOC_ALLOC ioctl により新しいバッファが割り当てられ、それを ION handle(opaque 型の整数型で、割り当てられる ION client にのみ有意な値)としてユーザー空間に返していました。バッファをユーザー空間にマッピングする、もしくは他のプロセスと共有する際には、ION_IOC_SHARE ioctl により、ION handle が dma-buf fd として再エクスポートされていました。

カーネル 4.12 では、ION_IOC_ALLOC ioctl により dma-buf fd が直接出力されます。中間処理として用意されていた ION handle は、ION handle の使用や生成を行うすべての ioctl と合わせて削除されました。dma-buf fd は特定の ION client には結び付けられていないため、ION_IOC_SHARE ioctl が不要になり、ION client のインフラストラクチャもすべて削除されています。

cache-coherency ioctl の追加

カーネル 4.12 より前のバージョンでは、ファイル ディスクリプタをメモリと同期させる ION_IOC_SYNC ioctl が提供されていました。ただ、この ioctl についてはドキュメントが十分に用意されておらず、柔軟性に欠けていたことから、多くのベンダーがキャッシュ メンテナンスを行うためのカスタム ioctl を実装していました。

カーネル 4.12 では、ION_IOC_SYNClinux/dma-buf.h で定義されている DMA_BUF_IOCTL_SYNC ioctl に置き換えられました。DMA_BUF_IOCTL_SYNC は CPU へのアクセスの開始と終了のたびに呼び出され、そのアクセスが読み取り、書き込み、両方のどれにあたるかがフラグで示されます。DMA_BUF_IOCTL_SYNCION_IOC_SYNC よりも複雑ですが、背後で動作するキャッシュ メンテナンス操作について、ユーザー空間でより詳細に管理できるようになります。

DMA_BUF_IOCTL_SYNC はカーネルの安定版 ABI であり、ION による割り当てかどうかにかかわらず、すべての dma-buf fd で使用できます。

Android-4.12 以上へのベンダーコードの移行

Android システムチームは、ユーザー空間の client について、オープン コーディングで ioctl() を呼び出すのではなく、libion を使用するように強く推奨しています。Android 9 以降の libion では、ランタイムに ION ABI が自動的に検出され、カーネル間の相違が顕在化しないような処理が行われます。しかし、カーネル 4.12 以降からは、ion_user_handle_t handle を生成または使用する libion 関数は機能しなくなりました。この関数は、以下の dma-buf fd の同等の操作よって置き換えられており、すべてのカーネル バージョンで利用できます。

従来の ion_user_handle_t 呼び出し 同等の dma-buf fd 呼び出し
ion_alloc(ion_fd, …, &buf_handle) ion_alloc_fd(ion_fd, ..., &buf_fd)
ion_share(ion_fd, buf_handle, &buf_fd) N/A(dma-buf fd ではこの呼び出しは不要です)
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(dma-buf fd ではこの呼び出しは不要です)
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, ...);

カーネル内の client については、カーネル向け API のエクスポートが ION では行われなくなったことから、ion_import_dma_buf_fd() でカーネル内 ION カーネル API を使用していたドライバを、dma_buf_get()カーネル内 dma-buf API を使用するように変換する必要があります。

将来的な ION ABI の互換性の問題

ION がステージング ツリーに移行するまでに、今後リリースされるカーネルで ION ABI の互換性の問題が再び生じる可能性があります。Android システムチームでは、こうした変更が Android の次期バージョンで動作するデバイスに影響するとは想定していません。ただし、次期バージョンより後の Android においては、デバイスに影響をおよぼす可能性があります。

たとえば、アップストリームのコミュニティでは、デバイスが各ヒープに異なる SELinux ポリシーを適用できるように、単一の /dev/ion ノードをヒープごとの複数のノードに分割します(例: /dev/ion/heap0)。このような変更が将来のカーネル リリースで実装されると、ION ABI に互換性の問題が生じる恐れがあります。