クマは森で用を足しますか?

アウトプットは重要です。

SM-DP+ (IIJ) で学ぶ OpenSSL

先日、Pixel 4 の eSIM に STORE DATA コマンドを送信し、eSIM に入っていたプロファイルの情報を読み出しました。eSIM には IIJ のプロファイルが入っていますので、同プロファイルに関する Notification の送信先アドレスも得ることができました。プロファイル情報の読み出しについては、下記のエントリをご覧ください。

cheerio-the-bear.hatenablog.com

今回はその (おそらく SM-DP+ の) アドレスを使い、OpenSSL について少し学んでみました。ここのところ担当している業務でこれ系のコードを書くことは滅多にないので、良いエクササイズになりました。

OpenSSL で接続してみる : openssl s_client

まずは、SM-DP+ の FQDN をそのまま指定して openssl s_client を実行してみます。SM-DP+ から受け取った証明書の検証結果は、下記のように X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN (19) になります。

$ openssl s_client -connect SM-V4-033-A-GTM.PR.GO-ESIM.COM:443
...
    Start Time: 1612622663
    Timeout   : 7200 (sec)
    Verify return code: 19 (self signed certificate in certificate chain)
    Extended master secret: no

GSMA ルート CI の証明書を指定していないので、サーバー証明書の検証結果が X509_V_OK (0) にならないのは想定通りです。GSMA の下記サイトから、SGP.21 と SGP.22 に対応する方のルート CI 証明書をダウンロードして指定します。

www.gsma.com

結果は下記の通り、今度はサーバー証明書の検証結果が X509_V_OK (0) になりました。

$ openssl s_client -connect SM-V4-033-A-GTM.PR.GO-ESIM.COM:443 -CAfile ./Symantec_GSMA_RSPv2-Root-CI1.pem
...
    Start Time: 1612622673
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: no

OpenSSL で接続してみる : 自作

次に、上記のコマンドと同じようなことをする小さな実行ファイルを、OpenSSL を使って久しぶりに C 言語で書いて作ってみました。引数で受け取った PEM ファイルを SSL_CTX_load_verify_locations() で指定して接続し、SSL_get_peer_certificate() と SSL_get_verify_result() を使ってサーバー証明書を検証します。あっ!コミットメッセージに typo ある ..

github.com

GSMA のルート CI 証明書を指定しない場合、サーバー証明書の検証結果は下記のように X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN (19) になります。IIJ の SM-DP+ でも楽天モバイルの SM-DP+ でも、結果は同じです。

$ ./sample -n SM-V4-033-A-GTM.PR.GO-ESIM.COM
Verify Result: 19

$ ./sample -n rakuten.prod.ondemandconnectivity.com
Verify Result: 19

GSMA のルート CI 証明書を指定すれば、X509_V_OK (0) になりました。それなりに期待した通りに動いてくれたようです。

$ ./sample -n SM-V4-033-A-GTM.PR.GO-ESIM.COM -c ./Symantec_GSMA_RSPv2-Root-CI1.pem
Verify Result: 0

$ ./sample -n rakuten.prod.ondemandconnectivity.com -c ./Symantec_GSMA_RSPv2-Root-CI1.pem
Verify Result: 0

eSIM が無ければ Pixel 4 を潰せばいいじゃない

リムーバブルな eSIM が手に入らない

eSIM にコマンドを送りたくなること、ありますよね。4FF/nano カードタイプのいわゆるリムーバブルな eSIM を入手し、PC/SC インターフェースを通して ES10x のコマンドを送ることができればと考えたんですけど、そもそもそんな eSIM を簡単に入手できそうにありません。

f:id:cheerio-the-bear:20210127230729p:plain

SGP.26 のテスト証明書を入れた商品は見つけましたが、それでは今後やれることが限られてしまいそうです。海外の eSIM 事業者さんにもお尋ねしてみましたが、門前払いみたいな感じでした。まぁ、そりゃそうでしょう。

リムーバブルじゃなくてもいいか(諦めた)

全く eSIM が手に入らないのかというと、そういうわけではありません。リムーバブルなカードタイプではなく、更には既に商品に組み込まれてしまっているだけのことです。所望のものが手に入らないのはもう仕方がないということで、Pixel 4 に組み込まれている eSIM を利用することにしました。

f:id:cheerio-the-bear:20210127230744p:plain

我ながら適当なワークアラウンドを考えたものです。adb shell content コマンドを使って ES10x コマンド部を Android 端末に渡し、端末内に追加する Content Provider を通して eSIM に送り込みます。アプリから見れば、ES10x コマンドの送信をお願いした先の仕組みが違うだけのことで、何ら不都合はありません。不都合として何か挙げるとするならば、Pixel 4 をルート化しないといけないことくらいでしょうか。

今回作成した Content Provider はこちら

クライアントから ES10x コマンドを受け取り、APDU ヘッダを付けて STORE DATA コマンドにして、テレフォニー API を使って eSIM に送りこむだけの Content Provider です。論理チャネルのオープン・クローズや ISD-R の選択もやりますが、どうあれ大した処理ではないのでコード量は極小です。

github.com

ProfileInfoListRequest 'BF2D' の実行例をご紹介します。Content URI の最後のスラッシュ以降が ES10b コマンド部で、そこで指定したコマンドデータが STORE DATA コマンドに載せられて eSIM まで運ばれます。要求するデータオブジェクトは profileState '9F70' と profileName '92'、profileClass '95'、notificationConfigurationInfo 'B6' の四つ。

$ adb shell content query --uri content://com.github.cheeriotb.isdrap.provider/store/BF2D075C059F709295B6
Row: 0 response=BF2D7DA07BE31D9F7001009214416E726974737520546573742050726F66696C65950100E35A9F700100920349494A950102B64C302480020410811E534D2D56342D3033332D412D47544D2E50522E474F2D4553494D2E434F4D302480020780811E534D2D56342D3033332D412D47544D2E50522E474F2D4553494D2E434F4D9000

Android 端末からは、ProfileInfoListResponse 'BF2D' とステータスワード '9000' が返っています。テストプロファイルがひとつ、そして IIJ の商用プロファイルがひとつ入っていることが読み取れます。

