VPN の承認ボタンをタップしても、ダイアログが反応しない。当然の結論はアプリかサーバーが壊れているというものなので、人はパスワードを再設定し、DNS を変え、クライアントを再インストールする。しかし通常、そのどれも原因に触れていない。Android は障害物を通って届いたタップを破棄する仕様であり、VPN の承認画面はまさにそうした機微な同意ダイアログだからだ。タップがボタンに届くことはない。

保護が実際に拒否しているもの

Android は、別のウィンドウがダイアログの上に重なりタップを盗んだり曖昧にしたりするタップジャッキングから、機微な操作を守る。ビューは View.setFilterTouchesWhenObscured で参加し、別のウィンドウが部分的または全的に覆っていると印を付けられると、イベントは MotionEvent.FLAG_WINDOW_IS_OBSCURED を伴って届く。その場合イベントは誤った場所に渡されるのではなく破棄される。Android 12 (API 31) は、システムの同意画面で信頼できないタッチを遮断することで同じ保護を拡張した。だから承認ダイアログは、他のアプリならまだ受け付けるオーバーレイからのタップを拒否できる。

障害物を日常的に生むのは三つ。他のアプリの上に表示する権限を持つアプリ、コンテンツを描画するアクセシビリティサービス、画面録画やフィルター系ツールのフローティングウィジェットだ。ベンダーの表示機能が独自のレイヤーを足すこともあり、同じ Android 版の二台でも同じダイアログの挙動が変わる。部分的に覆うウィンドウは FLAG_WINDOW_IS_PARTIALLY_OBSCURED を設定し、タッチはボタンが見る前に破棄される。これは画面の性質であり、ネットワークの性質ではない。タップが破棄された時点で VPN サーバーには何も送られていないので、サーバー側の変更が結果を左右することはない。

死んだタップと失敗した接続を切り分ける

この区別が診断のすべてで、十秒で終わる。タップが無視されダイアログが元のままなら、障害はローカルだ。ダイアログが閉じてその後エラーが出るなら、同意は受理されており、アプリ自身のイベント情報が必要な別の段階に進んでいる。

ローカルだという読みは、要求したアプリが接続を試みたかどうかを確認することで裏付けられる。同意ダイアログが表示されている間にハンドシェイクの試行を一度も記録しないクライアントは、ネットワークに達していない。

adb shell cmd appops get com.example.vpn SYSTEM_ALERT_WINDOW
adb shell settings get secure enabled_accessibility_services

オーバーレイ権限を持つアプリと有効なアクセシビリティサービスを列挙し、稼働中のものと突き合わせる。プラットフォームの保護自体を切らないこと。隠れたウィンドウがあなたの代わりに同意ダイアログへ答えるのを防いでいるのは、その保護だ。

障害物を取り除き、通常の流れをやり直す

まずどのアプリが VPN の承認を求めたのかを特定し、どの同意を与えるのかを知る。次に、後で必要になるかもしれない広い権限を取り上げるのではなく、その特定のオーバーレイをそれ自身の設定で止める。画面フィルターは自アプリにトグルがあり、フローティングウィジェットには閉じる操作があり、ベンダーの表示モードには表示設定の中にスイッチがある。

その後 VPN アプリに戻り、承認を再び要求してダイアログを新しく作らせる。タップが通るようになったら、オーバーレイの互換動作を調整するか接続中は切っておき、タッチ保護は有効のままにする。

どのウィンドウが原因か分からない場合は、一つずつ外し、変更のたびに同意ダイアログを試す。録画の操作バーやフローティングのショートカットが常連で、うまくいった直前に外したものが答えだ。

途中で切った無関係なものは元に戻す。画面フィルターや夜間モードは敵ではない。ダイアログに重なる特定のウィンドウが敵だ。

ダイアログを通すためにやってはいけないこと

ボタンを押させるために未知のアプリへアクセシビリティを与えたり、そのための補助アプリを入れたりしない。それは、VPN を許可する画面で、保護が拒むために存在する能力をそのまま渡すことになる。

入力ツールでダイアログを自動化するのも避ける。悪意あるオーバーレイと同じ結果になり、原因について何も教えてくれない。

管理対象端末では、VPN の変更を制限するポリシーは管理者の判断だ。オーバーレイの実験はそれを回避する許可ではない。同様に、反応しない同意ボタンは証明書検証を弱めたりアカウント情報を変えたりする理由にならない。どちらの設定もローカルのタッチ障害を取り除かない。

それでも失敗するなら、正確な挙動を報告する

結論ではなくダイアログを描写する。どのアプリが承認を求めたか、ダイアログが開いたままか閉じたか、未知のソースやアクセシビリティの警告など他の機微な確認もタップを無視するか、端末の型と Android 版、そして取得したオーバーレイとアクセシビリティの一覧。

その場でサポート担当にもう一つ尋ねる。端末ポリシーが VPN 設定の変更を制限しているかどうか。管理されたブロックは無視されたタップとは見え方が違い、どちらを見ているか分かれば往復が一度減る。

この組み合わせは、覆われたタッチの問題を、壊れた入力機器、固まったダイアログ、ポリシーによるブロックから切り分ける。次に担当する人が画面を見るべきかネットワークを見るべきかも伝える。

Android のタップジャッキング指針は、覆われたウィンドウの条件とこの挙動の背後の API を扱っている。証拠をたどるなら、ボタンに届かなかったイベントで FLAG_WINDOW_IS_OBSCURED と FLAG_WINDOW_IS_PARTIALLY_OBSCURED を探す。開いたままのダイアログこそ記録すべきもので、タップが別のウィンドウに渡らずに留められたことを示す。

関連記事