Android 4.3: NotificationListenerServiceマニアックスとAndroidセキュリティ観測

Android 4.3では、NotificationListnerService という、アプリが、他のアプリも含めて通知バーに追加された通知の情報を取得することが出来るという機能が追加されています。

このNotificationListnerServiceとリフレクションを用いたサンプルアプリをgithub上に公開しております

本記事では、NotificationListenerServiceとはどういうものか、基本的な使い方と踏み込んだ使い方、そしてNotificationListenerServiceを含めたAndroidのセキュリティについての考え方の方針転換の可能性についてを書きたいと思います。

NotificationListenerServiceとは?(基本的な使い方)

4.2以前のAndroidでは、自分のアプリの通知を通知バーに登録することは出来ました。4.3では、他のアプリが通知を行ったことを知り、それをトリガにして処理を実行することが出来るようになりました。 ((裏ワザ的なAccessibilityService使用によって、同様のことは出来たりはしますが))

ユーザは以下のように NotificationListnerService の派生クラスを作り、

public class MyListenerService extends NotificationListenerService {

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        /* 通知が追加された時に呼ばれる */
    }

    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        /* 通知が通知バーから削除された時に呼ばれる */
    }
}

AndroidManifest.xml にその派生クラスがNotificationListnerServiceの権限でのアクセスのみを受け付けることを宣言します。

    <service
        android:name=".MyListenerService"
        android:label="@string/app_name"
        android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
        <intent-filter>
            <action android:name="android.service.notification.NotificationListenerService" />
        </intent-filter>
    </service>

これによって、MyListenerSeriviceはBIND_NOTIFICATION_LISTENER_SERVICE のpermissionを持つものからの要求のみを受け付けるようになります。
BIND_NOTIFICATION_LISTNER_SERVICE は一般ユーザが使用することが出来ないprotectionLevelを持っているため、このサービスの機能を呼び出すことが出来るのはAndroid 4.3のシステムに組み込まれて適切な権限を持っているものからのみとなります。

前述のpermission宣言により、アプリ自身からもこのサービスを起動することは出来ませんが、[設定]->[セキュリティ]->[通知へのアクセス]の設定に従って自動的にシステムにより起動されます。以下はセキュリティ設定画面のキャプチャです。

security-setting

「通知へのアクセス」という項目は、実際にNotificationListnerServiceを用いたアプリを手順に従って端末にインストールするまではあらわれません。
最初、アプリをインストールしただけでは、そのアプリの使用許可は与えられていない状態です(下図参照)。

setting-notificationlistener01

チェックボックスをオンにすることでインストールされたアプリを有効化することが出来ますが、その時に非常に刺激的な警告文が表示されます。

setting-notificationservice02

非常にいろんなことが出来るので、信頼出来るアプリにしか許可を与えてはいけないという警告文です。この警告を受けた上でOKボタンを押すと、チェックボックスが有効になり、インストールしたアプリのNotificationListnerServiceを派生したサービスが起動します。逆にチェックボックスを外すと、サービスは停止します。

このようにして、システムから起動されたサービスは新しい通知が通知バーに登録される度にonNotificationPosted()が呼び出され、通知が削除される度にonNotificationRemoved()が呼び出されますので、それらをトリガとして処理を行うことが可能となります。

NotificationListnerServiceの踏み込んだ使い方

NotificationListenerService#onNotificationPosted()の引数として渡されるStatusBarNotificationからは、通知元のパッケージ名や通知が作成された時間、Linux UID、Notificationクラスのインスタンスなどを取得することが出来ます。しかしそれらの情報を用いてできることはそんなにたいしたことではありません。先ほど、機能を有効にする際にダイアログで警告されたようなことはほとんど出来ません。

しかしあれは単なる脅しではありません。Androidでは非公開のAPIもリフレクションを用いて呼び出すことができます。リフレクションによって先のダイアログにて警告されたような機能を実現することは可能です(本記事では述べません)。

以下のサンプルコードは、StatusBarNotificationのインスタンスからメールが到着した時にそのGmailを表示するためにPendingIntentを取得し、そのPendingIntentに紐付けられたIntentを送る方法を示します。

public class MyListenerService extends NotificationListenerService {
    private static final String TARGET_APP_PACKAGE = "com.google.android.gm"; // Gmail Application

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
    // return if the notification isn't from the target
    if (!TARGET_APP_PACKAGE.equals(sbn.getPackageName())) {
        return;
    }

    Notification notification = sbn.getNotification();

    Intent intent = new Intent();
    PendingIntent pendingIntent = notification.contentIntent;
    try {
        pendingIntent.send(this, 0, intent);
    } catch (PendingIntent.CanceledException e) {
        e.printStackTrace();
    }
}

実際に動作するサンプルコード全体は github で公開しておりますので、そちらをご参照ください。

NotificationListenerService のセキュリティ

従来のpermissionモデルであれば、ユーザがアプリをインストールした時点で、そのアプリが宣言していた機能をすべて使用させることになりますが、NotificationListenerServiceはその方法で通知バーの情報を保護しません。

通知バーにアクセスをする機能を持ったアプリをユーザがインストールし、なおかつ、ユーザが明示的に通知バーへのアクセスを許可するように設定を変更することを求めます。そして、その設定変更時には非常に強い警告を表示することで、ユーザが安易に設定を変更しないことを求めています。

このようにして、アプリのインストール後にユーザがアプリに対して機能の利用をON/OFFするというのは、弊社ブログでも紹介したAppOpsでも行われています。これは、Androidのセキュリティについての考え方が変化してきている兆候だろうと弊社では考えています。

騙してインストールさせて、電話帳のデータや端末固有情報(機体番号や電話番号)などを吸い出し、サーバに勝手に送信してしまうようなアプリが社会的な問題となりました。そのため、アプリ作成時に利用する権限を宣言し、インストール時に確認をさせるだけでなく、インストール後にも与えた権限を剥奪出来るようにすることや、重大な機能はユーザが明示的に許可するまでは使用できなくするようにGoogleはAndroidのセキュリティについての考え方を変化させつつあると判断しています。

また、通知バー広告を使ったアプリの排除など、Google Playを通じたアプリの配信でもセキュリティ強化は進んでいます。

特にGoogle Playを通じて配信する場合は、Androidでのセキュリティについての考え方の変化についてもしっかりと考慮し、誠実なアプリ開発を行っていくことが必要です。