ProfileInfo profileState disabled (0)
profileName Anritsu Test Profile
profileClass test (0)
ProfileInfo profileState disabled (0)
profileName IIJ
profileClass operational (2)
notificationConfigurationInfo profileManagementOperation notificationDelete (3)
notificationAddress SM-V4-033-A-GTM.PR.GO-ESIM.COM
notificationConfigurationInfo profileManagementOperation notificationInstall (0)
notificationAddress SM-V4-033-A-GTM.PR.GO-ESIM.COM

端末から返ってくるデータサイズが大きい場合の動作をまだ確認できていないので、うまく動かないケースがあれば都度修正しようと思います。また、現状は Pixel 端末を想定したコードになっていますが、ほんの少し書き換えるだけで Rakuten Mini 等にも転用できるはずです。

久しぶりにリフレクションしました

今回利用した API の中には @hide なものも含まれていたので、久しぶりにリフレクションを使いました。Kotlin だと、他にもっと綺麗に書く方法もあるんでしょうか。

    transmit = TelephonyManager::class.java.getDeclaredMethod(
        "iccTransmitApduLogicalChannelBySlot", Int::class.java,
        Int::class.java, Int::class.java, Int::class.java, Int::class.java,
        Int::class.java, Int::class.java, String::class.java)

    val tm = context!!.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager?
        ?: throw UnsupportedOperationException("Telephony Manager is unavailable")

    transmitRsp = Response(transmit.invoke(tm, PHYSICAL_SLOT_NUM, openRsp.channel,
            STORE_DATA_CLA, STORE_DATA_INS, p1, seqNumber, block.length / 2, block)
            as String?)

あと、サービスだけどうして Java で書いちゃったのかは謎です。適当に試してみたときに、勝手に手がそう動いちゃったんだと思います。

apt-get install build-essential で Media change: please insert the disc labeled

下記コマンドで Ubuntu 20.04 LTS に "build-essential" をインストールしようとしたら、CD-ROM の挿入を求められました。

$ sudo apt-get update
$ sudo apt-get install build-essential

このメッセージです。

Media change: please insert the disc labeled
 'Ubuntu 20.04.01 LTS _Focal Fossa_ - Release amd64 (20200731)’
in the drive '/cdrom/' and press [Enter]
f:id:cheerio-the-bear:20210104222726p:plain
"Media change" のお誘い

下記 FAQ のコメント欄に書かれているように、/etc/apt/sources.list の一行目の先頭に # を入れてコメントアウトすることで解決しました。

www.cyberciti.biz

エディタはなんでもいいんですけど、

$ sudo gedit /etc/apt/sources.list

一行目をこうです。

f:id:cheerio-the-bear:20210104223204p:plain
一行目をコメントアウト

久しぶりにデスクトップ PC を組み立てたので、各種設定を少しずつ進めているところです。

cheerio-the-bear.hatenablog.com

SM-DP+ で学ぶ TLS ハンドシェイク (楽天モバイル)

Rakuten Mini に tcpdump を入れて、楽天モバイルの SM-DP+ と通信する際の TLS ハンドシェイクの様子を見てみました。SM-DP+ のアドレスが "rakuten.prod.ondemandconnectivity.com" になっているので、Thales (Gemalto) のサービスを利用されているのでしょうか。なるほど、確かにそういうソリューションはアリだと思います。

f:id:cheerio-the-bear:20210101230257p:plain
TLS ハンドシェイク
@startuml
"SM-DP+" <- LPA: Client Hello (rakuten.prod.ondemandconnectivity.com)
"SM-DP+" -> LPA: Server Hello (TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384)
"SM-DP+" -> LPA: Certificate (*.prod.ondemandconnectivity.com, GSM Association - RSP2 Root CI1)
"SM-DP+" -> LPA: Server Key Exchange
"SM-DP+" -> LPA: Server Hello Done
"SM-DP+" <- LPA: Client Key Exchange
"SM-DP+" <- LPA: Change Cipher Spec
"SM-DP+" <- LPA: Finished
"SM-DP+" -> LPA: Change Cipher Spec
"SM-DP+" -> LPA: Finished
@enduml

ハンドシェイク中に流れていたメッセージとパラメータは、資料としてここに貼っておきます。

