複数ユーザーをテストする

このページでは、Android プラットフォームで複数ユーザーをテストする際の重要な観点について説明します。マルチユーザー サポートの実装については、複数ユーザーのサポートをご覧ください。

デバイスパス

次の表に、一部のデバイスパスとその解決方法を示します。 パス列の値は、すべてユーザーごとのサンドボックス化されたストレージです。 Android のストレージは年々進化しています。詳しくは、ストレージのドキュメントをご覧ください。

パス システムパス(省略可) 目的
/data/user/{userId}/{app.path} /data/data アプリ ストレージ
/storage/emulated/{userId} /sdcard 共有内部ストレージ
/data/media/{userId} なし ユーザーのメディアデータ(音楽、動画など)
/data/system/users/{userId} なし ユーザーごとのシステム構成や状態

システムアプリからのみアクセス可能

次は、ユーザーごとのパスを使用する例です。

# to access user 10's private application data for app com.bar.foo:
$ adb shell ls /data/user/10/com.bar.foo/

ユーザーをまたぐ adb の操作

以下の adb コマンドは、複数のユーザーを取り扱う場合に使用できます。コマンドの一部は、Android 9 以降でのみサポートされています。

  • adb shell am instrument --user <userId>: 特定のユーザーに対してインストゥルメンテーション テストを実行します。デフォルトでは、現在のユーザーが使用されます。
  • adb install --user <userId>: 特定のユーザーに対してパッケージをインストールします。全ユーザーに対してパッケージがインストールされるようにするには、各ユーザーに対してこのコマンドを呼び出す必要があります。
  • adb uninstall --user <userId>: 特定のユーザーのパッケージをアンインストールします。--user フラグを付けずに呼び出すと、すべてのユーザーのパッケージをアンインストールします。
  • adb shell am get-current-user: 現在(フォアグラウンド)のユーザー ID を取得します。
  • adb shell pm list users: 既存のユーザーのリストを取得します。
  • adb shell pm create-user: 新規のユーザーを作成し、その ID を返します。
  • adb shell pm remove-user: ID により特定のユーザーを削除します。
  • adb shell pm disable --user <userId>: 特定のユーザーのパッケージを無効にします。
  • adb shell pm enable --user <userId>: 特定のユーザーのパッケージを有効にします。
  • adb shell pm list packages --user <userId>: 特定のユーザーのパッケージを表示します。-e を指定すると有効なパッケージを表示し、-d を指定すると無効なパッケージを表示します。デフォルトでは、常にシステム ユーザーのパッケージを表示します。

以下で、複数ユーザーに対する adb の動作について説明します。

  • adb(正確には adbd デーモン)は、現在のユーザーに関係なく、常にシステム ユーザー(ユーザー ID が 0)として動作します。したがって、ユーザーに依存するデバイスパス(/sdcard/ など)は常にシステム ユーザーとして解決されます。詳しくは、デバイスパスをご覧ください。

  • デフォルト ユーザーが指定されていない場合は、adb の各サブコマンドは別のユーザーとして実行されます。--user <userId> フラグをサポートしているコマンドには、am get-current-user でユーザー ID を取得してから、明示的にこのフラグを使用することをおすすめします。Android 9 までは、すべてのコマンドで明示的に user フラグを使用することはできませんでした。

  • Android 9 以降では、セカンダリ ユーザーの /sdcard パスへのアクセスが拒否されます。テスト中にファイルを取得する方法については、マルチユーザー データのコンテンツ プロバイダをご覧ください。

マルチユーザー データのコンテンツ プロバイダ

Android 9 以降では、adb はシステム ユーザーとして動作し、データはサンドボックス化されているため、システム ユーザー以外のユーザーのテストデータを push または pull するにはコンテンツ プロバイダを使用する必要があります。ただし、次の場合にはその必要がありません。

  • adbd がルートとして動作している(adb root を使用)。これは userdebug ビルドまたは usereng ビルドでのみ可能です。

  • Trade Federation(Tradefed)の ITestDevice を使用してファイルを push または pull している。この場合は、テスト構成の /sdcard/ パスを使用します。たとえば、NativeDevice.java の pushFile のソースコードを確認してください。

コンテンツ プロバイダがセカンダリ ユーザーで動作している場合は、user や uri などの適切なパラメータを指定して adb shell content コマンドを使用することによりアクセスできます。

