Wrap Shell スクリプト

アプリをネイティブ コードでデバッグおよびプロファイリングする場合、コマンドライン デベロッパー ツールを APK にバンドルし、アプリの起動時に端末でそれらのツールを自動的に実行できると便利です。

Android 8.0 以降では、デバッグ可能なアプリの起動時に新しいプロセスでシステムが自動的に実行するユーザー定義シェル スクリプトを作成してパッケージ化できるようになりました。 この機能を使用すると、次のようなオペレーションを実行するネイティブ デベロッパー ツールを呼び出すスクリプトを記述できます。

  • strace でシステム呼び出しをトレースする。
  • malloc debugAddress Sanitizer(ASAN)、Valgrind を使用してメモリの整合性を確保する。
  • malloc debug を介してアプリ固有のネイティブ メモリ トラッキングを可能にする。
  • Java コードのプロファイリングを実行している場合に、特定のアプリプロセスに対して Simpleperf を実行する。

Wrap Shell スクリプトの使用

Wrap Shell スクリプトを使用してネイティブ デベロッパー ツールを端末で実行するには、次の手順に従います。

  1. 次のものをパッケージしたデバッグ可能なカスタム APK をコンパイルします。
  2. デバッグ可能な APK を端末にインストールします。 端末の Android プラットフォームのバージョンによっては、実行する Wrap Shell スクリプトのプロセスに対するアクセス制御を変更する必要があります。
    • Android 8.1(API レベル 27)以上: そのような変更は不要です。
    • Android 8.0(API レベル 26): 端末で SELinux の強制を無効にする必要があります。 SELinux の強制を無効にするには userdebug ビルドまたは eng ビルドで adb を使用します。 これらのパーミッション レベルがサポートされる端末は次のとおりです。
      • userdebug システム イメージを適用した Android エミュレータ
      • AOSP eng ビルドまたは root イメージを書き込んだ Google 端末。
  3. アプリ ランチャー経由またはコマンドラインを使用して端末上でアプリを通常どおりに起動します。
  4. 完了したら、端末上で SELinux 強制を再度有効化することを強くおすすめします。

Wrap Shell スクリプトの作成

ランタイム環境をカスタマイズするには wrap.sh という名前のシェル スクリプトを作成します。 そのスクリプトでは環境変数を設定し、ランタイム引数を変更します。 スクリプトは MirBSD Korn shell(mksh)の構文に従っている必要があります。

wrap.sh を含むデバッグ可能な APK を起動すると、システムによってそのスクリプトが実行され、アプリプロセスに対する制御権がスクリプトに付与されます。 システムは、要求されたアプリを開始するコマンドを wrap.sh を呼び出すときに引数として渡します。 アプリを開始する役割はスクリプトが果たす必要があることに注意してください。

アプリを開始するだけのシンプルな wrap.sh ファイルは次のスニペットのとおりです。

#!/system/bin/sh
"$@"

wrap.sh を使用して malloc debug ツールを開始するには、次の行を組み込みます。

#!/system/bin/sh
LIBC_DEBUG_MALLOC_OPTIONS=backtrace logwrapper $@

wrap.sh のパッケージ化

wrap.sh を利用するには、デバッグ可能な APK をビルドする必要があります。 Android マニフェストの <application> 要素に android:debuggable=”true” 設定を組み込んでください。

wrap.sh スクリプトはアプリのネイティブ ライブラリと一緒にパッケージする必要があります。 アプリにネイティブ ライブラリが含まれていない場合は、プロジェクト ディレクトリに手動で lib ライブラリを追加します。 アプリがサポートしているアーキテクチャごとに、対応するネイティブ ライブラリ アーキテクチャのディレクトリの下に Wrap Shell スクリプトのコピーを提供する必要があります。

次のプロジェクト ディレクトリの例は x86 および ARMv8 の両方のアーキテクチャをサポートするファイル レイアウトを示しています。

# App Directory
|- AndroidManifest.xml
|- …
|- lib
   |- x86
      |- ...
      |- wrap.sh
   |- arm64-v8a
      |- ...
      |- wrap.sh

wrap.sh スクリプトは必ず実行可能にしてください(つまりスクリプトの実行可能ビットをセットします)。 次に例を示します。

$ ls -l lib/x86/wrap.sh
-rwxr-x--x 1 user user 0 Jan 01  1980 lib/x86/wrap.sh