アナログ金木犀

つれづれなるまままにつれづれする

Android Mのパーミッション個別設定情報がどこに保存されているのか調べてみた

今日、これに参加しました。

mandroidfcr.doorkeeper.jp

以前からAndroid Mのパーミッションの設定値の保存先でも探してみようかと思ってたので、この時間を使って調べてみました。

ちなみに、雰囲気はすごくまったりしていてよかったです。会場が自分の会社ってのもあるかもだけど。

さて本題。

なんとなくの経験から大抵こういう設定値は保存されている場所が限られています。

  1. アプリごとの保存場所 (/data/data/パッケージ名)
  2. SettingsのDB /data/data/com.android.providers.settings/databases/settings.db
  3. /data/system配下

"アプリごとの保存場所"はパーミッションの個別設定を変えてデータを削除しても、その設定状態が保存されていたので対象から外しました。 ということで、残りの二つを適当に漁ってみました。

するとすぐに見つかりました。

そのファイルのパスが /data/system/users/{userId}/runtime-permissions.xml

中身はこんな感じ。

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<runtime-permissions>
  <pkg name="com.android.launcher">
    <item name="android.permission.CALL_PHONE" granted="true" flags="0" />
  </pkg>
  <pkg name="com.android.browser">
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="0" />
    <item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
    <item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
    <item name="android.permission.READ_PROFILE" granted="true" flags="0" />
    <item name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" granted="true" flags="0" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="0" />
    <item name="android.permission.CAMERA" granted="true" flags="0" />
    <item name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS" granted="true" flags="0" />
    <item name="com.android.launcher.permission.INSTALL_SHORTCUT" granted="true" flags="0" />
    <item name="android.permission.RECORD_AUDIO" granted="true" flags="0" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="0" />
  </pkg>
  :
  <shared-user name="android.uid.shell">
    <item name="android.permission.READ_CALENDAR" granted="true" flags="10" />
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="true" flags="10" />
    <item name="android.permission.BLUETOOTH" granted="true" flags="10" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="true" flags="10" />
    <item name="android.permission.SEND_SMS" granted="true" flags="10" />
    <item name="android.permission.CALL_PHONE" granted="true" flags="10" />
    <item name="android.permission.WRITE_CONTACTS" granted="true" flags="10" />
    <item name="android.permission.WRITE_CALENDAR" granted="true" flags="10" />
    <item name="android.permission.READ_USER_DICTIONARY" granted="true" flags="10" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="10" />
  </shared-user>
  <shared-user name="android.uid.calendar">
    <item name="android.permission.READ_CALENDAR" granted="true" flags="0" />
    <item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
    <item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
    <item name="com.google.android.googleapps.permission.GOOGLE_AUTH.cl" granted="true" flags="0" />[f:id:kgmyshin:20150630002958p:plain]
    <item name="android.permission.SUBSCRIBED_FEEDS_WRITE" granted="true" flags="0" />
    <item name="android.permission.WRITE_CALENDAR" granted="true" flags="0" />
  </shared-user>
</runtime-permissions>

すごくそれっぽいですね。

基本的には<pkg>タグに囲まれて中に設定されているパーミッションがあるようです。

これを取得した後に下記のように、Browserの「Camera」と「Location」をOFFにしてみました。

そしてその後、再度xmlを取得すると下記のように変更されていることを確認しました。

:
  <pkg name="com.android.browser">
    <item name="android.permission.ACCESS_FINE_LOCATION" granted="false" flags="1" />
    <item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
    <item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
    <item name="android.permission.READ_PROFILE" granted="true" flags="0" />
    <item name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" granted="true" flags="0" />
    <item name="android.permission.ACCESS_COARSE_LOCATION" granted="false" flags="1" />
    <item name="android.permission.CAMERA" granted="false" flags="1" />
    <item name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS" granted="true" flags="0" />
    <item name="com.android.launcher.permission.INSTALL_SHORTCUT" granted="true" flags="0" />
    <item name="android.permission.RECORD_AUDIO" granted="true" flags="0" />
    <item name="android.permission.READ_CONTACTS" granted="true" flags="0" />
  </pkg>
:

CameraとLocationがgranted=falseになっていることがわかります。ということで、このファイルが設定値の保存先で間違いなさそうです。

さらにこの手順の後に、Cameraだけgranted=trueにしてpushしてみて、Settingsを確認しましたが、変更はされていませんでした。(再起動したらさすがに反映されたけど、他にトリガーがあるのかは不明)

常時監視しているわけではなさそうです(そりゃそうか)。

ここまで動作で確認して、あとはコードではどうなってるのか確認してみました。

runtime-permissions.xmlの文字列で検索すると下記が引っかかりました。

場所: com/android/server/pm/Settings.java

private static final String RUNTIME_PERMISSIONS_FILE_NAME = "runtime-permissions.xml";

pmというのはパッケージマネージャ。

このファイル名からFileインスタンスに変更して返却している関数がこれで、

        private File getUserRuntimePermissionsFile(int userId) {
            // TODO: Implement a cleaner solution when adding tests.
            // This instead of Environment.getUserSystemDirectory(userId) to support testing.
            File userDir = new File(new File(mSystemDir, "users"), Integer.toString(userId));
            return new File(userDir, RUNTIME_PERMISSIONS_FILE_NAME); ★★
        }

下記が読み込んでいる関数。

           public void readStateForUserSyncLPr(int userId) {
                File permissionsFile = getUserRuntimePermissionsFile(userId); ★★ ファイルを読み込む
                if (!permissionsFile.exists()) {
                    return;
                }
    
                FileInputStream in;
                try {
                    in = new FileInputStream(permissionsFile);
                } catch (FileNotFoundException fnfe) {
                    Slog.i(PackageManagerService.TAG, "No permissions state");
                    return;
                }
    
                try {
                    XmlPullParser parser = Xml.newPullParser();
                    parser.setInput(in, null);
                    parseRuntimePermissionsLPr(parser, userId); ここでxmlをparseしている
    
                } catch (XmlPullParserException | IOException e) {
                    throw new IllegalStateException("Failed parsing permissions file: "
                            + permissionsFile , e);
                } finally {
                    IoUtils.closeQuietly(in);
                }
            }

parseRuntimePermissionsLPrという関数の中でPermissionをメンバの潜ったところに詰めているところを確認しました。

ただ、これを呼び出しているのは見つけられなかった。(srcが全部あったわけじゃないので)

書き込みはwritePermissionsSyncという関数でやってるというところまで確認しましたが、外部からこれを呼び出しているところがこちらも見つからず。

少なくともSettingsアプリから読んでるんだろうけど、そのソースがなかったのかなと。。

などとやってるところで時間終了でした。

会場の設備の調整だったり、受付だったりで全部の時間は使えなかったけど、最低限の目的は達成できたのでよかったです。

コード読んでないじゃん?ってのはきっとばれてないはず。

雰囲気楽しかったので次回に期待です。