(SM-DP+ < LPA) Client Hello

Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Client Hello
        Content Type: Handshake (22)
        Version: TLS 1.0 (0x0301)
        Length: 198
        Handshake Protocol: Client Hello
            Handshake Type: Client Hello (1)
            Length: 194
            Version: TLS 1.2 (0x0303)
            Random: aaae079065c30cd5523bb8e3de7f8b2b5d142623b93e66d53867f07945f00146
                GMT Unix Time: Sep 28, 2060 02:32:00.000000000 東京 (標準時)
                Random Bytes: 65c30cd5523bb8e3de7f8b2b5d142623b93e66d53867f07945f00146
            Session ID Length: 0
            Cipher Suites Length: 28
            Cipher Suites (14 suites)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca9)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
                Cipher Suite: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
                Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
                Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
                Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
                Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
                Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
                Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
            Compression Methods Length: 1
            Compression Methods (1 method)
                Compression Method: null (0)
            Extensions Length: 125
            Extension: renegotiation_info (len=1)
                Type: renegotiation_info (65281)
                Length: 1
                Renegotiation Info extension
                    Renegotiation info extension length: 0
            Extension: server_name (len=42)
                Type: server_name (0)
                Length: 42
                Server Name Indication extension
                    Server Name list length: 40
                    Server Name Type: host_name (0)
                    Server Name length: 37
                    Server Name: rakuten.prod.ondemandconnectivity.com
            Extension: extended_master_secret (len=0)
                Type: extended_master_secret (23)
                Length: 0
            Extension: session_ticket (len=0)
                Type: session_ticket (35)
                Length: 0
                Data (0 bytes)
            Extension: signature_algorithms (len=20)
                Type: signature_algorithms (13)
                Length: 20
                Signature Hash Algorithms Length: 18
                Signature Hash Algorithms (9 algorithms)
                    Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
                        Signature Hash Algorithm Hash: SHA256 (4)
                        Signature Hash Algorithm Signature: ECDSA (3)
                    Signature Algorithm: rsa_pss_rsae_sha256 (0x0804)
                        Signature Hash Algorithm Hash: Unknown (8)
                        Signature Hash Algorithm Signature: Unknown (4)
                    Signature Algorithm: rsa_pkcs1_sha256 (0x0401)
                        Signature Hash Algorithm Hash: SHA256 (4)
                        Signature Hash Algorithm Signature: RSA (1)
                    Signature Algorithm: ecdsa_secp384r1_sha384 (0x0503)
                        Signature Hash Algorithm Hash: SHA384 (5)
                        Signature Hash Algorithm Signature: ECDSA (3)
                    Signature Algorithm: rsa_pss_rsae_sha384 (0x0805)
                        Signature Hash Algorithm Hash: Unknown (8)
                        Signature Hash Algorithm Signature: Unknown (5)
                    Signature Algorithm: rsa_pkcs1_sha384 (0x0501)
                        Signature Hash Algorithm Hash: SHA384 (5)
                        Signature Hash Algorithm Signature: RSA (1)
                    Signature Algorithm: rsa_pss_rsae_sha512 (0x0806)
                        Signature Hash Algorithm Hash: Unknown (8)
                        Signature Hash Algorithm Signature: Unknown (6)
                    Signature Algorithm: rsa_pkcs1_sha512 (0x0601)
                        Signature Hash Algorithm Hash: SHA512 (6)
                        Signature Hash Algorithm Signature: RSA (1)
                    Signature Algorithm: rsa_pkcs1_sha1 (0x0201)
                        Signature Hash Algorithm Hash: SHA1 (2)
                        Signature Hash Algorithm Signature: RSA (1)
            Extension: status_request (len=5)
                Type: status_request (5)
                Length: 5
                Certificate Status Type: OCSP (1)
                Responder ID list Length: 0
                Request Extensions Length: 0
            Extension: application_layer_protocol_negotiation (len=11)
                Type: application_layer_protocol_negotiation (16)
                Length: 11
                ALPN Extension Length: 9
                ALPN Protocol
                    ALPN string length: 8
                    ALPN Next Protocol: http/1.1
            Extension: ec_point_formats (len=2)
                Type: ec_point_formats (11)
                Length: 2
                EC point formats Length: 1
                Elliptic curves point formats (1)
                    EC point format: uncompressed (0)
            Extension: supported_groups (len=8)
                Type: supported_groups (10)
                Length: 8
                Supported Groups List Length: 6
                Supported Groups (3 groups)
                    Supported Group: x25519 (0x001d)
                    Supported Group: secp256r1 (0x0017)
                    Supported Group: secp384r1 (0x0018)

(SM-DP+ > LPA) Server Hello

Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 112
        Handshake Protocol: Server Hello
            Handshake Type: Server Hello (2)
            Length: 108
            Version: TLS 1.2 (0x0303)
            Random: ddfa9070ac4963c42f1ff9a24f22850c2c0ceff5b11936e6444f574e47524401
                GMT Unix Time: Jan  6, 2088 09:01:52.000000000 東京 (標準時)
                Random Bytes: ac4963c42f1ff9a24f22850c2c0ceff5b11936e6444f574e47524401
            Session ID Length: 32
            Session ID: 1467e29c67b26cc0d2a711124f1f0a5430c05e88ce2d9b9294d4199780fd3652
            Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
            Compression Method: null (0)
            Extensions Length: 36
            Extension: renegotiation_info (len=1)
                Type: renegotiation_info (65281)
                Length: 1
                Renegotiation Info extension
                    Renegotiation info extension length: 0
            Extension: server_name (len=0)
                Type: server_name (0)
                Length: 0
            Extension: ec_point_formats (len=4)
                Type: ec_point_formats (11)
                Length: 4
                EC point formats Length: 3
                Elliptic curves point formats (3)
                    EC point format: uncompressed (0)
                    EC point format: ansiX962_compressed_prime (1)
                    EC point format: ansiX962_compressed_char2 (2)
            Extension: application_layer_protocol_negotiation (len=11)
                Type: application_layer_protocol_negotiation (16)
                Length: 11
                ALPN Extension Length: 9
                ALPN Protocol
                    ALPN string length: 8
                    ALPN Next Protocol: http/1.1
            Extension: extended_master_secret (len=0)
                Type: extended_master_secret (23)
                Length: 0