アプリ デベロッパー向けの回避策

push コマンドまたは pull コマンドの代わりに、adb content と ContentProvider のインスタンスを使用してテストファイルを操作します。

  1. 必要に応じて、ファイルの提供や保存ができるアプリがホストしている ContentProvider のインスタンスを作成します。アプリの内部ストレージを使用してください。
  2. adb shell content の read コマンドまたは write コマンドを使用して、ファイルを push または pull します。

メディア ファイルの回避策

メディア ファイルを SD カードのメディア パーティションに push するには、MediaStore 公開 API を使用します。次に例を示します。

# push MVIMG_20190129_142956.jpg to /storage/emulated/10/Pictures
# step 1
$ adb shell content insert --user 10 --uri content://media/external/images/media/ --bind _display_name:s:foo.jpg

# step 2
$ adb shell content query --user 10 --projection _id --uri content://media/external/images/media/ --where "_display_name=\'foo.jpg\'"

# step 3
$ adb shell content write --user 10 --uri content://media/external/images/media/8022 < MVIMG_20190129_142956.jpg

汎用コンテンツ プロバイダをインストールする

ユーザーごとの /sdcard パスにファイルを読み書きする既存のコンテンツ プロバイダをインストールして使用します。

make TradefedContentProvider を使用してソースから TradefedContentProvider.apk をビルドします。

```
# install content provider apk
$ adb install --user 10 -g TradefedContentProvider.apk

# pull some_file.txt
$ adb shell content read --user 10 --uri content://android.tradefed.contentprovider/sdcard/some_file.txt > local_file.txt

# push local_file.txt
$ adb shell content write --user 10 --uri content://android.tradefed.contentprovider/sdcard/some_file.txt < local_file.txt
```

Trade Federation のマルチユーザー サポート

Tradefed は Android の公式テストハーネスです。ここでは、Tradefed に組み込まれているマルチユーザー テストシナリオのサポートについて一部を説明します。

ステータス チェッカー

システム ステータス チェッカー(SSC)はターゲット作成ツールの前に実行され、そのクリーンアップはターゲット作成ツールの後で実行されます。

UserChecker は、デベロッパーによる複数ユーザーのテストを支援することを目的として明示的に定義されています。テストでデバイス上のユーザーの状態が変更されたかどうかを追跡します(ティアダウンの際に削除せずにユーザーを作成したなど)。また、user-cleanup が設定されている場合は、テスト後に自動的にクリーンアップを試みます。この場合も、テストの修正を行ううえで有用なエラーを確認できます。

<system_checker class="com.android.tradefed.suite.checker.UserChecker" >
    <option name="user-cleanup" value="true" />
</system_checker>

ターゲット作成ツール

ターゲット作成ツールは通常、特定の構成でデバイスをセットアップするために使用されます。マルチユーザー テストの場合は、作成ツールを使用して特定タイプのユーザーを作成したり、他のユーザーに切り替えたりすることもできます。

セカンダリ ユーザーがないデバイスタイプの場合は、AndroidTest.xml 内で CreateUserPreparer を使用してセカンダリ ユーザーを作成し、そのユーザーに切り替えられます。テストの最後に、作成ツールが元のユーザーに戻して、セカンダリ ユーザーを削除します。

<target_preparer
  class="com.google.android.tradefed.targetprep.CreateUserPreparer" >
</target_preparer>

作成しようとするユーザータイプがすでにデバイスに存在する場合は、SwitchUserTargetPreparer を使用してその既存のユーザーに切り替えます。一般的な user-type の値には system や secondary があります。

<target_preparer
  class="com.android.tradefed.targetprep.SwitchUserTargetPreparer">
    <option name="user-type" value="secondary" />
</target_preparer>

ホストドリブン テスト

インスタンスによっては、テスト中にユーザーを切り替えることが必要な場合がありますが、UI Automator などのデバイス側のテスト フレームワーク内からは切り替えないでください。テストプロセスが突如強制終了される可能性があります。代わりに、Tradefed のホストドリブン テスト フレームワークのようなホスト側のテスト フレームワークを使用します。これにより、ITestDevice にアクセスして必要なユーザーに切り替えられるようになります。

ユーザーの状態を変更するホストドリブン テストには、終了後にテストが適切にクリーンアップされるように UserChecker(ステータス チェッカーを参照)を使用します。