僕の考えた最強のspモード

このエントリの見方

長いので手早く読みたい方は、前置きとリンクしている高木さんのエントリを確認し、結論とまとめに飛び、シーケンス図を確認し、補足とおまけを後回しにしながら必要な所だけ順番に見るといいかもしれません。時間と根気がある方は順番にどうぞ。
(追記:もしかしたらSMS使わずともC2DMまたはGCMで横取りの心配もなく実装出来るかもしれない…? 後日検証予定。即時性については未確認なのでどこまで使えるか分かりませんが…。)

ドコモが理想とするspモードと、根深い問題を抱えた現実(前置き)

昨年12月、spモードメールで大規模な障害が発生しました。障害の原因の一つに「IPアドレスで電話機を識別していた」というものがありました。それを見た多くの技術者は「その実装は無いわー」と思ったのですが、高木浩光さんの考証によるとなかなか根深い理由があった様です。
http://takagi-hiromitsu.jp/diary/20111229.html#p01
要は「ドコモはi-modeの様に、ID・パスワードが存在しないネットワークを再現したい」という大前提があるという事です。でもそれは決して簡単な話ではなく、高木さんも「そもそもspモードは安全に成り立つのか」の解を「spモードが目指すところはそもそも技術論的に無理があるのではないか」と結論付けられてます。


まあ今後は「普通のPOP3S/SMTPSのメールシステムにして、IDとパスワードを入力させる形式にする」か「MMSに対応する」方が素直なやり方なんでしょうね。通常のISPが接続ID・接続パスワード・メールID・メールパスワードを発行する運用を続けてきましたし、ケータイユーザーも甘やかされず自立出来る可能性は十分あると思います。
『通話と電話番号あてのメールさえ送れれば良いSMSで十分なユーザー』『IDとパスワードから開放されてるガラケーi-mode』『PCライクにIDとパスワード管理をするスマートフォン』。そういうカタチで住み分けも出来そうに思えます。


しかしその難題である「ドコモの理想とするspモード」は何とか実現する方法がないか、私はあえて考えてみることにしました。こちらは責任者でもないただの部外者ですし、のんびりじっくりと実装を考える事が出来ます。納期もノルマも課せられてないので、マイペースで3ヶ月程考えてみました。

仕様確認と「SMS利用」という思いつき、そして挫折

必要な仕様は次の通りです。とりあえず1番目を最重要に考えて考えてみましょう。

  • 要件1:「ID・パスワードが存在しない」spモードメール+dmenuを実現する。
  • 要件2:テザリングした端末からはspモードメール+dmenuにアクセス出来ない様にする。*1
  • 要件3:悪意のあるアプリからはspモードメール+dmenuにアクセス出来ない様にする。
  • 要件4:既存端末もケータイアップデートと公式アプリ入れ替えで対応できるようにする。
  • 要件5:もちろんIPアドレスで電話機を識別しない


2〜3日かけて思いついた第一案が「SMSを使おう」でした。SIMの中のデータとアンテナ局側が良く分からない不思議な動きをして、契約者を確認し、通話やSMSが出来るようサービスを提供しています。ここで行われてるのは間違いなく「認証」処理です。別のSIMを刺した電話機にSMSを誤送したり、契約者に間違った電話番号を割り当てたりはされていません。
「だったらそのしっかりした認証周りを、spモードの認証に利用しちゃえばいいよね?」と考えたわけですね。そうして順序だてたのが次の流れになります。


spモードメール

  1. spモードメールアプリがhttpsで認証サーバーにリクエストを送る。パラメーターは「電話番号」で、同時にspモードメールアプリは「セッションID」を記憶する。とりあえずブラウザクッキーに使われるセッションIDをそのまま使う。
  2. 認証サーバーはPOP3S/SMTPS用のID・パスワードの前半部分を乱数で生成*2。同時にメールサーバーも生成したアカウント情報に更新する。
  3. この時のパスワードには「生成したパスワード用乱数」と「セッションID」を連結したモノを使う。
  4. SMSにてIDと、パスワードの「乱数」部分のみ電話機に送る。
  5. spモードメールアプリは受け取ったID、パスワードの「乱数」部分と、アプリ上で記憶している「セッションID」を使ってメールサーバーにアクセス。
  6. POP3S/SMTPSに成功。

dmenuも大体同じ流れです。とりあえず話を進める為にここでは省略します。