(SM-DP+ > LPA) Certificate, Server Key Exchange, Server Hello Done

Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Certificate
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 1330
        Handshake Protocol: Certificate
            Handshake Type: Certificate (11)
            Length: 1326
            Certificates Length: 1323
            Certificates (1323 bytes)
                Certificate Length: 728
                Certificate: 308202d430820279a003020102021003485c90de04b1e87a12a507d3e768cd300a06082a… (id-at-commonName=*.prod.ondemandconnectivity.com,id-at-organizationName=GEMALTO SA,id-at-localityName=Tours,id-at-countryName=FR)
                    signedCertificate
                        version: v3 (2)
                        serialNumber: 0x03485c90de04b1e87a12a507d3e768cd
                        signature (ecdsa-with-SHA256)
                            Algorithm Id: 1.2.840.10045.4.3.2 (ecdsa-with-SHA256)
                        issuer: rdnSequence (0)
                            rdnSequence: 2 items (id-at-commonName=GSM Association - RSP2 Root CI1,id-at-organizationName=GSM Association)
                                RDNSequence item: 1 item (id-at-organizationName=GSM Association)
                                    RelativeDistinguishedName item (id-at-organizationName=GSM Association)
                                        Id: 2.5.4.10 (id-at-organizationName)
                                        DirectoryString: printableString (1)
                                            printableString: GSM Association
                                RDNSequence item: 1 item (id-at-commonName=GSM Association - RSP2 Root CI1)
                                    RelativeDistinguishedName item (id-at-commonName=GSM Association - RSP2 Root CI1)
                                        Id: 2.5.4.3 (id-at-commonName)
                                        DirectoryString: printableString (1)
                                            printableString: GSM Association - RSP2 Root CI1
                        validity
                            notBefore: utcTime (0)
                                utcTime: 2020-05-22 00:00:00 (UTC)
                            notAfter: utcTime (0)
                                utcTime: 2022-08-24 23:59:59 (UTC)
                        subject: rdnSequence (0)
                            rdnSequence: 4 items (id-at-commonName=*.prod.ondemandconnectivity.com,id-at-organizationName=GEMALTO SA,id-at-localityName=Tours,id-at-countryName=FR)
                                RDNSequence item: 1 item (id-at-countryName=FR)
                                    RelativeDistinguishedName item (id-at-countryName=FR)
                                        Id: 2.5.4.6 (id-at-countryName)
                                        CountryName: FR
                                RDNSequence item: 1 item (id-at-localityName=Tours)
                                    RelativeDistinguishedName item (id-at-localityName=Tours)
                                        Id: 2.5.4.7 (id-at-localityName)
                                        DirectoryString: printableString (1)
                                            printableString: Tours
                                RDNSequence item: 1 item (id-at-organizationName=GEMALTO SA)
                                    RelativeDistinguishedName item (id-at-organizationName=GEMALTO SA)
                                        Id: 2.5.4.10 (id-at-organizationName)
                                        DirectoryString: printableString (1)
                                            printableString: GEMALTO SA
                                RDNSequence item: 1 item (id-at-commonName=*.prod.ondemandconnectivity.com)
                                    RelativeDistinguishedName item (id-at-commonName=*.prod.ondemandconnectivity.com)
                                        Id: 2.5.4.3 (id-at-commonName)
                                        DirectoryString: uTF8String (4)
                                            uTF8String: *.prod.ondemandconnectivity.com
                        subjectPublicKeyInfo
                            algorithm (id-ecPublicKey)
                                Algorithm Id: 1.2.840.10045.2.1 (id-ecPublicKey)
                                ECParameters: namedCurve (1)
                                    namedCurve: 1.2.840.10045.3.1.7 (secp256r1)
                            Padding: 0
                            subjectPublicKey: 04b656ecce3584125a1e6d103b3ba786e042c1a99604d7338a46cb5eaf03c13a2efc93fd…
                        extensions: 7 items
                            Extension (id-ce-certificatePolicies)
                                Extension Id: 2.5.29.32 (id-ce-certificatePolicies)
                                CertificatePoliciesSyntax: 1 item
                                    PolicyInformation
                                        policyIdentifier: 2.23.146.1.2.1.3 (joint-iso-itu-t.23.146.1.2.1.3)
                            Extension (id-ce-cRLDistributionPoints)
                                Extension Id: 2.5.29.31 (id-ce-cRLDistributionPoints)
                                CRLDistPointsSyntax: 1 item
                                    DistributionPoint
                                        distributionPoint: fullName (0)
                                            fullName: 1 item
                                                GeneralName: uniformResourceIdentifier (6)
                                                    uniformResourceIdentifier: http://gsma-crl.symauth.com/offlineca/gsma-rsp2-root-ci1.crl
                            Extension (id-ce-extKeyUsage)
                                Extension Id: 2.5.29.37 (id-ce-extKeyUsage)
                                critical: True
                                KeyPurposeIDs: 2 items
                                    KeyPurposeId: 1.3.6.1.5.5.7.3.1 (id-kp-serverAuth)
                                    KeyPurposeId: 1.3.6.1.5.5.7.3.2 (id-kp-clientAuth)
                            Extension (id-ce-keyUsage)
                                Extension Id: 2.5.29.15 (id-ce-keyUsage)
                                critical: True
                                Padding: 7
                                KeyUsage: 80
                                    1... .... = digitalSignature: True
                                    .0.. .... = contentCommitment: False
                                    ..0. .... = keyEncipherment: False
                                    ...0 .... = dataEncipherment: False
                                    .... 0... = keyAgreement: False
                                    .... .0.. = keyCertSign: False
                                    .... ..0. = cRLSign: False
                                    .... ...0 = encipherOnly: False
                                    0... .... = decipherOnly: False
                            Extension (id-ce-subjectAltName)
                                Extension Id: 2.5.29.17 (id-ce-subjectAltName)
                                GeneralNames: 3 items
                                    GeneralName: dNSName (2)
                                        dNSName: *.prod.ondemandconnectivity.com
                                    GeneralName: dNSName (2)
                                        dNSName: *.prod.ids-odc.gemalto.com
                                    GeneralName: registeredID (8)
                                        registeredID: 1.3.6.1.4.1.31746.1.220.100.101.2 (iso.3.6.1.4.1.31746.1.220.100.101.2)
                            Extension (id-ce-subjectKeyIdentifier)
                                Extension Id: 2.5.29.14 (id-ce-subjectKeyIdentifier)
                                SubjectKeyIdentifier: 8efb03c8e210f825105a66bffe5e1a1927bcc76b
                            Extension (id-ce-authorityKeyIdentifier)
                                Extension Id: 2.5.29.35 (id-ce-authorityKeyIdentifier)
                                AuthorityKeyIdentifier
                                    keyIdentifier: 81370f5125d0b1d408d4c3b232e6d25e795bebfb
                    algorithmIdentifier (ecdsa-with-SHA256)
                        Algorithm Id: 1.2.840.10045.4.3.2 (ecdsa-with-SHA256)
                    Padding: 0
                    encrypted: 3046022100cc75a507eb5c94024aa51ffa4d7d31ed15fe044f477ad88f6cb26abb3e9a78…
                Certificate Length: 589
                Certificate: 30820249308201efa00302010202106e68567a77a0ee7c85ee183963dfaa7a300a06082a… (id-at-commonName=GSM Association - RSP2 Root CI1,id-at-organizationName=GSM Association)
                    signedCertificate
                        version: v3 (2)
                        serialNumber: 0x6e68567a77a0ee7c85ee183963dfaa7a
                        signature (ecdsa-with-SHA256)
                            Algorithm Id: 1.2.840.10045.4.3.2 (ecdsa-with-SHA256)
                        issuer: rdnSequence (0)
                            rdnSequence: 2 items (id-at-commonName=GSM Association - RSP2 Root CI1,id-at-organizationName=GSM Association)
                                RDNSequence item: 1 item (id-at-organizationName=GSM Association)
                                    RelativeDistinguishedName item (id-at-organizationName=GSM Association)
                                        Id: 2.5.4.10 (id-at-organizationName)
                                        DirectoryString: printableString (1)
                                            printableString: GSM Association
                                RDNSequence item: 1 item (id-at-commonName=GSM Association - RSP2 Root CI1)
                                    RelativeDistinguishedName item (id-at-commonName=GSM Association - RSP2 Root CI1)
                                        Id: 2.5.4.3 (id-at-commonName)
                                        DirectoryString: printableString (1)
                                            printableString: GSM Association - RSP2 Root CI1
                        validity
                            notBefore: utcTime (0)
                                utcTime: 2017-02-22 00:00:00 (UTC)
                            notAfter: generalizedTime (1)
                                generalizedTime: 2052-02-21 23:59:59 (UTC)
                        subject: rdnSequence (0)
                            rdnSequence: 2 items (id-at-commonName=GSM Association - RSP2 Root CI1,id-at-organizationName=GSM Association)
                                RDNSequence item: 1 item (id-at-organizationName=GSM Association)
                                    RelativeDistinguishedName item (id-at-organizationName=GSM Association)
                                        Id: 2.5.4.10 (id-at-organizationName)
                                        DirectoryString: printableString (1)
                                            printableString: GSM Association
                                RDNSequence item: 1 item (id-at-commonName=GSM Association - RSP2 Root CI1)
                                    RelativeDistinguishedName item (id-at-commonName=GSM Association - RSP2 Root CI1)
                                        Id: 2.5.4.3 (id-at-commonName)
                                        DirectoryString: printableString (1)
                                            printableString: GSM Association - RSP2 Root CI1
                        subjectPublicKeyInfo
                            algorithm (id-ecPublicKey)
                                Algorithm Id: 1.2.840.10045.2.1 (id-ecPublicKey)
                                ECParameters: namedCurve (1)
                                    namedCurve: 1.2.840.10045.3.1.7 (secp256r1)
                            Padding: 0
                            subjectPublicKey: 049d6abad2f41c2317e76189ebf8de89bb00a997d42d68ff5f5d29fcc8a7eac79937e85f…
                        extensions: 6 items
                            Extension (id-ce-keyUsage)
                                Extension Id: 2.5.29.15 (id-ce-keyUsage)
                                critical: True
                                Padding: 1
                                KeyUsage: 06
                                    0... .... = digitalSignature: False
                                    .0.. .... = contentCommitment: False
                                    ..0. .... = keyEncipherment: False
                                    ...0 .... = dataEncipherment: False
                                    .... 0... = keyAgreement: False
                                    .... .1.. = keyCertSign: True
                                    .... ..1. = cRLSign: True
                                    .... ...0 = encipherOnly: False
                                    0... .... = decipherOnly: False
                            Extension (id-ce-basicConstraints)
                                Extension Id: 2.5.29.19 (id-ce-basicConstraints)
                                critical: True
                                BasicConstraintsSyntax
                                    cA: True
                            Extension (id-ce-subjectAltName)
                                Extension Id: 2.5.29.17 (id-ce-subjectAltName)
                                GeneralNames: 1 item
                                    GeneralName: registeredID (8)
                                        registeredID: 1.3.6.1.4.1.46304 (iso.3.6.1.4.1.46304)
                            Extension (id-ce-certificatePolicies)
                                Extension Id: 2.5.29.32 (id-ce-certificatePolicies)
                                critical: True
                                CertificatePoliciesSyntax: 1 item
                                    PolicyInformation
                                        policyIdentifier: 2.23.146.1.2.1.0 (joint-iso-itu-t.23.146.1.2.1.0)
                            Extension (id-ce-cRLDistributionPoints)
                                Extension Id: 2.5.29.31 (id-ce-cRLDistributionPoints)
                                CRLDistPointsSyntax: 1 item
                                    DistributionPoint
                                        distributionPoint: fullName (0)
                                            fullName: 1 item
                                                GeneralName: uniformResourceIdentifier (6)
                                                    uniformResourceIdentifier: http://gsma-crl.symauth.com/offlineca/gsma-rsp2-root-ci1.crl
                            Extension (id-ce-subjectKeyIdentifier)
                                Extension Id: 2.5.29.14 (id-ce-subjectKeyIdentifier)
                                SubjectKeyIdentifier: 81370f5125d0b1d408d4c3b232e6d25e795bebfb
                    algorithmIdentifier (ecdsa-with-SHA256)
                        Algorithm Id: 1.2.840.10045.4.3.2 (ecdsa-with-SHA256)
                    Padding: 0
                    encrypted: 30450220209758b0e3055b388f2bb97c9e1e66bb4aa246255fdb9a1af6e9651bf388012c…
Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Server Key Exchange
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 114
        Handshake Protocol: Server Key Exchange
            Handshake Type: Server Key Exchange (12)
            Length: 110
            EC Diffie-Hellman Server Params
                Curve Type: named_curve (0x03)
                Named Curve: x25519 (0x001d)
                Pubkey Length: 32
                Pubkey: e77f9f2abe1566d1fdd3c195bff77a78e1dbca48676d3c55826c7739b2dabe5f
                Signature Algorithm: ecdsa_secp256r1_sha256 (0x0403)
                    Signature Hash Algorithm Hash: SHA256 (4)
                    Signature Hash Algorithm Signature: ECDSA (3)
                Signature Length: 70
                Signature: 30440220709f62956b1cccbaf5afc73a762cd6979e6dd40345bf0b3991668b99cdcc3392…
    TLSv1.2 Record Layer: Handshake Protocol: Server Hello Done
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 4
        Handshake Protocol: Server Hello Done
            Handshake Type: Server Hello Done (14)
            Length: 0

