APDU コマンド出ました
今回は学習目的で「しっかりテストコードを書く」と決めて始めてしまったので、ちょっとしたことを実現するだけでもとても時間がかかります。おかげで、Kotlin の超基本的な文法みたいなところはちょっと書き慣れてきたような気がしないでもないです。
MF を SELECT (一回目)
ということで、APDU コマンドの送受信のために最低限必要となるコードを書いて、基本チャネルを使って MF に対して SELECT コマンドを送信してみました。動作確認に使ったスマートフォンが出力する radio ログを見てみると、ちゃんと期待通りの RIL コマンドとその応答が表示されています。
[0146]> RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC [SUB0] [0146]< RIL_REQUEST_SIM_TRANSMIT_APDU_BASIC IccIoResult sw1:0x61 sw2:0x56 Payload: ******* Error: unknown [SUB0]
良かった良かった ... いや、SELECT は出来てそうですけど SW 61xx じゃないですか。なるほど、SW 61xx のハンドリングはアプリ側でやってあげないといけなかったんですね。確かにそんな感じです。
MF を SELECT (二回目)
SW 61xx に加えて SW 6Cxx についても考慮するようコードを書き換えて、今度は送信したコマンドと受信したデータの両方を自前でログに出力してみました。
V/TelephonyInterface0: Sent: 00A40004023F00 V/TelephonyInterface0: Received: 6156 V/TelephonyInterface0: Sent: 00C0000056 V/TelephonyInterface0: Received: 62548202782183023F00A51980017183027FFFCB0D00000000000000000000000000CA01828A0105AB1B84012E9000840188A4068301019501088401FCA40683010A950108C60F90017083010183010A83010B8301819000
いいですね。ターゲットを MF (3F00) にした SELECT (A4) コマンドが送信され、SW 6156 を受けて GET RESPONSE (C0) コマンドを送信。データが返ってきて最後は SW 9000 で終了。ちゃんと送受信できてそうです。
ここまでのクラス構成
TelephonyManager の iccTransmitApduBasicChannel() や iccTransmitApduLogicalChannel() には既に "Deprecated in API level R" が付けられていますが、その代わりに利用することが推奨されている android.se.omapi への移行は Android R 端末を入手してからです。そのため、今回はそれらの TelephonyManager API を使うことにはしましたが、APDU コマンドやその応答は 16 進数の String 表現ではなく android.se.omapi を想定してByteArray で表現するようにしました。 無駄にデータのコンバートが発生しますが、やむを得ませんね。
今後は、クラス図中央上にいる TelephonyInterface クラスを使って APDU コマンドを送信してゆきます。チャネルリソースには限りがあることですし、基本チャネルもしくはその他の論理チャネルの中から一本だけを同時に利用できる仕様にしています。
ところでこの TelephonyManager API ですが、誰でも自由に使えるものではありません。久しぶりにテスト SIM の ARA-M を改変し、作成中のアプリに UICC Carrier Privileges を与えることにしました。
関連のある記事というか日記
普段の業務では使わない Kotlin を学ぶべく、のんびりコードを書いています。
前回の記事というか日記はこちら。
cheerio-the-bear.hatenablog.com
次の回はこちらです。