で、このロジックの検証をしてみたのですが、要件1と要件2*3は何とか満たせそうなのですが、要件3が満たせません。
何故なら「公式アプリ以外でセッションIDを生成or取得できなくする」のが普通のhttpsである以上不可能だからです。そうなると「SMS受信(or読み取り)権限」と「完全なインターネットアクセス」の権限があるアプリであれば、公式アプリと同じ挙動をするだけでspモードメール+dmenuへ自由にアクセス出来てしまいます。


……不味いですね。SMSの秘密情報を死守しないと悪意あるアプリにフルボッコ確定です。そんな訳でこの案はあっさり打ち砕かれました。これが昨年の話。*4
そして今年に入って、ふと気づいたのです。「いつからOSに手を入れてはいけないと錯覚していた?」という事実に。

SMSを独占しちゃえ! …という事で勉強開始

前項で分かった事は、単にSMSを使うだけでは悪意あるアプリのカモである事。そしてSMSを隠蔽する方法があれば、SMSを認証に使える可能性があるかもしれないという事です。そして金と時間と努力と兵隊があれば、Android OS自体を改造するという方法も一応存在するという事も思い出しました。もちろんOS内部まで大幅修正しちゃうのは副作用が大きいですし、一応候補として残しますが最終手段としておきましょう。


そうして真面目にAndroidアプリの勉強を始めたのがつい最近。タオ本だって購入しました。

Android Security  安全なアプリケーションを作成するために

Android Security  安全なアプリケーションを作成するために

という事でチマチマ勉強してSMS受信の流れを調べていきました。どうやら次の様な流れになっているようです。

AndroidにおけるSMS受信の流れ

システムがSMSを受信する



システムから"android.provider.Telephony.SMS_RECEIVED"というブロードキャスト*5を送信(sendOrderedBroadcast)。SMSの内容はintentのextra内の"pdu"という項目に格納。



権限"android.permission.RECEIVE_SMS"の使用を許可されたアプリへ、先程のブロードキャストを受け取る設定をしたBroadcastReceiverに"順次"ブロードキャストが届く。これはブロードキャスト送信にsendOrderedBroadcastを使っているから。



SMSを受信箱に格納するのは、↑のブロードキャストを受け取った側のお仕事。標準のOS構成では"com.android.mms"パッケージが担当。
権限"android.permission.READ_SMS"と"android.permission.WRITE_SMS"は"content://sms/inbox"への読み書きに対する権限。権限READ_SMSには前述のブロードキャストの中身を見る事が出来ない。
担当者不在なら"content://sms/inbox"は使われない。IS01等は標準の"content://sms/inbox"に保存せず、独自領域に保存している模様。



受け取り手がシステムに無かったり、受け取るけど誰も"content://sms/inbox"に保存するモノがいない場合、結局権限"android.permission.READ_SMS"を許可されたアプリにはSMSの受信内容は見れない。

この流れを整理してみると、いくつかSMS隠蔽のチャンスが見受けられます。


もしSMSを他アプリから隠すとするなら

  1. sendOrderedBroadcastを送る直前で隠す。(OSの改造が必須)
  2. ブロードキャストを最初に受け取って、秘密の情報は他のBroadcastReceiverに流さない。(そういう隠蔽用アプリを用意する)

の2パターンが考えられそうです。

補足:AndroidにおけるSMS受信の流れに関連する権限の動作(読み飛ばし可)

また関連する権限"android.permission.BROADCAST_SMS"については以下のような制御が行われている事を確認しました。

(1)送り側のパターンその1
uses-permission:"android.permission.BROADCAST_SMS"
sendOrderdBroadcastで"android.provider.Telephony.SMS_RECEIVED"する。


(2)送り側のパターンその2
sendOrderdBroadcastで"android.provider.Telephony.SMS_RECEIVED"する。


(3)受け手側のパターンその1
uses-permission:"android.permission.RECEIVE_SMS"
ブロードキャストで"android.provider.Telephony.SMS_RECEIVED"を受け取るreceiver


(4)受け手側のパターンその2
uses-permission:"android.permission.RECEIVE_SMS"
ブロードキャストで"android.provider.Telephony.SMS_RECEIVED"を受け取り、かつpermissionに"android.permission.BROADCAST_SMS"が指定されてるreceiver


