見出し画像

MGL週報 #26 - Appleの「理由の宣言が求められるAPI」について

このエントリはゲーム開発用フレームワーク「MGL」の開発記録です.MGLは次のWebサイトにて無償で公開されています.

次期アップデートの作業が中途半端になっていて今週の週報どうしようかなと考えていましたが,何も書かないより何か書いたほうがマシだろうという事で遅ればせながら投稿します.ちょうど先週末にAppleさんが燃料投下してくれたので,タイムリーなネタとして今秋から始まる新ルールとそのMGL側の対応についてのお話です.

10/29 追記:実際の対応方法についても書き残しておきました.参考にしたい方はよろしければどうぞ.



理由の宣言が求められるAPI

前回のWWDCで発表された事ですが,macOS以外のApple環境ではより厳格なプライバシー保護の仕組みが導入されます.このうちの1つとして,使い方次第ではユーザーの追跡が可能となるAPIを使用する場合,その用途の宣言をアプリケーション側に組み込む必要があります.この仕組みは今年の秋頃に導入予定で,来春には義務付けられるとの事です.

さて,サードパーティー製のSDKを用いて開発する場合,この対応はSDK側で行う必要があります.これはゲーム開発用フレームワークであるMGLも例外ではなく,対象APIを調査して適切な対応を行わなければなりません.

ちょうど先週末に対象となるAPIの一覧が公開されたため,これらのMGL側の対応方針やその他諸々をお話ししておこうかと思います.

※記事作成時点では公開直後の情報を参照しています.以降の内容は最新の情報とは噛み合わなくなる場合がありますがご了承ください.

対応が必要なAPI

先述の通り,Appleがこのルールを導入する理由はユーザーの追跡を行わせないためです.ユーザーの行動を追跡するために,何らかの情報からユーザーを特定する事は「フィンガープリンティング」と呼ばれています.安全性とプライバシーの尊重を売りにしているAppleはこの手法を是としておらず,より厳格化するために今回のルールの導入に至ったようです.

さて,当然ながらアプリケーションの開発はAppleが用意したAPIを用いて行いますが,この中には図らずともユーザーの特定に繋がる情報を得られるAPIも存在します.今回新たに導入されるルールでは,そういったAPIを使用する場合は理由を宣言しておき,その理由とは異なる用途でAPIを使用することを禁じるというものです.

先日公開された,使用するにあたって理由を宣言する必要のあるAPIの一覧は次のリンク先にて公開されています.

これらのAPIを用いる場合,対応した理由の宣言が必要です.この理由は好き勝手に定義できるものではなく,Apple側が用意した中からいずれかを選択します.これにより,特定のAPIは特定の用途以外では使っちゃダメとなる訳です.

さてさて,ここからが本題.リストアップされているAPIのうち,MGLが使用しているAPIは次の2種類です.

  • mach_absolute_time()

  • stat()とその派生関数

これらの詳細と対応方針についてを説明しましょう.

mach_absolute_time()

mach_absolute_time()は,システムが起動してからの時間をTickTimeで返す関数です.

TickTimeとは何ぞや? というと,これはCPU時間とも呼ばれる高精度の時間単位です.CPUはハードウェア的には順序回路と呼ばれる類のもので,順路回路の動作には一定期間毎に届くクロック信号が必要になります.このクロック信号を元に計測するのがTickTimeであり,ほとんどのコンピュータでは最も精度の高いタイマーになります.

これがゲームアプリケーションのどこに使用されるのかというと,経過時間の測定に用いられています.

多くのゲームはフレーム単位で動作しますが,フレームレートは環境によってまちまちです.どのような環境でも同じように動作させようとする場合,フレーム間の経過時間に基づいてゲーム内の世界を動かす必要があります.この経過時間の計算にも様々な方法がありますが,ゲーム用途に耐えられる高精度なものとなると,どうしてもこのTickTimeくらいしか選択肢がありません.

このAPIに対応する使用理由の宣言は1つしかありません.

35F9.1

Declare this reason to access the system boot time in order to measure the amount of time that has elapsed between events that occurred within the app or to perform calculations to enable timers.
Information accessed for this reason, or any derived information, may not be sent off-device. There is an exception for information about the amount of time that has elapsed between events that occurred within the app, which may be sent off-device.

