Android
Linux
Debian
DebianNoroot

Termux 開発コミュニティによる libandroid-shmem.so を Debian noroot 環境に導入する

はじめに

Debian noroot とは、 Android OS 上において root 権限を取ることなく Debian 環境を構築するためのアプリケーションです。

CPU の性能とメモリ容量が潤沢にある Android 端末であれば、 Debian noroot アプリの導入によって Android OS 端末上で非常に軽快な Debian 環境を実現することができます。

さて、 pelya 氏によって作成された Debian noroot 環境には、共有メモリ関連の標準 C ライブラリ関数を /dev/ashmem によってエミュレートする Debian noroot 環境のための動的ライブラリである libandroid-shmem.so が導入されています。

しかし、 pelya 氏による libandroid-shmem.so では、幾つかの共有メモリ関係のライブラリ関数を用いたソフトウエアが正常に動作しなかったり、パフォーマンスが良くないという問題があります。

ここで、 Debian noroot 環境において、 pelya 氏による libandroid-shmem.so に代えて Termux の開発コミュニティ による libandroid-shmem.soDebian noroot 環境上で動作するように再修正を加えた上で、 Termux の開発コミュニティによる libandroid-shmem.so の導入を行いました。

そして、 pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティによって改良された libandroid-shmem.so について、Termux の開発コミュニティに同梱されたテストプログラムを用いて動作と実行速度の検証を行った所、 Termux の開発コミュニティによる libandroid-shmem.so の導入によって Debian noroot 環境上で動作する共有メモリを使用したソフトウェアが正常かつ安定に動作する事が判りました。

本稿では、 Debian noroot 環境において、 pelya 氏による Debian noroot 環境オリジナルの libandroid-shmem.so に代えて Termux の開発コミュニティによる libandroid-shmem.so を導入する手法及び、 pelya 氏による libandroid-shmem.soTermux の開発コミュニティによる libandroid-shmem.so の動作比較の検証を行った結果について述べます。

まず最初に、 "libandroid-shmem.so の導入" の章において、Termux の開発コミュニティによって改良された libandroid-shmem.soDebian noroot 環境上に移植するための差分ファイルを適用し、 Debian noroot 環境に導入する手法について述べます。

次に、 "libandroid-shmem.so の検証" の章において、 pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティによって改良された libandroid-shmem.so について、Termux の開発コミュニティ による libandroid-shmem.so に同梱されたテストプログラムのコンパイルと実行及び実行速度の検証を行った結果について述べます。

最後に、 "結論" の章において、本稿の結論について述べます。

libandroid-shmem.so の導入

本章では、 Termux の開発コミュニティによる libandroid-shmem.so のソースコードに、Termux の開発コミュニティによる libandroid-shmem.soDebian noroot 環境に再移植するための差分ファイルを適用してコンパイルし、 Debian noroot 環境に導入する手法について述べます。

まず、 Termux の開発コミュニティによる libandroid-shmem.so の github 版若しくは v0.2 版を以下の URL から入手し、 tarball の場合は適当なディレクトリに展開します。

次に、Termux の開発コミュニティによる libandroid-shmem.soDebian noroot 環境に再移植するための差分ファイルを以下の URL より入手します。

そして、入手したソースコードが置かれているディレクトリに、以下のようにして、差分ファイル libandroid-shmem-termux-0.2_2-fix.diff を適用して通常通りに make コマンドによってコンパイルすると、動的ライブラリ libandroid-shmem-termux.so が生成されます。

 $ patch -p1 < /path/to/diff/libandroid-shmem-termux-0.2_3-fix.diff
 (ここに、 /path/to/diff は、 libandroid-shmem-termux-0.2_3-fix.diff が置かれているディレクトリのパス名)
 $ make ... (オプションを適宜設定すること。)

この動的ファイルを使用するには、まず最初に生成された動的ライブラリを Debian noroot 環境のルートディレクトリにインストールします。

 # install -v -m 0755 libandroid-shmem-termux.so /

なお、ソースコードをコンパイルする事が煩わしい場合や何らかの問題で困難である場合は、次に示す URL から下記のようにダウンロードして、 libandroid-shmem-termux.so.{arm,x86-32} を下記のようにルートディレクトリにインストールしても構いません。

 $ wget -O libandroid-shmem-termux.so.arm https://git.io/libandroid-shmem-termux.so-0.2.103.arm     # (ARM 用のバイナリファイルのダウンロードの場合)
 $ wget -O libandroid-shmem-termux.so.x86-32 https://git.io/libandroid-shmem-termux.so-0.2.103.x32  # (32 ビット x86 用のバイナリファイルのダウンロードの場合)
 $ sudo install -v -m 0700 libandroid-shmem-termux.so.arm /libandroid-shmem-termux.so # (x86-32 搭載の端末の場合はinstall -m 0700 libandroid-shmem-termux.so.x86-32 /libandroid-shmem-termux.so)