各組み合わせでの送受信成否

  • (1)→(3)ok
  • (1)→(4)ok
  • (2)→(3)bad(Permission Denial)
  • (2)→(4)ok

先日再確認したら全然違った…。TAO本確認しても現在の自分の認識と比較しても、上記組み合わせは何かおかしい。訂正記事書く時間はまだ無いので、とりあえず間違ってるという事だけメモしておきます。。


(1)は"android.permission.BROADCAST_SMS"がOS(android)で定義されてるpermissionで、protectionlevelが"signature"。よってOSをビルドしたのと同じ証明書で署名される必要があり、実質的にプリインストールアプリしか使えない。
(4)の"android.permission.BROADCAST_SMS"指定は、あくまで「"android.permission.BROADCAST_SMS"権限を持ってる人のだけ受け取るよ!」という意味であり、OSと同じ署名は必要ない。


そして(1)(2)からブロードキャストを受け取った(3)(4)のアプリは、receiverのpermission指定に関係無くにabortBroadcastが出来る。
あくまでsendOrderdBroadcastとBroadcastReceiverの経路の正当性確保の為だけにpermissionが使われているみたい。

ブロードキャストの仕組みを研究

BroadcastReceiverは、abortBroadcast()で他のBroadcastReceiverへブロードキャストを伝達させない事が出来ます。n番目のBroadcastReceiverがabortBroadcast()すると、n+1番目以降のBroadcastReceiverにはブロードキャストが伝わらないという事です。10秒ルールが守られている場合に限ります *6 けども。またReceiverの登録時にIntentFilterへpriorityを指定する事が出来、そこに他アプリが登録していない大きな数値を指定すると優先してブロードキャストを受け取る事ができます。最大値はInteger.MAX_VALUEです。


ただし同じpriorityのReceiverがある場合は動作が保証されてません。一応登録順に流れるような挙動はしていますが、順番を死守したいなら同値かそれ以上のpriorityのReceiverが他に無いかチェックする必要があるでしょう。これはPackageManger.queryBroadcastReceiver()でチェックが可能です。またチェック後のタイミングでアプリを追加されては意味が無いので、パッケージの追加も"android.intent.action.PACKAGE_ADDED"等を受け取ってチェックする仕組みが必須ですね。


他にも動的にReceiverを登録する方法も存在するので、その点も注意する必要がありそうです。万全を期すならば、"android.permission.RECEIVE_SMS"を利用しているあるアプリをホワイトリスト方式でチェックし、該当アプリを削除(ICS以降なら停止?)する事になるかと思われます。


以上を踏まえて「SMS隠蔽アプリ」の仕様を考えてみましょう。
SMSを最優先で受け取ったReceiverには、秘密情報を保管した上でabortBroadcast()してもらいます。秘密情報を保管したSMSかどうかは、送り主の電話番号と内容のチェックで行う形になるでしょうね。秘密情報はドコモ共通のContentProviderに格納します。ここにはアクセス用permissionを定義し、protectionLevelはsignatureOrSystemとします。もちろんドコモ謹製アプリは署名を統一させる必要があります。


※もしAndroidのシステムが、複数送り元からのSMSを同一のブロードキャストで流す仕様だった場合はabortBroadcastの後、再度フィルタリング結果をブロードキャストする必要があります。また10秒ルールに抵触しないよう安全寄りに作る場合も即abortBraoadcastしてからサービス利用で再ブロードキャストする作りにしないといけません。またそれらの「再ブロードキャストが必要な場合」では、SMS隠蔽アプリにAndroidをビルドしたのと同じ証明書で署名する必要があります。これは前項の補足で出てきた権限が、パッケージ"android"と同一signatureしか使えないからです。

処理の流れをシーケンス図にしてみた

多分どこか書き方間違えてます。UMLとツールの使い方が分かっていませんので。処理順序の参考程度にしてご覧ください。

流れとしては上記の通りですが、一部のアクセスを適切に制御する為の設定も必要です。各アプリパッケージの署名やパーミッション設定は、次のような指定が必要になります。

  • 「spモードメールアプリ」…ドコモの証明書で署名する。
  • 「SMS隠蔽アプリ」…BroadCastReceiver。OSと同じの証明書で署名する(ブロードキャスト再送が必要な場合)か、ドコモの証明書で署名する(10秒ルールの心配が無くてabortBroadCastで本当に十分な場合)。
  • 「秘密情報倉庫」…ContentProvider。ドコモの証明書で署名する。アクセス用PermisionのprotectlevelをsignatureOrSystemに。