(SM-DP+ < LPA) Client Key Exchange, Change Cipher Spec, Finished

Transport Layer Security
    TLSv1.2 Record Layer: Handshake Protocol: Client Key Exchange
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 37
        Handshake Protocol: Client Key Exchange
            Handshake Type: Client Key Exchange (16)
            Length: 33
            EC Diffie-Hellman Client Params
                Pubkey Length: 32
                Pubkey: fe4a98ccd86a53697931d3e2ac14664f483db564830c501f55317098bb2dbf54
    TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
        Content Type: Change Cipher Spec (20)
        Version: TLS 1.2 (0x0303)
        Length: 1
        Change Cipher Spec Message
    TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 40
        Handshake Protocol: Encrypted Handshake Message

(SM-DP+ > LPA) Change Cipher Spec, Finished

Transport Layer Security
    TLSv1.2 Record Layer: Change Cipher Spec Protocol: Change Cipher Spec
        Content Type: Change Cipher Spec (20)
        Version: TLS 1.2 (0x0303)
        Length: 1
        Change Cipher Spec Message
    TLSv1.2 Record Layer: Handshake Protocol: Encrypted Handshake Message
        Content Type: Handshake (22)
        Version: TLS 1.2 (0x0303)
        Length: 40
        Handshake Protocol: Encrypted Handshake Message