次に、 Debian noroot 環境の初期化ファイルである /proot.sh において、環境変数 LD_PRELOAD が定義されている行を以下のように修正します。

...
# LD_PRELOAD="... /libandroid-shmem.so ..."
LD_PRELOAD="... /libandroid-shmem-termux.so ..."    # /libandroid-shmem.so を /libandroid-shmem-termux.so に修正。
...

初期化ファイル /proot.sh の修正後は、 Debian noroot 環境を再起動して設定を有効にします。

libandroid-shmem.so の検証

本章では、 pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティによる libandroid-shmem.so について、Termux の開発コミュニティに同梱されたテストプログラムのコンパイルと実行を行った結果及び、ベンチマークとなるテストプログラムの実行時間の計測を行った結果について述べます。

まず最初に、 "検証で使用したテストプログラム" の節において、本稿において使用した、 pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティによる libandroid-shmem.so の比較検証の為に使用した、 Termux の開発コミュニティによる libandroid-shmem.so に同梱されたテストプログラムの概要について述べます。

次に、 "テストプログラムのコンパイル及び実行結果" の節において、 pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティ による libandroid-shmem.so を用いて、テストプログラムのコンパイル及び実行を行った結果について述べます。

最後に、 "テストプログラムの実行時間の計測結果" の節において、 pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティ による libandroid-shmem.so を用いて、テストプログラムの実行時間の計測を行った結果について述べます。

検証で使用したテストプログラム

本稿では、テストプログラムとして、 Termux の開発コミュニティ版の libanddroid-shmem.so に同梱されている以下のプログラムを使用しました。

ここで、上記のテストプログラムをコンパイルすると、以下の実行ファイルが生成されます。

  • libandroid-shmem/test/test-error-codes
  • libandroid-shmem/test/test-after-fork
  • libandroid-shmem/test/test-at-memmory
  • libandroid-shmem/test/test-ipc-private
  • libandroid-shmem/test/test-with-key

なお、これらのテストプログラムは、 Termux の開発コミュニティ版の libanddroid-shmem.so の git リポジトリ内test/ ディレクトリ以下の Makefile を用いてコンパイル及び実行を同時に行うことが出来ます。

テストプログラムのコンパイル及び実行結果

まず最初に、 pelya 氏による libandroid-shmem.so を用いて、次のようにして test/ ディレクトリ以下の Makefile によってテストプログラムをコンパイルし実行すると、以下の結果を得ることが出来ました。

  $ cd libandroid-shmem/test
  $ LD_PRELOAD="/libandroid-shmem.so" make -i
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM error-codes.c -o test-error-codes
  ./test-error-codes
  shmat: shmid 3039 shmaddr (nil) shmflg 0
  ...(略)...
  shmget: ID 0 shmid 57d70001 FD 4 size 4096
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM ipc-private.c -o test-ipc-private
  ./test-ipc-private
  shmget: key 0 size 30 flags 01666 (flags are ignored)
  shmget: bound UNIX socket /dev/shm/000057e5
  ...(略)...
  shm_find_id: cannot find shmid 57e50002
  shmat: shmid 57e50002 does not exist
  shmat-parent-from-child: Invalid argument
  Makefile:19: recipe for target 'testcase-ipc-private' failed
  make: [testcase-ipc-private] Error 1 (無視されました)
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM with-key.c -o test-with-key
  ./test-with-key
  shmget: key 369240251 size 30 flags 01666 (flags are ignored)
  shmget: key 369240251 != IPC_PRIVATE,  this is not supported
  shmget: Invalid argument
  Makefile:19: recipe for target 'testcase-with-key' failed
  make: [testcase-with-key] Error 1 (無視されました)
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM at-memory.c -o test-at-memory
  ./test-at-memory
  shmget: key 0 size 30 flags 01666 (flags are ignored)
  shmget: bound UNIX socket /dev/shm/00005800
  ...(略)...
  shmat: shmid 58000001 shmaddr 0xe7afc000 shmflg 0
  shmat: shmaddr != NULL not supported
  shmat-child-2: Invalid argument
  child-exit
  Makefile:19: recipe for target 'testcase-at-memory' failed
  make: [testcase-at-memory] Error 1 (無視されました)
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM after-fork.c -o test-after-fork
  ./test-after-fork
  shmget: key 0 size 30 flags 01666 (flags are ignored)
  shmget: bound UNIX socket /dev/shm/0000580d
  ...(略)...
  shmdt: unmapped addr 0xf478a000 for FD 6 ID 0 shmid 580d0001
  shmdt: deleting shmid 580d0001
  ./cleanup-shared-memory.sh
  $