悪意あるアプリはどうなる?

上記のシーケンスとパーミッション設定等で、悪意あるアプリがどうなるかまとめてみます。

  • 悪意あるアプリはSMS受信時のブロードキャスト(シーケンス図の3.6.1.1)をSMS隠蔽アプリより先に受け取れない。(※受けれる可能性のある環境では認証処理を開始しないようチェックする仕様です)
  • 悪意あるアプリは秘密情報倉庫にアクセス出来ない。


この前提により「spモードメールのapkを解析して同じ振る舞いをする」ような悪意あるアプリを作れたとしても、ドコモがアプリ署名に使っている証明書が流出しない限りは権限チェックで不正アクセスを排除できます。


あと悪意あるアプリとはやや違う話ですが、

  • もし仮にSMSを傍受する方法があっても、spモードメールアプリが受け取ってるセッションIDも揃わないと完全なパスワードは分からない。

という事にもなります。

補足:各アプリのJavaソース抜粋(読み飛ばし可)

全然エレガントじゃないけどご容赦ください。何せ私は「ArrayListのtoArray()呼ぶ時、引数無しで呼んでキャストに失敗する」くらいのヘッポコレベルですので…。
「SMS隠蔽アプリ」 ※きっちり作る時は処理をサービスに移動すべき(10秒ルールの危険がある)。

package com.example.docomo.yokodorisms;
/* 省略 */
public class SmsYokodoriReceiver extends BroadcastReceiver {
    private static final String TRUE_STRING = "true";
    private static final String BUNDLE_SKIP = "com.example.docomo.SmsYokodoriReceiver.skip";

    @Override
    public void onReceive(Context context, Intent intent) {
        Bundle bundle = intent.getExtras();
        
        if ((String)bundle.get(BUNDLE_SKIP) != null) {
            if (((String)bundle.get(BUNDLE_SKIP)).equals(TRUE_STRING)) {
                return; //検閲済み
            }
        }
        
        //ここから下は10秒ルールに抵触すると危険なので、さっさとabortBroadcastしサービスに再ブロードキャストしてもらうのが正しい作り、かも…?
        
        Object messages[] = (Object[]) bundle.get("pdus");
        ArrayList<byte[]> arrayList = new ArrayList<byte[]>();
        for (int n = 0; n < messages.length; n++) {
            SmsMessage hoge = SmsMessage.createFromPdu((byte[])messages[n]);
            if (hoge.getOriginatingAddress().equals("110")) { //←秘密のSMSは警察から届く…というサンプル
                //秘密のSMSは、ドコモ公式アプリ限定使用のContentProvidorへ保存(アクセス用パーミッションはsignatureOrSystemに設定)
                ContentValues values = new ContentValues();
                values.put("OriginatingAddress", hoge.getOriginatingAddress());
                values.put("MessageBody", hoge.getMessageBody());
                Uri uri = Uri.parse("content://com.example.docomo.secret.secretprovider");
                context.getContentResolver().insert(uri, values);
            } else {
                arrayList.add((byte[])messages[n]);
            }
        }
        if (true || (arrayList.size() != messages.length)){
            abortBroadcast(); //一旦abort
            if ((0 < arrayList.size())) {
                //秘密データを除いたSMSを再度ブロードキャスト送信
                Intent newIntent = new Intent("android.provider.Telephony.SMS_RECEIVED");
                newIntent.putExtra("pdus", (byte[][]) arrayList.toArray(new byte[0][0]));
                newIntent.putExtra("format", (String) intent.getExtras().get("format"));
                newIntent.putExtra(BUNDLE_SKIP, (String) TRUE_STRING);
                context.sendOrderedBroadcast(newIntent, "android.permission.RECEIVE_SMS");
            }

            //TODO:spモードアプリにも何らかの手段で通知ー。
        }
    }

}

「spモードメールアプリ」における他のBroadcastReceiverのPriorityチェック

