Android6 互換モード(3) コンテントプロパイダーの動作

A+ a-

互換モード:「Android6.0以上の端末で、インストールタイムパーミッションモデルで実行しているアプリケーションが、端末の設定画面から、特定のパーミッションをはく奪された時」の動作確認記事三本目です。
連絡先アクセス(コンテントプロパイダー経由)での動作を調査してみました。
結論としては、読み込み時は取得したCursorのsizeが0となりあまり影響はないといった感じです。

以下調査結果です。


互換モードでどのような動作をするかを調査するために、targetSdkVersion=21で作成したアプリをAndroid OS 6.0の端末にインストールし、設定画面より電話帳のアクセス(READ_CONTACTS及びWRITE_CONTACTS)を不許可にした時の動作を確認しました。
また、比較のため、同じコードをtargetSdkVersion=23に変更しAndroid 6.0の端末にインストールした時の動作も確認しました(requestPermissionはしていないので必ずSecurityException等なんらかのExceptionを吐く)

連絡先グループとパーミッション


パーミッショングループパーミッション説明
CONTACTSREAD_CONTACTS 連絡先の読み取り
携帯端末に保存されている連絡先に関するデータの読み取りをアプリに許可します。このデータには、電話、メール、または他の手段で特定の相手と連絡をとった頻度も含まれます。これにより、アプリに連絡先データの保存を許可することになり、悪意のあるアプリによって知らないうちに連絡先データが共有される恐れがあります。
WRITE_CONTACTS 連絡先の変更
携帯端末に保存されている連絡先に関するデータの変更をアプリに許可します。このデータには、電話、メール、または他の手段で特定の相手と連絡をとった頻度も含まれます。これにより、アプリが連絡先データを削除できるようになります。
GET_ACCOUNTS この端末上のアカウントの検索
携帯端末で認識されているアカウントのリストの取得をアプリに許可します。これには、インストールしたアプリによって作成されたアカウントも含まれます。
※GET_ACCOUNTSに関しては別記事で動作確認を行う 。

連絡先読み取りのテストコード

AndroidManifest.xml
targetSdkVersion=xxx
<uses-permission android:name="android.permission.READ_CONTACTS"/>
ソース
// 連絡先情報の取得
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
….

連絡先変更のテストコード 

AndroidManifest.xml
targetSdkVersion=xxx
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>

ソース
ContentValues values = new ContentValues();

// 連絡先情報の追加
Uri uri = getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values);
long id = ContentUris.parseId(uri);

values.put(ContactsContract.Data.RAW_CONTACT_ID, id);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
values.put(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, ("TestContact" + id));
getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);

// 連絡先情報の更新
values.clear();
values.put(ContactsContract.Contacts.DISPLAY_NAME_PRIMARY, "CustomContact");
getContentResolver().update(ContactsContract.RawContacts.CONTENT_URI, values,
    (ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " LIKE 'TestContact%' "), null);

// 連絡先情報の削除
getContentResolver().delete(ContactsContract.RawContacts.CONTENT_URI,
    (ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " = 'CustomContact' "), null);
….

テスト環境

  • Nexsus 5をAndroid 6.0にバージョンアップした物 
  • イメージバージョン番号:MRA58K 

※アンドキュメントな部分なので確認した環境です

 結果

Android6.0上で設定メニューから「連絡先」パーミッショングループを不許可にした場合

targetSdkVersion=21

互換モードの動作です。
  • 連絡先情報の読み取り時:
    • 無条件で空(Cursor#getCount()が0)のCursorが返却される
  • 連絡先情報の追加時:
    • ContentProviderへの書き込みが行われず、IDが0となる以下のUriが返却される
  • ContactsContract.RawContacts.CONTENT_URIへの書き込み:
    • content://com.android.contacts/raw_contacts/0
  • ContactsContract.Data.CONTENT_URIへの書き込み:
    • content://com.android.contacts/data/0
  • 連絡先情報の更新時:
    • ContentProvider上のデータの更新が行われず、更新件数として0が返却される
  • 連絡先情報の削除時:
    • ContentProvider上のデータの削除が行われず、削除件数として0が返却される

targetSdkVersion=23

本来requestPermissionすべきですがしてませんのでエラー系となるのが当然です。


  • 連絡先情報の読み取り時:
    • ContentResolver#query()呼び出し時に以下のSecurityExceptionが発生

java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{39efe3a 7259:com.example.taosoftware.contactstest/u0a120} (pid=7259, uid=10120) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS


  • 連絡先情報の追加・更新・削除時:
    • ContentResolver#insert(),ContentResolver#update(),ContentResolver#delete()呼び出し時に以下のSecurityExceptionが発生

ava.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{55a5f77 7412:com.example.taosoftware.contactstest/u0a120} (pid=7412, uid=10120) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS

まとめ

互換モードの時、連絡先情報は0件として扱わる。NULLが返るわけではないので、既存アプリがぬるぽでおちるといった事はない。更新や削除は「0件処理をしました」という結果がかえりこれもあまり影響はないと考えられる。一部のアプリでは書き込み処理をした後のIDを取得して処理等行う事があるかもしれないが、最終的にハングアップという動作は考えにくい。

他のパミッションが必要なContentProvider(ブックマーク等)も同じような動作をすると考えられますが、動作確認はしていません。多分同じ仕様なんだろうと思ってます。
というか、自身がContentProviderを設計する時には、同じような実装にすべきだと感じました。

しかし、シャープ端末でのアクセス制限方法と同じですね。
ちょっと時代が早かった?>シャープさん


がく

がく

リスクファインダーはAndroidアプリのセキュリティホールを見つけます!

Androidスマートフォンが急速に普及するとともにアプリの脆弱性報告も急増しています。
リスクファインダーは、Androidアプリの脆弱性診断WEBサービスです。
500項目以上のチェックでアプリの脆弱性や問題を検出し、セキュアなアプリ開発をサポートします。

  • ブラウザでファイルをアップロードするだけ
  • アプリの脆弱性を指摘するだけでなく対処方法も提示
  • 頻繁にバージョンアップするAndroidの最新情報に素早く対応

リスクファインダーの詳細はこちら