以上の実行結果から以下のことが判りました。

  • テストプログラム ipc-private.c において、子プロセスから親プロセスの共有メモリを、標準ライブラリ関数 shmat(2) でメモリマッピングを行う時点でプログラムの実行が失敗する。
  • テストプログラム with-key.c において、標準ライブラリ関数 shmget(2) の引数 keyIPC_PRIVATE が使用できないためにプログラムの実行が失敗する。
  • テストプログラム at-memmory.c において、標準ライブラリ関数 shmat(2) の引数 shmaddrNULL 以外が使用できないためにプログラムの実行が失敗する。

また、以上の実行結果より、 pelya 氏による libandroid-shmem.so において、標準ライブラリ関数 shmget(2) 及び shmat(2) の実装が一部不完全であることも同時に判ります。

そして、 Debian noroot 環境に移植した Termux の開発コミュニティ版の libanddroid-shmem.so を用いて、同様に test/ ディレクトリ以下の Makefile によってテストプログラムをコンパイルし実行すると以下の結果を得ることが出来ました。

  $ cd libandroid-shmem/test
  $ LD_PRELOAD="../libandroid-shmem-termux.so" make -i
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM error-codes.c -o test-error-codes
  ./test-error-codes
  [shmem] ashv_find_local_index: cannot find shmid 3039
  [shmem] shmat: shmid 00003039 does not exist
  ...(略)...
  [shmem] ashmem_create_region: name `/dev/shm/000058ca-0` size 4096
  [shmem] shmget: ID 0 shmid 58ca0001 FD 5 size 4096
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM ipc-private.c -o test-ipc-private
  ./test-ipc-private
  [shmem] shmget: bound UNIX socket /dev/shm/000058d8 in pid=22744
  [shmem] ashv_thread_function: thread started
  ...(略)...
  [shmem] shmat: mapped addr 0xecc24000 for FD 11 ID 1
  [shmem] ashv_thread_function: send FD 10 key 00000000
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM with-key.c -o test-with-key
  ./test-with-key
  [shmem] shmget: bound UNIX socket /dev/shm/000058e5 in pid=22757
  [shmem] ashv_thread_function: thread started
  ...(略)...
  [shmem] shmdt: unmapped addr 0xf13da000 for FD 7 ID 0 shmid 58e50001
  [shmem] shmdt: deleting shmid 58e50001
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM at-memory.c -o test-at-memory
  ./test-at-memory
  [shmem] shmget: bound UNIX socket /dev/shm/000058f4 in pid=22772
  [shmem] shmget: key = 00000000 (is IPC_PRIVATE)
  ...(略)...
  [shmem] shmdt: deleting shmid 58f40001
  [shmem] ashv_thread_function: send FD 6 key 00000000
  cc -Wall -Wextra -Werror -std=c99 -DSYSV_ASHMEM_TEST_SYSTEM after-fork.c -o test-after-fork
  ./test-after-fork
  [shmem] shmget: bound UNIX socket /dev/shm/00005904 in pid=22788
  [shmem] shmget: key = 00000000 (is IPC_PRIVATE)
  ...(略)...
  [shmem] shmdt: unmapped addr 0xef3b0000 for FD 6 ID 0 shmid 59040001
  [shmem] shmdt: deleting shmid 59040001
  ./cleanup-shared-memory.sh
  $

以上の実行結果から、 Termux の開発コミュニティ版の libanddroid-shmem.so を用いた場合、全てのテストプログラムについて問題無くコンパイルとプログラムの実行が可能であることが判りました。

テストプログラムの実行時間の計測結果

まず最初に、 pelya 氏による libandroid-shmem.so を用いて、テストプログラム after-fork.c をコンパイルして生成した実行ファイル test-after-fork をベンチマークとして、以下のようにしてテストプログラムの実行時間を計測した所、以下の結果を得ることが出来ました。