/* 省略 */
public class SpMailerActivity extends Activity {
/* 省略 */
    private boolean checkBroadcastPriority() {
        PackageManager pm = getPackageManager();
        Intent intent = new Intent("android.provider.Telephony.SMS_RECEIVED");
        List<ResolveInfo> apps = pm.queryBroadcastReceivers(intent, 0);
        
        for (int i = 0; i < apps.size(); i++) {
            ResolveInfo info = apps.get(i);
            if (info.priority == Integer.MAX_VALUE) {
                if (info.activityInfo.packageName
                        .equals("com.example.docomo.yokodorisms")
                        && info.activityInfo.name
                                .equals("com.example.docomo.yokodorisms.SmsYokodoriReceiver")) {
                } else {
                    // ドコモの謹製アプリ以外が、同priorityで存在しては困る
                    new AlertDialog.Builder(this)
                            .setTitle("zannnendattane!")
                            .setMessage("You can't use spmode. Please uninstall \"" + info.activityInfo.packageName + "\".")
                            .setPositiveButton("Exit", new OnClickListener() {
                                
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    finish();
                                }
                            })
                            .show();
                    return false;
                }
            }
        }
        return true;
    }
}

その他実装すべきコードはありますが、とりあえずSMS隠蔽に関する部分だけ載せておきます。

おまけ:OSを改造するパターン(読み飛ばし可)

仮にSMSを最優先取得&隠蔽の方式が使えない場合、AndroidのOS部分に手を入れるくらいしか方法がありません。
/base/core/java/android/provider/Telephony.java
辺りに手を入れて頑張れば良いのではないでしょうか。


どのSMSを隠蔽するか、隠蔽するSMSの保存先(ContentProvidor)は何処か、その辺のルール記述を出来るようにしておき、必要のない他キャリアは設定画面を無効にすれば影響出ないとか様に思われます。そうすれば新たなシステムpermissoinの定義等をせずとも実装出来そうです。
端末もケータイアップデート時にルール設定ファイルを配信すれば大丈夫そうです。勿論spモードユーザーにルールを手動設定させるのも可能ですが、IDとパスワードを無くす為にそんな行為を押し付けては本末転倒になってしまいますね…。
もちろんそれらはAndroid OSへ反映されず、ドコモローカル使用のパッチとして運用される運命かもしれませんけども。

SMSが隠蔽された事で要件仕様は満たせるか?

長々と書きましたが、前述のロジックで要件はどこまで満たせたでしょうか?

  • 要件1:OK
  • 要件2:OK
  • 要件3:OK(※動的に登録されたBroadcastReceiverの対策もしっかり想定していれば)
  • 要件4:OK
  • 要件5:OK

何とか大丈夫そうですね。


ただしrootを取った端末で、かつ悪意のあるアプリにroot権限を与えていた場合はうまく処理出来ないでしょう。ただその点については「自己責任で権限を切り替えて使ってもらう」以外の答えは無いと思われます。そもそも権限を適切に使いこなせないような方まで端末をroot化するのは好ましくありません。


また別途入手したカスタムROMを適用した場合、必要なアプリが足りてないのでspモードの利用は出来なくなります。対策としてはspモード/dmenuの「ID・パスワード手動設定版アプリ」を作ってしまうというくらいですが、わざわざドコモさんが用意してくれる可能性は少ないでしょうね。

懸念事項

いくつか懸念材料はあります。

海外に移動した場合、SMSの送信元番号はどうなるの?
→ドコモが送信元に使う電話番号が海外で一般的な番号だったら、他のSMS受信アプリが困る。海外出発時に工夫が要りそう。
海外に移動した場合、そもそもドコモサーバーからのSMSは電話機に届くの?
→前項と同じく厄介そうですね。下手したらドコモがローミング先業者に大金を払う事になるかもしれません。やはりSMS使った認証方法は、国内にいる時だけに限定すべきかもしれません。
2in1サービスに対応出来るの?
→2in1についてはドコモ自身に考えて頂きたいです。使用電話番号の切り替えをspモードアプリが認識出来る*7のなら、アカウント情報払い出しを2番号分やるだけで大丈夫だと思います。
ブロードキャスト割り込み方式の場合、動的ブロードキャストの対応は大丈夫?
→はっきりとは分かりません。登録と解除をランダムに繰り返されると、タイミング次第でqueryBroadcastReceiverに出ないかもしれません。完全に対策するには前述の通りRECEIVE_SMSなアプリ登録を一時的にでも削除してもらうしかなさそうです。

補足:なりすましで任意の電話番号宛にSMSを送られる事の対策(読み飛ばし可)

