clearCallingIdentityでコールバック内にて特権操作を行う方法

2019年9月11日

本稿ではclearCallingIdentityの使用方法について説明します。

コールバック内で特権のある操作を行うとどうなる?

例として、AプロバイダーのコールバックでBプロバイダーにqueryを実行するとします。

            Uri uri = Contract.ContentUri.buildItemForJoinedList("com.sample.provider");
            ContentResolver resolver = context.getContentResolver();
            try (Cursor cur = resolver.query(uri, new String[]{ItemTable.NAME + ".*"},
                    null, null, null)) {
            }

そうするとBプロバイダーにアクセスできないというSecurityExceptionが発生します。

  
Error while accessing provider:com.sample.provider.sampleBProvider
java.lang.SecurityException: Permission Denial:
reading com.sample.api.content.sampleBProvider uri
content://com.sample.provider/item/joinedlist from pid=xxxx, uid=xxxx requires the provider be exported, or grantUriPermission()

これは、アプリのプロセスIDではなく呼び出し元のプロセスIDでコールバックが動いており、コールバック内で権限が必要な処理を行おうとするとセキュリティチェックで失敗しするためです。

コールバック内で特権のある操作を実行するには?

IDをリセットする為にclearCallingIdentity()を呼び、権限が必要な処理が終わったら、IDを戻すためにrestoreCallingIdentity()を呼びます。

            Uri uri = Contract.ContentUri.buildItemForJoinedList("com.sample.provider");
            ContentResolver resolver = context.getContentResolver();
long token = Binder.clearCallingIdentity();
            try (Cursor cur = resolver.query(uri, new String[]{ItemTable.NAME + ".*"},
                    null, null, null)) {
            } finally {
                Binder.restoreCallingIdentity(token);
            }