なお、実行時間の計測は、テストプログラム after-fork.c をコンパイルして生成した実行ファイル test-after-fork を 200 回連続して実行し、これを 3 回試行して平均を取ることにより行いました。

  $ cd libandroid-shmem/test
  $ time (for i in `seq 1 200`; do LD_PRELOAD="/libandroid-shmem.so" ./test-after-fork; done)
  ...(略)...
  shmat:  mapped addr 0xf31f0000 for FD 6 ID 0
  shmdt: unmapped addr 0xf31f0000 for FD 6 ID 0 shmid 776a0001
  shmdt: deleting shmid 776a0001

  real    0m4.765s
  user    0m0.190s
  sys     0m1.370s
  $ time (for i in `seq 1 200`; do LD_PRELOAD="/libandroid-shmem.so" ./test-after-fork; done)
  ...(略)...
  real    0m4.704s
  user    0m0.250s
  sys     0m1.180s
  $ time (for i in `seq 1 200`; do LD_PRELOAD="/libandroid-shmem.so" ./test-after-fork; done)
  ...(略)...
  real    0m5.236s
  user    0m0.150s
  sys     0m1.200s
  $
  $ # (平均: real 4.902s, user 0.197s, sys 1.250s)

そして、 Debian noroot 環境に移植した Termux の開発コミュニティ版の libanddroid-shmem.so を用いて、同様にテストプログラム after-fork.c をベンチマークとしてテストプログラムの実行時間を計測した所、以下の結果を得ることが出来ました。

  $ cd libandroid-shmem/test
  $ time (for i in `seq 1 200`; do LD_PRELOAD="../libandroid-shmem-termux.so" ./test-after-fork; done)
  ...(略)...
  [shmem] shmdt: shmaddr 0xe8582000
  [shmem] shmdt: unmapped addr 0xe8582000 for FD 6 ID 0 shmid 1950001
  [shmem] shmdt: deleting shmid 1950001

  real    0m5.473s
  user    0m0.160s
  sys     0m1.070s
  $ time (for i in `seq 1 200`; do LD_PRELOAD="../libandroid-shmem-termux.so" ./test-after-fork; done)
  ...(略)...
  real    0m5.015s
  user    0m0.150s
  sys     0m1.030s
  $ time (for i in `seq 1 200`; do LD_PRELOAD="../libandroid-shmem-termux.so" ./test-after-fork; done)
  ...(略)...
  real    0m5.075s
  user    0m0.140s
  sys     0m0.970s
  $
  $ # (平均: real 5.187s, user 0.150s, sys 1.023s)

以上の結果から、 Debian noroot 環境に移植した Termux の開発コミュニティ版の libanddroid-shmem.so を用いた場合の方が僅かに実行時間が長くなるものの、双方の実行時間の計測を更に複数回繰り返し試行して結果を比較すると、pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティ による libandroid-shmem.so において、双方の実行時間の差に有意差が無い事が判りました。

結論

本稿において、まず最初に前々章において、 Termux の開発コミュニティによって改良された libandroid-shmem.so のソースコードに、 Termux の開発コミュニティによる libandroid-shmem.soDebian noroot 環境上に移植するための差分ファイルを適用し、 libandroid-shmem.so をビルドした上で、環境変数 LD_PRELOADlibandroid-shmem.so のパスを設定して Debian noroot 環境を再起動することに基づいた Termux の開発コミュニティによる libandroid-shmem.so の導入手法について述べました。

そして、前章において、pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティ による libandroid-shmem.so を用いて、テストプログラムのコンパイル及び実行を行った結果、 pelya 氏による libandroid-shmem.so を用いた場合では、標準ライブラリ関数 shmget(3), shmat(3) の実装の一部が不完全であり、このために 標準ライブラリ関数 shmget(3), shmat(3) の動作に問題が発生する可能性があることが判りました。

しかしながら、 pelya 氏による libandroid-shmem.so 及び Termux の開発コミュニティ による libandroid-shmem.so を用いて、テストプログラムの実行時間を計測した結果、双方の実行時間の差に有意差が現れないことが判りました。

以上により、 Debian noroot 環境において、 pelya 氏による Debian noroot 環境オリジナルの libandroid-shmem.so に代えて Termux の開発コミュニティによる libandroid-shmem.so を導入することにより、 Debian noroot 環境上で動作する共有メモリを使用したソフトウェアが正常かつ安定に動作する事が判りました。

謝辞

本稿の記述に当たって、まず最初に、 Android OS 端末上で非常に軽快な Debian 環境を実現することを可能にした Debian noroot 環境の開発者である pelya 氏に心より感謝致します。

そして、 pelya 氏による Debian noroot 環境オリジナルの libandroid-shmem.so に各種修正を加え、新たに libandroid-shmem.so を公開した Termux の開発コミュニティの関係各位に心より感謝致します。

最後に、 Debian noroot 環境Android OS 及び Debian 環境の全ての事に関わる全ての皆様に心より感謝致します。

追記とお断り

2018/12/13 現在の追記

"libandroid-shmem.so の導入" の章において、コンパイル済の動的ライブラリ libandroid-shmem-termux.so を直接ダウンロードできる URL を追記しました。どうか御了承下さい。