翻訳:
アプリ内で発生したイベント間の経過時間を測定するため,またはタイマーを有効にするための計算を実行するために,システム起動時間にアクセスするためにこの理由を宣言します.
この理由でアクセスされた情報,または派生する情報は,デバイス外に送信することはできません.ただし,アプリ内で発生したイベント間の経過時間に関する情報は例外であり,デバイス外に送信することができます.

先述の公式ドキュメントより引用

MGLでの用途と合致しているため,宣言を追加すれば問題は無さそうですね.取得した値そのものはデバイス外への送信が禁止されていますが,そこから計算した経過時間については特に制限は無いようです.ただし,MGLのAPIにはTickTimeそのものを返すものがあるため,これを外部に送信しないようAPIリファレンスに記述しておく必要はありそうです.

ところで,これに近い機能のmach_continuous_time()は対象外ですが,これはどうなんでしょう? 違いはスリープ中にも時間が経過するか否かなのですが,ユーザーの特定が難しいからOKという事でしょうか.スリープと復帰のタイミングはアプリケーションからも取得可能なので,こちらで置き換えるという方法も不可能ではなさそうです.

stat()とその派生関数

ちょっと作業が必要そうなのがこちら.

stat()はPOSIXに準拠したC言語の標準関数で,ファイルエントリの情報を取得するための関数です.LinuxとBSDでは細かい部分で異なるという断りを入れつつ,Linuxのマニュアルページの日本語訳へのリンクを貼っておきます.

ちょうど先週の週報で書いた通り,MGLでファイルアクセスを担うのは環境毎のファイルデリゲートです.そして,Apple環境向けのファイルデリゲートはPOSIX準拠で書かれており,当然ながらこのstat()も多用しています.

困った事に,このstat()は「ファイルのタイムスタンプにアクセスするAPI」としてリストアップされています.対応する理由もファイルのタイムスタンプに関するものだけです.裏を返すと,タイムスタンプの取得以外にこの関数を使用することはできません.

stat()は大変便利な関数で,パスを与えるだけでファイルの内容以外のほとんどの情報が得られます.ファイルサイズ,ファイルの種類,存在チェック,アクセスできない場合はその理由もstat()で得られます.しかし,今回のルールの導入により,これらの情報の取得にはstat()は使用できなくなってしまいました.

……まあ,無理もない話なんですけどね.特定のファイルのinode番号なんてユーザー間で重複することは滅多に無いでしょうから,ユーザーの追跡にはもってこいの情報ですし.

この問題への対応策として,POSIX準拠のファイルデリゲートの使用をやめてNSFileManagerを用いたファイルデリゲートを新たに用意する予定です.本来はこちらが正攻法だったのですが,あえてPOSIX準拠で書いたのはLinuxなどの他の環境への移植を見据えての事でした.こうなってしまった以上,もう移植性を優先する必要も無いでしょう.

ちょっと疑問

ドキュメントには特に書かれていなかった事なのですが,C++の標準ライブラリはどうなのでしょうね?

実のところ,MGLが使用している対象APIはC++の標準ライブラリで置き換えができます.時間計測はstd::chrono::steady_clockで,ファイルデリゲートの実装はstd::filesystemで代用できるはずです.

これらのAPIが使用OKなのか,単にリストアップされていないだけなのかは現時点では判断が付きません.

例えば,ストレージの空き容量を取得するAPIは軒並みリストアップされているのですが,C++の標準ライブラリにあるstd::filesystem::spaceはリストに含まれていません.そして,リンク先の情報によると,この関数はPOSIX環境においてstatvfs()を利用すると書かれています.このstatvfs()は理由の宣言が必要なAPIとしてリストアップされています.

もし内部で該当APIを呼び出している場合はNGとなると,これは厄介な問題です.それを確認する方法はというと,ソースコードを読むかデバッガで追いかけるくらいしか思い当たりません.

要するに,現時点ではC++の標準ライブラリの使用可否が不明瞭だよね,というお話.対象APIとその理由のリストは随時更新されていくらしいので,この辺りも整備されていくことを期待しています.


その他

今月から忙しくなるような気がしていたが別にそんなことはなかったぜ!

この記事が気に入ったらサポートをしてみませんか?