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

このページでは、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.javapushFile のソースコードを確認してください。

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

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

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

  1. 必要に応じて、ファイルの提供や保存ができるアプリがホストしている ContentProvider のインスタンスを作成します。アプリの内部ストレージを使用してください。
  2. adb shell contentread コマンドまたは 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 の値には systemsecondary があります。

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

ホストドリブン テスト

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

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