DOS/V POWER REPORT を参考にデスクトップ PC を組む

Android OS をフルビルドできるくらいのスペックの開発環境がなんとなく欲しくなってしまったので、PC を新調することにしました。昨今の状況からポータビリティーに拘る必要もあまりなくなっちゃいましたし、Windows 10 とデュアルブート仕様のデスクトップ機にしておけば困ることはないでしょう。

Windows 10 Home と Ubuntu 20.04 LTS のインストールに関する話はこちら。

cheerio-the-bear.hatenablog.com

PC の自作なんて久しぶりなので、DOS/V POWER REPORT に掲載されていた大満足自作プランを参考にさせて頂きました。7 万円プランを参考にしたはずなのに、10 万円プランプラスアルファくらいになりましたよね。でも、既製品を買うよりも全然楽しめるのでヨシ。

モニタと HDMI ケーブル、キーボードとマウスは今回新調せず、下記のものを調達しました。ほとんどのものが Amazon で揃ってしまうことにちょっと驚きました。価格的にもその時点における最安値だったり、最安値と大きな価格差がなかったり。PC パーツは PC パーツショップで、という時代では無くなっているんですね。

ケース Thermaltake Core V21
マザーボード ASRock B550M Pro4
CPU AMD Ryzen 5 3600 BOX
CPU クーラー サイズ 虎徹 Mark II
グラフィックボード MSI GeForce GTX 1660 SUPER AERO ITX OC VD7112
メモリ Crucial CT2K16G4DFD832A DDR4-3200 PC4-25600 (16GB x 2)
M.2 SSD WD Blue SN550 NVMe WDS100T2B0C 1TB
ATX電源ユニット 玄人志向 KRPW-N500W/85+
Wi-Fi モジュール Intel 7260HMW + Fenvi miniPCI/PCI-E wifi 変換ボード
OS Windows 10 Home 64 ビット DSP 版 + Ubuntu 20.04 LTS

ケース

思ったよりも大きいとの評判のこちらのキューブ型ケース、確かに思ったよりも大きいです。でも、ケース内の空間に余裕があって組み立てやすく、良いケースだと思います。もう一台組み立てる機会があれば、Mini-ITX で Core V1 の方も使ってみたいです。

比較のために 1 ドル紙幣を置いてみましたが、このサイズ感、わかるでしょうか。おしゃれなオーブンレンジみたいで、かわいいです。もし「省スペース」が重要な場合は、キューブ型はおすすめしません。

f:id:cheerio-the-bear:20201228024046j:plain:w400
思ったよりも大きい

組み立てる上でほんの少し面倒なのは、電源ユニットを支えるブラケットの部分くらいではないでしょうか。2 つのブラケット部品を組み合わせ、下の写真のようにネジで止めます。

f:id:cheerio-the-bear:20201228025011j:plain:w400
平らな頭のネジはこっち
f:id:cheerio-the-bear:20201228025104j:plain:w400
丸い頭のネジはこっち

CPU

Intel/AMD の CPU 性能比較グラフなんてものがたくさん出回っているじゃないですか。第 10 世代 Core i5 同等もしくはちょい上くらいがいいなと思ったので、Ryzen 5 は 3600 を選択。

CPUクーラー

特にこだわりはないので、売れ筋のものを。

それにしても、最近の CPU クーラーについてくるヒートシンクは大きい。タワーマンションの模型のようにそびえ立ってます。

f:id:cheerio-the-bear:20201228023732j:plain:w400
CPUクーラーのヒートシンクがすごい

グラフィックボード

本来の目的を考えれば、蛇足です。Unity とか Blender とかやりたくなっちゃう未来を見据えて、これくらいのスペックにしてみました。

メモリ

Android OS のフルビルドに必要なメモリ量は増加の一途ですので、そろそろ 32 GBくらいは必要なんだろうと考えました。

www.pc-koubou.jp

ASRock B550M Pro4 の場合、A2 スロットと B2 スロットにそれぞれ装着します。

f:id:cheerio-the-bear:20201228030148j:plain:w400
一番外側に一枚、ひとつ空けてもう一枚

M.2 SSD

1TB あればとりあえずそれでいい、程度の基準で選びました。M.2 SSDヒートシンクは、ASRock B550M Pro4 に付属されているものをそのまま利用。

ATX電源ユニット

これも適当に売れ筋のものを選んじゃいましたが、グラフィックボード用の電源ケーブルがもう少し長いと嬉しい感じでした。今回の構成でもちゃんと届いているので、全く問題はないんですけども。

Wi-Fi モジュール

Mini PCI 用の Wi-Fi モジュールを変換して PCI Express に装着することにしたのは、もう調べるのが面倒になったからです(正直)。マザーボード自体にもスロットがあるわけですし、こんなまどろっこしいことをする必要は本来ないはずです。

この Joekyo さんのブログを拝見して、Windows / Ubuntu の両方で問題なく利用できているとのことでしたので、そのまま乗っかった次第です。

joekyo.com

