中継サーバを書いて、初めての Android アプリを作った

当時の開発ログを見返しながらのメモ。

同じ機械の中ならつながるようになったので、次はスマホ。
ただスマホは携帯回線の NAT の向こうにいるので、外から直接は話しかけられない。

■小さな中継

みんなが話しかけられる場所に中継(relay)を1つ置く。
5/22 の最初の版は C で200行ちょっと。12バイトのヘッダに「誰から・誰へ」を書いて送ると、中継が転送するだけ。

相手は IP・ポートではなくノード番号で覚える。スマホが Wi-Fi から携帯回線に切り替わっても、次に何か送れば住所が勝手に更新される。つなぎ直しの処理が要らない。

最初のテストで、終了の合図を送っても中継が止まらずに固まった。signal() だと受信待ちが自動でやり直される設定になるのが原因。sigaction() に変更。

■認証をつける

5/26 に認証を追加。送る側と中継が同じ鍵を持って、パケットごとに HMAC-SHA256。同じパケットの再送も弾く。
SHA-256 は OpenSSL を使わずに自前。中継は「1ファイル置けば動く」ままにしたかったので。

気をつけたのは確認の順番。署名が正しいのを先に確認して、合っていたときだけ再送チェック用の記録を更新する。逆にすると、でたらめなパケットで記録を進められてしまう。

■カーネルをライブラリにする

Android アプリからはカーネルを共有ライブラリ(.so)として読み込む。5/22 に試したら起動途中で落ちた。

最初は切り替え処理のアセンブリを疑ったけど違った。原因はメモリの端を決める定数。組み込み向けの「メモリの終わりはこのへん」という値が、アドレスがランダムに散らばる環境では的外れになって、メモリの大きさの計算がおかしくなっていた。疑う場所が1段ずれていた。

■APK ができた

26日の最後に APK が1つできた。3.5MB。中に p-kernel と中継につなぐ部分。
標準では充電中だけ動く。アプリを閉じても止まらないように、通知を出したまま動く形(フォアグラウンドサービス)。

ビルド環境は aarch64 の Linux だったけど、Android の開発ツールは x86_64 用しかない。ツールの実行ファイルを1つずつ qemu-x86_64 越しに呼ぶスクリプトで包んで無理やり動かした。遅いけど動く。

ヘッダを探す順番を1つ間違えて、エラーの定義が丸ごと別物になり1時間溶かしたのもこの日…

この日はビルドして中身を確かめたところまで。実際にスマホで動かしたのはもう少しあと。

※リポジトリ: https://github.com/monyuonyu/p-kernel

※この記事は、p-kernel の開発を手伝ってもらっている AI(Claude)と一緒に書いています。

コメントを書く