前述の仕様では、電話番号さえhttps経由で投げれば該当する電話番号へSMSが無料で送れてしまう形になってます。これは対策をしておかないと問題がありますね。SMS自体はSMS隠蔽アプリが隠すので画面上の表示は無い筈ですが、バンバン送られて来たら電池をいたずらに消耗させられるでしょう。

id:tamago@09012345678;pass:yakitoridaisuki;

仮に認証用SMSの仕様が、IDとパスワードのみの↑のような内容だったなら、そこにいたずら防止用の「ロック用コード」を追加します。

id:tamago@09012345678;pass:yakitoridaisuki;reject:urusaidamare;

身に覚えの無い設定用SMSを受け取った端末は、電話番号とロック用コードをユーザー管理サーバーへ送信し、アカウント仮登録処理を当分受け付けないように設定します。いわゆるアカウントロック的な動作ですね。
この時、ロックに成功したら「ロック解除用コード」をユーザー認証サーバーは返しておきましょう。何らかの理由で再設定が必要になった場合、ロック解除用コードを送るか、しばらく時間を置いて自然にロックが解除されるのを待つ仕様にする為です。
勿論他社宛SMS送信の踏み台にされないように、ドコモかつspモード契約者の電話番号相手にしかSMSを送信しないチェック処理を入れる必要もありますね。あとはお決まりの接続元IP制限(ドコモ網から以外受け付けない)もセットにすれば、いたずらの対処は比較的簡単では無いかと思われます。

結論とまとめ

  • ID・パスワードを使用しないで最初から使えるSMSというものがある。
  • 一応Android上でSMSを独占・隠蔽する方法がある。(iOSは不明)
  • ロジックと処理順序とAndroidManifest.xmlの定義とapk署名と証明書の管理を間違えなければ、spモード用アカウント情報をユーザーに意識させず払い出し可能。


という訳で、ドコモが考える「理想のspモード」とやらは、IPアドレスで管理しなくても実現可能みたいです。
途中のシーケンス図とかで出てきたように、端末のspモードメールアカウントが未設定の時とSIMの差し替えがあった時だけ認証処理する形が良さそうですね。その方がユーザー管理サーバーの処理負荷も低く出来ますし。ウィルコムのオンラインサインアップみたいな感覚でしょうか。dmenuも初回起動時でID・パスワードを払い出し、特定の処理時のみ再認証させる程度で何とかなる気がします。
これで「IPアドレスの管理が負荷増大で耐えれなかった!」→「シャッフルシャッフル!」という心配もなくなりますし、「負荷に耐えれるよう大金出してサーバーリソース増強します」という対策もあまり要らなくなるかと予想されます。


ちなみに実際にこの方法で運用する場合、真っ先にケータイアップデートで「秘密情報倉庫」と「SMS隠蔽アプリ」を含めたシステムに入れ替える必要があります。ユーザーが手動でアプリDL&追加の形では、権限定義に問題が発生する恐れがあるようですし*8、ドコモキャリア用スマホのOSビルド用証明書はおそらく各ベンダ毎に別々のものが使われている可能性がある為「SMS隠蔽アプリ」をマーケット公開するのは多分無理だと思われますから。

*1:現在でもAPNの切り替えでdmenuはアクセス不可にしてるみたいですけどね。spモードメールはうろ覚えです。まあ「APNそのままでも大丈夫」な仕様を考えてみましょう。

*2:乱数なのはパスワードだけで十分かも?

*3:テザリング端末からSMSを見れるようなお漏らしアプリがあれば別ですが。

*4:ついでに言うとメールサーバーのアカウント情報更新もSMSやり取り後にしないと、悪戯でspメールアカウントにログイン妨害させられてしまいます。まあこれは後ほどのシーケンス図にあるようにタイミングずらして「SMS受けたから更新初めて〜」「把握した」ってやり取り入れれば解決しますけど。

*5:OS上で全アプリに投げられる通信のようなもの。

*6:n番目のBroadcastReceiverが処理に10秒以上の時間がかかっている場合、痺れを切らしたシステムが"n番目強制終了する?"と確認ダイアログを出しつつn+1番目以降にブロードキャストを伝えてしまいます。

*7:B番号を手入力してもらうでもいいなら、B番号宛のSMSを受信さえ出来れば十分ですね。

*8:参考: https://subtech.g.hatena.ne.jp/cho45/20100205/1265367008 可能なら全AndroidManifest.xmlを調べて定義宣言の重複と署名チェックの処理を用意すべきかもしれませんね。