どちらの OS でも何もしなくてもちゃんと認識してくれて、期待通りでした。ただ、グラフィックボードと並べて挿すと、グラフィックボードのファンとほんの少し干渉してしまいます。一番外側のスロットに挿すことにして、難を逃れています。尚、Wi-Fi モジュールを変換ボードに装着するのは簡単ですが、2 つのアンテナプラグの接続は指の細い人のほうが得意そうです。

f:id:cheerio-the-bear:20201228030044j:plain:w400
不器用には厳しい大きさ

Windows 10 Home 日本語版

プロダクトキーを入手するため、今回は Home の DSP 版を購入しました。価格差が大きくないので、Pro でも良かったかもと思ったりしてます。

送付される DVD メディアではなく、マイクロソフト社から提供されているツールを使ってインストール用 USB メモリを作りました。

www.microsoft.com

Windows 10 Home と Ubuntu 20.04 LTS のデュアルブートにする

[2022/09/05 追記] その後、この PC は Windows 11 Professional と Ubuntu 22.04.1 LTS のデュアルブート機になっています。手順は同じ。

Android OS をフルビルドできるくらいのスペックの開発環境がなんとなく欲しくなってしまったので、PC を新調することにしました。昨今の状況からポータビリティーに拘る必要もあまりなくなっちゃいましたし、Windows 10 とデュアルブート仕様のデスクトップ機にしておけば困ることはないでしょう。

PC のスペックや構成するパーツに関する話はこちら。

cheerio-the-bear.hatenablog.com

インストール方法

デュアルブートを実現する方法について参考にさせて頂こうと思い、複数の個人ブログや企業ブログを見て回りました。実現方法はもちろんのこと、おまじない的なものの類まで複数あって惑わされましたが、結局のところこのシンプルな手順で普通に実現できたみたいです。しばらく使ってみていますが、今のところ不都合はありません。

  1. Windows 10 Home を USB メモリから UEFI モードでインストールする
  2. Windows 10 上で基本パーティションを半分に縮小する
  3. Ubuntu 20.04 LTS を USB メモリから UEFI モードでインストールする

1. Windows 10 Home のインストール

DSP 版で Windows 10 Home のライセンスを購入したので、ついつい届けられた DVD メディアを使ってインストールしてしまったのは失敗だったようです。

同様にしくじってしまった人は、Windows の「システム情報」の BIOS モード表示が「レガシ」になっていることに気付くことでしょう。次のスクリーンショットのように、UEFI モードでインストールされているのが期待です。

BIOS モードは UEFI

下記マイクロソフトのサイトからダウンロードできるインストールメディア作成ツールを使い、UEFI モードでインストールできる USB メモリを作成しましょう。

www.microsoft.com

また、インストールした後になって、Windows OS 標準機能のリモートデスクトップWindows 10 Home では使えないことに気付きました。価格差が大きくないことを考えると、もしかすると Windows 10 Pro にしておくべきだったかもしれません。まぁ、今のところ特に困ってはいません。

2. Ubuntu をインストールする領域を空ける

新調した 1TB の SSDWindows 10 Home を新たにインストールしたので、そのほぼ全領域が C ドライブのためのパーティションに割り当てられました。Windows の「ディスクの管理」を使ってそのパーティションのサイズを半分近くまで縮小し、Ubuntu の基本パーティションのために領域を空けました。

空けた領域を「未割り当て」の状態にしたまま Ubuntu のインストール作業を終え、最終的にパーティション構成はこんな感じになりました。約 430GB のパーティションUbuntu が入っています。

Ubuntu をインストールした後はこうなる

Windows 上でこの空き領域を作る手続きをしてはいけないと書かれているブログも見かけましたが、今は特に問題が発生しなくなっているのかもしれません。

3. Ubuntu 20.04 LTS のインストール

Ubuntu は下記サイトからダウンロードします。

jp.ubuntu.com

インストール用の USB メモリを作るために、Rufus を利用しました。パーティション構成には GPT、ターゲットシステムには UEFI を指定します。

RufusUbuntu のインストールメディアを作成

Google Pixel 4 がデュアル SIM 端末になるとき

Google Pixel 4 は出荷時はシングル SIM 端末ですが、その後の UI 操作によってデュアル SIM 端末へ動的に変化します。Google Pixel 4 に IIJ さんの eSIM をダウンロードしてデュアル SIM 端末にしましたので、そのときに観測できたことをメモしておこうと思います。

f:id:cheerio-the-bear:20200613223945p:plain:w360f:id:cheerio-the-bear:20200613224033p:plain:w360
デュアル SIM 端末になる際のユーザー確認

1. シングル SIM 動作時の端末コンフィギュレーション

1-1. FEATURE

Google Pixel 4 が eSIM を取り扱う能力がある端末であることを示す FEATURE_TELEPHONY_EUICC は、最初から表示されています。

$ pm list features
...
feature:android.hardware.telephony
feature:android.hardware.telephony.carrierlock
feature:android.hardware.telephony.cdma
feature:android.hardware.telephony.euicc // これ
feature:android.hardware.telephony.gsm
feature:android.hardware.telephony.ims
...

その他の FEATURE 一覧はこちら。

cheerio-the-bear.hatenablog.com

1-1. コンフィギュレーション用リソース

Android フレームワークが持っているリソースを、幾つか読んでみました。

f:id:cheerio-the-bear:20200613221310p:plain
各リソースの値

config_telephonyEuiccDeviceCapabilities は概ね Google/AOSP にある下記の例の通りですが、contactlessSupportedRelease と rspCrlSupportedVersion の指定はありません。3GPP 系がリリース 11 になっているのは、どうしてでしょうか。

    <!-- An array of device capabilities defined by GSMA SGP.22 v2.0.
         The first item is the capability name that the device supports. The second item is the
         major version. The minor and revision versions are default to 0s.
         The device capabilities and their definition in the spec are:
             gsm : gsmSupportedRelease
             utran : utranSupportedRelease
             cdma1x : cdma2000onexSupportedRelease
             hrpd : cdma2000hrpdSupportedRelease
             ehrpd : cdma2000ehrpdSupportedRelease
             eutran : eutranSupportedRelease
             nfc : contactlessSupportedRelease
             crl : rspCrlSupportedVersion
    -->
    <string-array translatable="false" name="config_telephonyEuiccDeviceCapabilities">
        <item>"gsm,11"</item>
        <item>"utran,11"</item>
        <item>"cdma1x,1"</item>
        <item>"hrpd,3"</item>
        <item>"ehrpd,12"</item>
        <item>"eutran,11"</item>
    </string-array>

二番目の物理スロットが端末に実装されている eSIM なので、non_removable_euicc_slots の配列には 1 だけが設定されています。

    <!-- Device-specific array of SIM slot indexes which are are embedded eUICCs.
         e.g. If a device has two physical slots with indexes 0, 1, and slot 1 is an
         eUICC, then the value of this array should be:
             <integer-array name="non_removable_euicc_slots">
                 <item>1</item>
             </integer-array>
         If a device has three physical slots and slot 1 and 2 are eUICCs, then the value of
         this array should be:
             <integer-array name="non_removable_euicc_slots">
                <item>1</item>
                <item>2</item>
             </integer-array>
         This is used to differentiate between removable eUICCs and built in eUICCs, and should
         be set by OEMs for devices which use eUICCs. -->
    <integer-array name="non_removable_euicc_slots">
       <item>1</item>
    </integer-array>

この時点ではシングル SIM 端末ですが、Google Pixel 4 はデュアル SIM 端末になれる子です。config_num_physical_slots は 2 になっています。

    <!-- Number of physical SIM slots on the device. This includes both eSIM and pSIM slots, and
         is not necessarily the same as the number of phones/logical modems supported by the device.
         For example, a multi-sim device can have 2 phones/logical modems, but 3 physical slots,
         or a single SIM device can have 1 phones/logical modems, but 2 physical slots (one eSIM
         and one pSIM) -->
    <integer name="config_num_physical_slots">2</integer>
1-3. テレフォニー API が返す値

テレフォニー API が返す値が、複数の SIM を取り扱うこと能力があることを示していることがわかります。Google Pixel 4 がデュアル SIM 端末になるときに端末の再起動を求められるのは、doesSwitchMultiSimConfigTriggerReboot() が true を返しているからですね。

API 返値
doesSwitchMultiSimConfigTriggerReboot() true
getActiveModemCount() (Android Q にはまだない)
getSupportedModemCount() (Android Q にはまだない)
getMaxNumberOfSimultaneouslyActiveSims() (Android Q にはまだない)
getMultiSimConfiguration() UNKNOWN
getSimCount() 1
isMultiSimEnabled() false
isMultiSimSupported() 0 (MULTISIM_ALLOWED)
1-4. システムプロパティ

システムプロパティも確認してみましたが、シングル SIM 端末として動作している時点では "persist.radio.multisim.config" が見当たりません。

cheerio-the-bear.hatenablog.com

2. デュアル SIM 端末へ変更

2-1. 物理スロットの状態

物理スロットの状態を示す下記のログは、まだシングル SIM 端末として動作しているときにとった radio ログから抜き出したものです。物理スロット 2 にある eSIM だけがアクティブで、論理スロット 1 にマッピングされているようです。端末をアンロックしていないので、TelephonyManager.getLogicalToPhysicalSlotMapping() の返値は確認できていません。

D/RadioConfigResponse( 2047): [0009]< GET_SLOT_STATUS [
    IccSlotStatus {CARDSTATE_ABSENT,SLOTSTATE_INACTIVE,logicalSlotIndex=0,atr=,iccid=,eid=},
    IccSlotStatus {CARDSTATE_PRESENT,SLOTSTATE_ACTIVE,logicalSlotIndex=0,atr=3b9f96803fc6a28031e073f62157574a4d021060500002,
    ...
]

その状態から物理スロット 1 に SIM カードを装着すると、本投稿の冒頭に貼ったスクリーンショットのダイアログ群が表示されます。デュアル SIM 端末になること、それには再起動が必要なことに同意すると、端末の再起動の後にデュアル SIM 端末へと切り替わります。SWITCH_DUAL_SIM_CONFIG がそのために送信されるメッセージのようです。

D/PhoneCfgMgr( 2048): switchMultiSimConfig: with numOfSims = 2
D/PhoneCfgMgr( 2048): switchMultiSimConfig: sending the request for switching
D/RadioConfig( 2048): [0352]> SWITCH_DUAL_SIM_CONFIG, numOfLiveModems = 2

デュアル SIM 端末になったところで、物理スロットの状態をもう一度見てみましょう。両方の物理スロットがアクティブになり、また物理・論理スロットのマッピングもストレートになっていることがわかります。

D/RadioConfigResponse( 2103): [0017]< GET_SLOT_STATUS [
    IccSlotStatus {CARDSTATE_PRESENT,SLOTSTATE_ACTIVE,logicalSlotIndex=0,atr=3b9f96c00a1fc68031e073fe211f65d00233131b810ffa,iccid=898109001[****],eid=},
    IccSlotStatus {CARDSTATE_PRESENT,SLOTSTATE_ACTIVE,logicalSlotIndex=1,atr=3b9f96803fc6a28031e073f62157574a4d021060500002,iccid=898103039[****],
    ...
]
2-2. テレフォニー API が返す値

getMultiSimConfiguration() と getSimCount()、isMultiSimEnabled() の返値が変わり、デュアル SIM 端末っぽくなっています。

API 返値
doesSwitchMultiSimConfigTriggerReboot() true
getActiveModemCount() (Android Q にはまだない)
getSupportedModemCount() (Android Q にはまだない)
getMaxNumberOfSimultaneouslyActiveSims() (Android Q にはまだない)
getMultiSimConfiguration() DSDS
getSimCount() 2
isMultiSimEnabled() true
isMultiSimSupported() 0 (MULTISIM_ALLOWED)
2-3. システムプロパティ

元々は存在しなかったプロパティ、"persist.radio.multisim.config" が動的に追加されているのがわかります。

...
[persist.mm.enable.prefetch]: [true]
[persist.radio.multisim.config]: [dsds]  // これ
[persist.rcs.supported]: [1]
...